blob: ff834b928467bd41b7ae812b417f02b090cd78c7 [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,
cristye7cc7cf2010-09-21 13:26:47 +0000122 const ssize_t,const size_t,const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000123 *GetVirtualPixelsCache(const Image *);
124
125static MagickBooleanType
cristye7cc7cf2010-09-21 13:26:47 +0000126 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,
127 PixelPacket *,ExceptionInfo *),
128 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
129 const ssize_t,const ssize_t,PixelPacket *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000130 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
131 ReadPixelCacheIndexes(CacheInfo *,NexusInfo *,ExceptionInfo *),
132 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
133 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
134 WritePixelCacheIndexes(CacheInfo *,NexusInfo *,ExceptionInfo *),
135 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
136
137static PixelPacket
cristye7cc7cf2010-09-21 13:26:47 +0000138 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
139 const size_t,ExceptionInfo *),
cristybb503372010-05-27 20:51:26 +0000140 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
141 const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000142 *SetPixelCacheNexusPixels(const Image *,const RectangleInfo *,NexusInfo *,
cristya4af2e32010-03-08 00:51:56 +0000143 ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +0000144
145#if defined(__cplusplus) || defined(c_plusplus)
146}
147#endif
148
149/*
150 Global declarations.
151*/
152static volatile MagickBooleanType
153 instantiate_cache = MagickFalse;
154
155static SemaphoreInfo
156 *cache_semaphore = (SemaphoreInfo *) NULL;
157
158static SplayTreeInfo
159 *cache_resources = (SplayTreeInfo *) NULL;
cristy3ed852e2009-09-05 21:47:34 +0000160
161/*
162%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
163% %
164% %
165% %
166+ A c q u i r e P i x e l C a c h e %
167% %
168% %
169% %
170%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
171%
172% AcquirePixelCache() acquires a pixel cache.
173%
174% The format of the AcquirePixelCache() method is:
175%
cristybb503372010-05-27 20:51:26 +0000176% Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000177%
178% A description of each parameter follows:
179%
180% o number_threads: the number of nexus threads.
181%
182*/
cristybb503372010-05-27 20:51:26 +0000183MagickExport Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000184{
185 CacheInfo
186 *cache_info;
187
cristy73bd4a52010-10-05 11:24:23 +0000188 cache_info=(CacheInfo *) AcquireMagickMemory(sizeof(*cache_info));
cristy3ed852e2009-09-05 21:47:34 +0000189 if (cache_info == (CacheInfo *) NULL)
190 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
191 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
192 cache_info->type=UndefinedCache;
cristy87528ea2009-09-10 14:53:56 +0000193 cache_info->mode=IOMode;
cristy3ed852e2009-09-05 21:47:34 +0000194 cache_info->colorspace=RGBColorspace;
195 cache_info->file=(-1);
196 cache_info->id=GetMagickThreadId();
197 cache_info->number_threads=number_threads;
198 if (number_threads == 0)
199 cache_info->number_threads=GetOpenMPMaximumThreads();
200 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
201 if (cache_info->nexus_info == (NexusInfo **) NULL)
202 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristy3ed852e2009-09-05 21:47:34 +0000203 cache_info->semaphore=AllocateSemaphoreInfo();
cristy93505cf2010-08-10 21:37:49 +0000204 cache_info->reference_count=1;
cristy3ed852e2009-09-05 21:47:34 +0000205 cache_info->disk_semaphore=AllocateSemaphoreInfo();
206 cache_info->debug=IsEventLogging();
207 cache_info->signature=MagickSignature;
208 if ((cache_resources == (SplayTreeInfo *) NULL) &&
209 (instantiate_cache == MagickFalse))
210 {
cristy4e1dff62009-10-25 20:36:03 +0000211 if (cache_semaphore == (SemaphoreInfo *) NULL)
212 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000213 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000214 if ((cache_resources == (SplayTreeInfo *) NULL) &&
215 (instantiate_cache == MagickFalse))
216 {
217 cache_resources=NewSplayTree((int (*)(const void *,const void *))
218 NULL,(void *(*)(void *)) NULL,(void *(*)(void *)) NULL);
219 instantiate_cache=MagickTrue;
220 }
cristyf84a1932010-01-03 18:00:18 +0000221 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000222 }
223 (void) AddValueToSplayTree(cache_resources,cache_info,cache_info);
224 return((Cache ) cache_info);
225}
226
227/*
228%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
229% %
230% %
231% %
232% A c q u i r e P i x e l C a c h e N e x u s %
233% %
234% %
235% %
236%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
237%
238% AcquirePixelCacheNexus() allocates the NexusInfo structure.
239%
240% The format of the AcquirePixelCacheNexus method is:
241%
cristybb503372010-05-27 20:51:26 +0000242% NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000243%
244% A description of each parameter follows:
245%
246% o number_threads: the number of nexus threads.
247%
248*/
cristy2cd7a752010-08-23 00:48:54 +0000249MagickExport NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000250{
cristy3ed852e2009-09-05 21:47:34 +0000251 NexusInfo
252 **nexus_info;
253
cristye076a6e2010-08-15 19:59:43 +0000254 register ssize_t
255 i;
256
cristyb41ee102010-10-04 16:46:15 +0000257 nexus_info=(NexusInfo **) AcquireQuantumMemory(number_threads,
cristy3ed852e2009-09-05 21:47:34 +0000258 sizeof(*nexus_info));
259 if (nexus_info == (NexusInfo **) NULL)
260 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristybb503372010-05-27 20:51:26 +0000261 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000262 {
cristy6a924af2010-09-23 14:02:54 +0000263 nexus_info[i]=(NexusInfo *) AcquireAlignedMemory(1,sizeof(**nexus_info));
cristy3ed852e2009-09-05 21:47:34 +0000264 if (nexus_info[i] == (NexusInfo *) NULL)
265 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
266 (void) ResetMagickMemory(nexus_info[i],0,sizeof(*nexus_info[i]));
267 nexus_info[i]->signature=MagickSignature;
268 }
269 return(nexus_info);
270}
271
272/*
273%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
274% %
275% %
276% %
cristyd43a46b2010-01-21 02:13:41 +0000277+ A c q u i r e P i x e l C a c h e P i x e l s %
278% %
279% %
280% %
281%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
282%
283% AcquirePixelCachePixels() returns the pixels associated with the specified
284% image.
285%
286% The format of the AcquirePixelCachePixels() method is:
287%
288% const void *AcquirePixelCachePixels(const Image *image,
289% MagickSizeType *length,ExceptionInfo *exception)
290%
291% A description of each parameter follows:
292%
293% o image: the image.
294%
295% o length: the pixel cache length.
296%
297% o exception: return any errors or warnings in this structure.
298%
299*/
300MagickExport const void *AcquirePixelCachePixels(const Image *image,
301 MagickSizeType *length,ExceptionInfo *exception)
302{
303 CacheInfo
304 *cache_info;
305
306 assert(image != (const Image *) NULL);
307 assert(image->signature == MagickSignature);
cristyd43a46b2010-01-21 02:13:41 +0000308 assert(exception != (ExceptionInfo *) NULL);
309 assert(exception->signature == MagickSignature);
310 assert(image->cache != (Cache) NULL);
311 cache_info=(CacheInfo *) image->cache;
312 assert(cache_info->signature == MagickSignature);
313 *length=0;
314 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
315 return((const void *) NULL);
316 *length=cache_info->length;
317 return((const void *) cache_info->pixels);
318}
319
320/*
321%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
322% %
323% %
324% %
cristyf34a1452009-10-24 22:29:27 +0000325+ C a c h e C o m p o n e n t G e n e s i s %
326% %
327% %
328% %
329%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
330%
331% CacheComponentGenesis() instantiates the cache component.
332%
333% The format of the CacheComponentGenesis method is:
334%
335% MagickBooleanType CacheComponentGenesis(void)
336%
337*/
338MagickExport MagickBooleanType CacheComponentGenesis(void)
339{
cristy165b6092009-10-26 13:52:10 +0000340 AcquireSemaphoreInfo(&cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000341 return(MagickTrue);
342}
343
344/*
345%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
346% %
347% %
348% %
349+ C a c h e C o m p o n e n t T e r m i n u s %
350% %
351% %
352% %
353%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
354%
355% CacheComponentTerminus() destroys the cache component.
356%
357% The format of the CacheComponentTerminus() method is:
358%
359% CacheComponentTerminus(void)
360%
361*/
362MagickExport void CacheComponentTerminus(void)
363{
cristy18b17442009-10-25 18:36:48 +0000364 if (cache_semaphore == (SemaphoreInfo *) NULL)
365 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000366 LockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000367 if (cache_resources != (SplayTreeInfo *) NULL)
368 cache_resources=DestroySplayTree(cache_resources);
369 instantiate_cache=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +0000370 UnlockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000371 DestroySemaphoreInfo(&cache_semaphore);
372}
373
374/*
375%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
376% %
377% %
378% %
cristy3ed852e2009-09-05 21:47:34 +0000379+ C l i p P i x e l C a c h e N e x u s %
380% %
381% %
382% %
383%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
384%
385% ClipPixelCacheNexus() clips the cache nexus as defined by the image clip
386% mask. The method returns MagickTrue if the pixel region is clipped,
387% otherwise MagickFalse.
388%
389% The format of the ClipPixelCacheNexus() method is:
390%
391% MagickBooleanType ClipPixelCacheNexus(Image *image,NexusInfo *nexus_info,
392% ExceptionInfo *exception)
393%
394% A description of each parameter follows:
395%
396% o image: the image.
397%
398% o nexus_info: the cache nexus to clip.
399%
400% o exception: return any errors or warnings in this structure.
401%
402*/
403static MagickBooleanType ClipPixelCacheNexus(Image *image,
404 NexusInfo *nexus_info,ExceptionInfo *exception)
405{
406 CacheInfo
407 *cache_info;
408
409 MagickSizeType
410 number_pixels;
411
412 NexusInfo
413 **clip_nexus,
414 **image_nexus;
415
416 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000417 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +0000418
419 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +0000420 *restrict nexus_indexes,
421 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +0000422
cristy3ed852e2009-09-05 21:47:34 +0000423 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000424 *restrict p,
425 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000426
cristye076a6e2010-08-15 19:59:43 +0000427 register ssize_t
428 i;
429
cristy3ed852e2009-09-05 21:47:34 +0000430 /*
431 Apply clip mask.
432 */
433 if (image->debug != MagickFalse)
434 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
435 if (image->clip_mask == (Image *) NULL)
436 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +0000437 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +0000438 if (cache_info == (Cache) NULL)
439 return(MagickFalse);
440 image_nexus=AcquirePixelCacheNexus(1);
441 clip_nexus=AcquirePixelCacheNexus(1);
442 if ((image_nexus == (NexusInfo **) NULL) ||
443 (clip_nexus == (NexusInfo **) NULL))
444 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
445 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,nexus_info->region.y,
446 nexus_info->region.width,nexus_info->region.height,image_nexus[0],
447 exception);
cristy2036f5c2010-09-19 21:18:17 +0000448 indexes=GetPixelCacheNexusIndexes(cache_info,image_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +0000449 q=nexus_info->pixels;
450 nexus_indexes=nexus_info->indexes;
451 r=GetVirtualPixelsFromNexus(image->clip_mask,MaskVirtualPixelMethod,
452 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
453 nexus_info->region.height,clip_nexus[0],exception);
454 number_pixels=(MagickSizeType) nexus_info->region.width*
455 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +0000456 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000457 {
458 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
459 break;
460 if (PixelIntensityToQuantum(r) > ((Quantum) QuantumRange/2))
461 {
cristyce70c172010-01-07 17:15:30 +0000462 SetRedPixelComponent(q,GetRedPixelComponent(p));
463 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
464 SetBluePixelComponent(q,GetBluePixelComponent(p));
465 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
cristy3ed852e2009-09-05 21:47:34 +0000466 if (cache_info->active_index_channel != MagickFalse)
467 nexus_indexes[i]=indexes[i];
468 }
469 p++;
470 q++;
471 r++;
472 }
473 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
474 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +0000475 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +0000476 return(MagickFalse);
477 return(MagickTrue);
478}
479
480/*
481%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
482% %
483% %
484% %
485+ C l o n e P i x e l C a c h e %
486% %
487% %
488% %
489%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
490%
491% ClonePixelCache() clones a pixel cache.
492%
493% The format of the ClonePixelCache() method is:
494%
495% Cache ClonePixelCache(const Cache cache)
496%
497% A description of each parameter follows:
498%
499% o cache: the pixel cache.
500%
501*/
502MagickExport Cache ClonePixelCache(const Cache cache)
503{
504 CacheInfo
505 *clone_info;
506
507 const CacheInfo
508 *cache_info;
509
510 assert(cache != (const Cache) NULL);
511 cache_info=(const CacheInfo *) cache;
512 assert(cache_info->signature == MagickSignature);
513 if (cache_info->debug != MagickFalse)
514 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
515 cache_info->filename);
516 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
517 if (clone_info == (Cache) NULL)
518 return((Cache) NULL);
519 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
520 return((Cache ) clone_info);
521}
522
523/*
524%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
525% %
526% %
527% %
cristy60c44a82009-10-07 00:58:49 +0000528+ 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 +0000529% %
530% %
531% %
532%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
533% ClonePixelCachePixels() clones the source pixel cache to the destination
534% cache.
535%
536% The format of the ClonePixelCachePixels() method is:
537%
538% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
539% CacheInfo *source_info,ExceptionInfo *exception)
540%
541% A description of each parameter follows:
542%
543% o cache_info: the pixel cache.
544%
545% o source_info: the source pixel cache.
546%
547% o exception: return any errors or warnings in this structure.
548%
549*/
550
551static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
552{
553 int
554 status;
555
cristy5ee247a2010-02-12 15:42:34 +0000556 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000557 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000558 if (cache_info->file != -1)
559 status=close(cache_info->file);
cristy3ed852e2009-09-05 21:47:34 +0000560 cache_info->file=(-1);
561 RelinquishMagickResource(FileResource,1);
cristyf84a1932010-01-03 18:00:18 +0000562 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000563 return(status == -1 ? MagickFalse : MagickTrue);
564}
565
566static void LimitPixelCacheDescriptors(void)
567{
568 register CacheInfo
569 *p,
570 *q;
571
572 /*
573 Limit # of open file descriptors.
574 */
575 if (GetMagickResource(FileResource) < GetMagickResourceLimit(FileResource))
576 return;
cristyf84a1932010-01-03 18:00:18 +0000577 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000578 if (cache_resources == (SplayTreeInfo *) NULL)
579 {
cristyf84a1932010-01-03 18:00:18 +0000580 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000581 return;
582 }
583 ResetSplayTreeIterator(cache_resources);
584 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
585 while (p != (CacheInfo *) NULL)
586 {
587 if ((p->type == DiskCache) && (p->file != -1))
cristy508d9312010-02-10 21:10:30 +0000588 break;
cristy3ed852e2009-09-05 21:47:34 +0000589 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
590 }
591 for (q=p; p != (CacheInfo *) NULL; )
592 {
593 if ((p->type == DiskCache) && (p->file != -1) &&
594 (p->timestamp < q->timestamp))
cristy508d9312010-02-10 21:10:30 +0000595 q=p;
cristy3ed852e2009-09-05 21:47:34 +0000596 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
597 }
598 if (q != (CacheInfo *) NULL)
cristy9e116922010-02-12 20:58:13 +0000599 {
600 /*
601 Close least recently used cache.
602 */
603 (void) close(q->file);
604 q->file=(-1);
605 }
cristyf84a1932010-01-03 18:00:18 +0000606 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000607}
608
609static inline MagickSizeType MagickMax(const MagickSizeType x,
610 const MagickSizeType y)
611{
612 if (x > y)
613 return(x);
614 return(y);
615}
616
617static inline MagickSizeType MagickMin(const MagickSizeType x,
618 const MagickSizeType y)
619{
620 if (x < y)
621 return(x);
622 return(y);
623}
624
625static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
626 const MapMode mode)
627{
628 int
629 file;
630
631 /*
632 Open pixel cache on disk.
633 */
cristyf84a1932010-01-03 18:00:18 +0000634 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000635 if (cache_info->file != -1)
636 {
cristyf84a1932010-01-03 18:00:18 +0000637 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000638 return(MagickTrue); /* cache already open */
639 }
640 LimitPixelCacheDescriptors();
641 if (*cache_info->cache_filename == '\0')
642 file=AcquireUniqueFileResource(cache_info->cache_filename);
643 else
644 switch (mode)
645 {
646 case ReadMode:
647 {
648 file=open(cache_info->cache_filename,O_RDONLY | O_BINARY);
649 break;
650 }
651 case WriteMode:
652 {
653 file=open(cache_info->cache_filename,O_WRONLY | O_CREAT | O_BINARY |
654 O_EXCL,S_MODE);
655 if (file == -1)
656 file=open(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
657 break;
658 }
659 case IOMode:
660 default:
661 {
662 file=open(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
663 O_EXCL,S_MODE);
664 if (file == -1)
665 file=open(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
666 break;
667 }
668 }
669 if (file == -1)
670 {
cristyf84a1932010-01-03 18:00:18 +0000671 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000672 return(MagickFalse);
673 }
674 (void) AcquireMagickResource(FileResource,1);
675 cache_info->file=file;
676 cache_info->timestamp=time(0);
cristyf84a1932010-01-03 18:00:18 +0000677 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000678 return(MagickTrue);
679}
680
681static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
682 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000683 unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000684{
685 register MagickOffsetType
686 i;
687
688 ssize_t
689 count;
690
cristy08a88202010-03-04 19:18:05 +0000691 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000692#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000693 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000694 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
695 {
cristyf84a1932010-01-03 18:00:18 +0000696 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000697 return((MagickOffsetType) -1);
698 }
699#endif
700 count=0;
701 for (i=0; i < (MagickOffsetType) length; i+=count)
702 {
703#if !defined(MAGICKCORE_HAVE_PREAD)
704 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
705 (MagickSizeType) SSIZE_MAX));
706#else
707 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
708 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
709#endif
710 if (count > 0)
711 continue;
712 count=0;
713 if (errno != EINTR)
714 {
715 i=(-1);
716 break;
717 }
718 }
719#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000720 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000721#endif
722 return(i);
723}
724
725static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
726 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000727 const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000728{
729 register MagickOffsetType
730 i;
731
732 ssize_t
733 count;
734
cristy08a88202010-03-04 19:18:05 +0000735 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000736#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000737 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000738 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
739 {
cristyf84a1932010-01-03 18:00:18 +0000740 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000741 return((MagickOffsetType) -1);
742 }
743#endif
744 count=0;
745 for (i=0; i < (MagickOffsetType) length; i+=count)
746 {
747#if !defined(MAGICKCORE_HAVE_PWRITE)
748 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
749 (MagickSizeType) SSIZE_MAX));
750#else
751 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
752 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
753#endif
754 if (count > 0)
755 continue;
756 count=0;
757 if (errno != EINTR)
758 {
759 i=(-1);
760 break;
761 }
762 }
763#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000764 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000765#endif
766 return(i);
767}
768
769static MagickBooleanType CloneDiskToDiskPixelCache(CacheInfo *clone_info,
770 CacheInfo *cache_info,ExceptionInfo *exception)
771{
772 MagickOffsetType
773 count,
774 offset,
775 source_offset;
776
777 MagickSizeType
778 length;
779
cristy3ed852e2009-09-05 21:47:34 +0000780 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000781 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +0000782
cristye076a6e2010-08-15 19:59:43 +0000783 register ssize_t
784 y;
785
cristybb503372010-05-27 20:51:26 +0000786 size_t
cristy3ed852e2009-09-05 21:47:34 +0000787 columns,
788 rows;
789
790 if (cache_info->debug != MagickFalse)
791 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
792 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
793 {
794 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
795 clone_info->cache_filename);
796 return(MagickFalse);
797 }
798 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
799 {
800 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
801 cache_info->cache_filename);
802 return(MagickFalse);
803 }
cristybb503372010-05-27 20:51:26 +0000804 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
805 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +0000806 if ((clone_info->active_index_channel != MagickFalse) &&
807 (cache_info->active_index_channel != MagickFalse))
808 {
809 register IndexPacket
810 *indexes;
811
812 /*
813 Clone cache indexes.
814 */
815 length=MagickMax(clone_info->columns,cache_info->columns)*
816 sizeof(*indexes);
817 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
818 if (indexes == (IndexPacket *) NULL)
819 {
820 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
821 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
822 return(MagickFalse);
823 }
824 (void) ResetMagickMemory(indexes,0,(size_t) length);
825 length=columns*sizeof(*indexes);
826 source_offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
827 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
828 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
829 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +0000830 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000831 {
832 source_offset-=cache_info->columns*sizeof(*indexes);
833 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
834 length,(unsigned char *) indexes);
835 if ((MagickSizeType) count != length)
836 break;
837 offset-=clone_info->columns*sizeof(*indexes);
838 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
839 (unsigned char *) indexes);
840 if ((MagickSizeType) count != length)
841 break;
842 }
cristybb503372010-05-27 20:51:26 +0000843 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000844 {
845 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
846 ThrowFileException(exception,CacheError,"UnableToCloneCache",
847 cache_info->cache_filename);
848 return(MagickFalse);
849 }
850 if (clone_info->columns > cache_info->columns)
851 {
852 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
853 (void) ResetMagickMemory(indexes,0,(size_t) length);
854 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
855 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +0000856 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000857 {
858 offset-=clone_info->columns*sizeof(*indexes);
859 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
860 length,(unsigned char *) indexes);
861 if ((MagickSizeType) count != length)
862 break;
863 }
cristybb503372010-05-27 20:51:26 +0000864 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000865 {
866 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
867 ThrowFileException(exception,CacheError,"UnableToCloneCache",
868 cache_info->cache_filename);
869 return(MagickFalse);
870 }
871 }
872 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
873 }
874 /*
875 Clone cache pixels.
876 */
877 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
878 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
879 if (pixels == (PixelPacket *) NULL)
880 {
881 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
882 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
883 return(MagickFalse);
884 }
885 (void) ResetMagickMemory(pixels,0,(size_t) length);
886 length=columns*sizeof(*pixels);
887 source_offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
888 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +0000889 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000890 {
891 source_offset-=cache_info->columns*sizeof(*pixels);
892 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
893 length,(unsigned char *) pixels);
894 if ((MagickSizeType) count != length)
895 break;
896 offset-=clone_info->columns*sizeof(*pixels);
897 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
898 (unsigned char *) pixels);
899 if ((MagickSizeType) count != length)
900 break;
901 }
cristybb503372010-05-27 20:51:26 +0000902 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000903 {
904 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
905 ThrowFileException(exception,CacheError,"UnableToCloneCache",
906 cache_info->cache_filename);
907 return(MagickFalse);
908 }
909 if (clone_info->columns > cache_info->columns)
910 {
911 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
912 sizeof(*pixels);
913 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
914 (void) ResetMagickMemory(pixels,0,(size_t) length);
cristybb503372010-05-27 20:51:26 +0000915 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000916 {
917 offset-=clone_info->columns*sizeof(*pixels);
918 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
919 (unsigned char *) pixels);
920 if ((MagickSizeType) count != length)
921 break;
922 }
cristybb503372010-05-27 20:51:26 +0000923 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000924 {
925 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
926 ThrowFileException(exception,CacheError,"UnableToCloneCache",
927 cache_info->cache_filename);
928 return(MagickFalse);
929 }
930 }
931 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
932 return(MagickTrue);
933}
934
935static MagickBooleanType CloneDiskToMemoryPixelCache(CacheInfo *clone_info,
936 CacheInfo *cache_info,ExceptionInfo *exception)
937{
938 MagickOffsetType
939 count,
940 offset;
941
942 MagickSizeType
943 length;
944
cristy3ed852e2009-09-05 21:47:34 +0000945 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000946 *restrict pixels,
947 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000948
cristye076a6e2010-08-15 19:59:43 +0000949 register ssize_t
950 y;
951
cristybb503372010-05-27 20:51:26 +0000952 size_t
cristy3ed852e2009-09-05 21:47:34 +0000953 columns,
954 rows;
955
956 if (cache_info->debug != MagickFalse)
957 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
958 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
959 {
960 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
961 cache_info->cache_filename);
962 return(MagickFalse);
963 }
cristybb503372010-05-27 20:51:26 +0000964 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
965 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +0000966 if ((clone_info->active_index_channel != MagickFalse) &&
967 (cache_info->active_index_channel != MagickFalse))
968 {
969 register IndexPacket
970 *indexes,
971 *q;
972
973 /*
974 Clone cache indexes.
975 */
976 length=MagickMax(clone_info->columns,cache_info->columns)*
977 sizeof(*indexes);
978 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
979 if (indexes == (IndexPacket *) NULL)
980 {
981 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
982 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
983 return(MagickFalse);
984 }
985 (void) ResetMagickMemory(indexes,0,(size_t) length);
986 length=columns*sizeof(IndexPacket);
987 offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
988 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
989 q=clone_info->indexes+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +0000990 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000991 {
992 offset-=cache_info->columns*sizeof(IndexPacket);
993 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,
994 length,(unsigned char *) indexes);
995 if ((MagickSizeType) count != length)
996 break;
997 q-=clone_info->columns;
cristy8f036fe2010-09-18 02:02:00 +0000998 (void) memcpy(q,indexes,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +0000999 if ((MagickSizeType) count != length)
1000 break;
1001 }
cristybb503372010-05-27 20:51:26 +00001002 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001003 {
1004 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1005 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1006 cache_info->cache_filename);
1007 return(MagickFalse);
1008 }
1009 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1010 }
1011 /*
1012 Clone cache pixels.
1013 */
1014 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1015 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1016 if (pixels == (PixelPacket *) NULL)
1017 {
1018 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1019 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1020 return(MagickFalse);
1021 }
1022 (void) ResetMagickMemory(pixels,0,(size_t) length);
1023 length=columns*sizeof(*pixels);
1024 offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
1025 q=clone_info->pixels+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001026 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001027 {
1028 offset-=cache_info->columns*sizeof(*pixels);
1029 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,length,
1030 (unsigned char *) pixels);
1031 if ((MagickSizeType) count != length)
1032 break;
1033 q-=clone_info->columns;
cristy8f036fe2010-09-18 02:02:00 +00001034 (void) memcpy(q,pixels,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00001035 }
cristybb503372010-05-27 20:51:26 +00001036 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001037 {
1038 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1039 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1040 cache_info->cache_filename);
1041 return(MagickFalse);
1042 }
1043 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1044 return(MagickTrue);
1045}
1046
1047static MagickBooleanType CloneMemoryToDiskPixelCache(CacheInfo *clone_info,
1048 CacheInfo *cache_info,ExceptionInfo *exception)
1049{
1050 MagickOffsetType
1051 count,
1052 offset;
1053
1054 MagickSizeType
1055 length;
1056
cristy3ed852e2009-09-05 21:47:34 +00001057 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001058 *restrict p,
1059 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +00001060
cristye076a6e2010-08-15 19:59:43 +00001061 register ssize_t
1062 y;
1063
cristybb503372010-05-27 20:51:26 +00001064 size_t
cristy3ed852e2009-09-05 21:47:34 +00001065 columns,
1066 rows;
1067
1068 if (cache_info->debug != MagickFalse)
1069 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
1070 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
1071 {
1072 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1073 clone_info->cache_filename);
1074 return(MagickFalse);
1075 }
cristybb503372010-05-27 20:51:26 +00001076 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1077 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001078 if ((clone_info->active_index_channel != MagickFalse) &&
1079 (cache_info->active_index_channel != MagickFalse))
1080 {
1081 register IndexPacket
1082 *p,
1083 *indexes;
1084
1085 /*
1086 Clone cache indexes.
1087 */
1088 length=MagickMax(clone_info->columns,cache_info->columns)*
1089 sizeof(*indexes);
1090 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
1091 if (indexes == (IndexPacket *) NULL)
1092 {
1093 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1094 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1095 return(MagickFalse);
1096 }
1097 (void) ResetMagickMemory(indexes,0,(size_t) length);
1098 length=columns*sizeof(*indexes);
1099 p=cache_info->indexes+cache_info->columns*rows;
1100 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1101 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +00001102 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001103 {
1104 p-=cache_info->columns;
cristy8f036fe2010-09-18 02:02:00 +00001105 (void) memcpy(indexes,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00001106 offset-=clone_info->columns*sizeof(*indexes);
1107 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1108 (unsigned char *) indexes);
1109 if ((MagickSizeType) count != length)
1110 break;
1111 }
cristybb503372010-05-27 20:51:26 +00001112 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001113 {
1114 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1115 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1116 cache_info->cache_filename);
1117 return(MagickFalse);
1118 }
1119 if (clone_info->columns > cache_info->columns)
1120 {
1121 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
1122 (void) ResetMagickMemory(indexes,0,(size_t) length);
1123 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1124 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +00001125 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001126 {
1127 offset-=clone_info->columns*sizeof(*indexes);
1128 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
1129 length,(unsigned char *) indexes);
1130 if ((MagickSizeType) count != length)
1131 break;
1132 }
cristybb503372010-05-27 20:51:26 +00001133 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001134 {
1135 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1136 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1137 cache_info->cache_filename);
1138 return(MagickFalse);
1139 }
1140 }
1141 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1142 }
1143 /*
1144 Clone cache pixels.
1145 */
1146 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1147 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1148 if (pixels == (PixelPacket *) NULL)
1149 {
1150 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1151 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1152 return(MagickFalse);
1153 }
1154 (void) ResetMagickMemory(pixels,0,(size_t) length);
1155 length=columns*sizeof(*pixels);
1156 p=cache_info->pixels+cache_info->columns*rows;
1157 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +00001158 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001159 {
1160 p-=cache_info->columns;
cristy8f036fe2010-09-18 02:02:00 +00001161 (void) memcpy(pixels,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00001162 offset-=clone_info->columns*sizeof(*pixels);
1163 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1164 (unsigned char *) pixels);
1165 if ((MagickSizeType) count != length)
1166 break;
1167 }
cristybb503372010-05-27 20:51:26 +00001168 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001169 {
1170 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1171 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1172 cache_info->cache_filename);
1173 return(MagickFalse);
1174 }
1175 if (clone_info->columns > cache_info->columns)
1176 {
1177 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
1178 sizeof(*pixels);
1179 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1180 (void) ResetMagickMemory(pixels,0,(size_t) length);
cristybb503372010-05-27 20:51:26 +00001181 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001182 {
1183 offset-=clone_info->columns*sizeof(*pixels);
1184 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1185 (unsigned char *) pixels);
1186 if ((MagickSizeType) count != length)
1187 break;
1188 }
cristybb503372010-05-27 20:51:26 +00001189 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001190 {
1191 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1192 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1193 cache_info->cache_filename);
1194 return(MagickFalse);
1195 }
1196 }
1197 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1198 return(MagickTrue);
1199}
1200
1201static MagickBooleanType CloneMemoryToMemoryPixelCache(CacheInfo *clone_info,
1202 CacheInfo *cache_info,ExceptionInfo *magick_unused(exception))
1203{
cristy3ed852e2009-09-05 21:47:34 +00001204 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001205 *restrict pixels,
1206 *restrict source_pixels;
cristy3ed852e2009-09-05 21:47:34 +00001207
cristye076a6e2010-08-15 19:59:43 +00001208 register ssize_t
1209 y;
cristy3ed852e2009-09-05 21:47:34 +00001210
cristybb503372010-05-27 20:51:26 +00001211 size_t
cristy3ed852e2009-09-05 21:47:34 +00001212 columns,
cristye076a6e2010-08-15 19:59:43 +00001213 length,
cristy3ed852e2009-09-05 21:47:34 +00001214 rows;
1215
1216 if (cache_info->debug != MagickFalse)
1217 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
cristybb503372010-05-27 20:51:26 +00001218 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1219 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001220 if ((clone_info->active_index_channel != MagickFalse) &&
1221 (cache_info->active_index_channel != MagickFalse))
1222 {
1223 register IndexPacket
1224 *indexes,
1225 *source_indexes;
1226
1227 /*
1228 Clone cache indexes.
1229 */
1230 length=columns*sizeof(*indexes);
1231 if (clone_info->columns == cache_info->columns)
cristy8f036fe2010-09-18 02:02:00 +00001232 (void) memcpy(clone_info->indexes,cache_info->indexes,length*rows);
cristy3ed852e2009-09-05 21:47:34 +00001233 else
1234 {
1235 source_indexes=cache_info->indexes+cache_info->columns*rows;
1236 indexes=clone_info->indexes+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001237 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001238 {
1239 source_indexes-=cache_info->columns;
1240 indexes-=clone_info->columns;
cristy8f036fe2010-09-18 02:02:00 +00001241 (void) memcpy(indexes,source_indexes,length);
cristy3ed852e2009-09-05 21:47:34 +00001242 }
1243 if (clone_info->columns > cache_info->columns)
1244 {
1245 length=(clone_info->columns-cache_info->columns)*
1246 sizeof(*indexes);
1247 indexes=clone_info->indexes+clone_info->columns*rows+
1248 cache_info->columns;
cristybb503372010-05-27 20:51:26 +00001249 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001250 {
1251 indexes-=clone_info->columns;
1252 (void) ResetMagickMemory(indexes,0,length);
1253 }
1254 }
1255 }
1256 }
1257 /*
1258 Clone cache pixels.
1259 */
1260 length=columns*sizeof(*pixels);
1261 if (clone_info->columns == cache_info->columns)
cristy8f036fe2010-09-18 02:02:00 +00001262 (void) memcpy(clone_info->pixels,cache_info->pixels,length*rows);
cristy3ed852e2009-09-05 21:47:34 +00001263 else
1264 {
1265 source_pixels=cache_info->pixels+cache_info->columns*rows;
1266 pixels=clone_info->pixels+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001267 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001268 {
1269 source_pixels-=cache_info->columns;
1270 pixels-=clone_info->columns;
cristy8f036fe2010-09-18 02:02:00 +00001271 (void) memcpy(pixels,source_pixels,length);
cristy3ed852e2009-09-05 21:47:34 +00001272 }
1273 if (clone_info->columns > cache_info->columns)
1274 {
1275 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1276 pixels=clone_info->pixels+clone_info->columns*rows+
1277 cache_info->columns;
cristybb503372010-05-27 20:51:26 +00001278 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001279 {
1280 pixels-=clone_info->columns;
1281 (void) ResetMagickMemory(pixels,0,length);
1282 }
1283 }
1284 }
1285 return(MagickTrue);
1286}
1287
1288static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1289 CacheInfo *cache_info,ExceptionInfo *exception)
1290{
1291 if ((clone_info->type != DiskCache) && (cache_info->type != DiskCache))
1292 return(CloneMemoryToMemoryPixelCache(clone_info,cache_info,exception));
1293 if ((clone_info->type == DiskCache) && (cache_info->type == DiskCache))
1294 return(CloneDiskToDiskPixelCache(clone_info,cache_info,exception));
1295 if (cache_info->type == DiskCache)
1296 return(CloneDiskToMemoryPixelCache(clone_info,cache_info,exception));
1297 return(CloneMemoryToDiskPixelCache(clone_info,cache_info,exception));
1298}
1299
1300/*
1301%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1302% %
1303% %
1304% %
1305+ C l o n e P i x e l C a c h e M e t h o d s %
1306% %
1307% %
1308% %
1309%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1310%
1311% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1312% another.
1313%
1314% The format of the ClonePixelCacheMethods() method is:
1315%
1316% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1317%
1318% A description of each parameter follows:
1319%
1320% o clone: Specifies a pointer to a Cache structure.
1321%
1322% o cache: the pixel cache.
1323%
1324*/
1325MagickExport void ClonePixelCacheMethods(Cache clone,const Cache cache)
1326{
1327 CacheInfo
1328 *cache_info,
1329 *source_info;
1330
1331 assert(clone != (Cache) NULL);
1332 source_info=(CacheInfo *) clone;
1333 assert(source_info->signature == MagickSignature);
1334 if (source_info->debug != MagickFalse)
1335 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1336 source_info->filename);
1337 assert(cache != (Cache) NULL);
1338 cache_info=(CacheInfo *) cache;
1339 assert(cache_info->signature == MagickSignature);
1340 source_info->methods=cache_info->methods;
1341}
1342
1343/*
1344%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1345% %
1346% %
1347% %
1348+ D e s t r o y I m a g e P i x e l C a c h e %
1349% %
1350% %
1351% %
1352%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1353%
1354% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1355%
1356% The format of the DestroyImagePixelCache() method is:
1357%
1358% void DestroyImagePixelCache(Image *image)
1359%
1360% A description of each parameter follows:
1361%
1362% o image: the image.
1363%
1364*/
1365static void DestroyImagePixelCache(Image *image)
1366{
1367 assert(image != (Image *) NULL);
1368 assert(image->signature == MagickSignature);
1369 if (image->debug != MagickFalse)
1370 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1371 if (image->cache == (void *) NULL)
1372 return;
1373 image->cache=DestroyPixelCache(image->cache);
1374}
1375
1376/*
1377%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1378% %
1379% %
1380% %
1381+ D e s t r o y I m a g e P i x e l s %
1382% %
1383% %
1384% %
1385%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1386%
1387% DestroyImagePixels() deallocates memory associated with the pixel cache.
1388%
1389% The format of the DestroyImagePixels() method is:
1390%
1391% void DestroyImagePixels(Image *image)
1392%
1393% A description of each parameter follows:
1394%
1395% o image: the image.
1396%
1397*/
1398MagickExport void DestroyImagePixels(Image *image)
1399{
1400 CacheInfo
1401 *cache_info;
1402
1403 assert(image != (const Image *) NULL);
1404 assert(image->signature == MagickSignature);
1405 if (image->debug != MagickFalse)
1406 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1407 assert(image->cache != (Cache) NULL);
1408 cache_info=(CacheInfo *) image->cache;
1409 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001410 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1411 {
1412 cache_info->methods.destroy_pixel_handler(image);
1413 return;
1414 }
cristy2036f5c2010-09-19 21:18:17 +00001415 image->cache=DestroyPixelCache(image->cache);
cristy3ed852e2009-09-05 21:47:34 +00001416}
1417
1418/*
1419%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1420% %
1421% %
1422% %
1423+ D e s t r o y P i x e l C a c h e %
1424% %
1425% %
1426% %
1427%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1428%
1429% DestroyPixelCache() deallocates memory associated with the pixel cache.
1430%
1431% The format of the DestroyPixelCache() method is:
1432%
1433% Cache DestroyPixelCache(Cache cache)
1434%
1435% A description of each parameter follows:
1436%
1437% o cache: the pixel cache.
1438%
1439*/
1440
1441static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1442{
1443 switch (cache_info->type)
1444 {
1445 case MemoryCache:
1446 {
1447 if (cache_info->mapped == MagickFalse)
1448 cache_info->pixels=(PixelPacket *) RelinquishMagickMemory(
1449 cache_info->pixels);
1450 else
1451 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,
1452 (size_t) cache_info->length);
1453 RelinquishMagickResource(MemoryResource,cache_info->length);
1454 break;
1455 }
1456 case MapCache:
1457 {
1458 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,(size_t)
1459 cache_info->length);
1460 RelinquishMagickResource(MapResource,cache_info->length);
1461 }
1462 case DiskCache:
1463 {
1464 if (cache_info->file != -1)
1465 (void) ClosePixelCacheOnDisk(cache_info);
1466 RelinquishMagickResource(DiskResource,cache_info->length);
1467 break;
1468 }
1469 default:
1470 break;
1471 }
1472 cache_info->type=UndefinedCache;
1473 cache_info->mapped=MagickFalse;
1474 cache_info->indexes=(IndexPacket *) NULL;
1475}
1476
1477MagickExport Cache DestroyPixelCache(Cache cache)
1478{
1479 CacheInfo
1480 *cache_info;
1481
cristy3ed852e2009-09-05 21:47:34 +00001482 assert(cache != (Cache) NULL);
1483 cache_info=(CacheInfo *) cache;
1484 assert(cache_info->signature == MagickSignature);
1485 if (cache_info->debug != MagickFalse)
1486 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1487 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001488 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001489 cache_info->reference_count--;
1490 if (cache_info->reference_count != 0)
1491 {
cristyf84a1932010-01-03 18:00:18 +00001492 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001493 return((Cache) NULL);
1494 }
cristyf84a1932010-01-03 18:00:18 +00001495 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001496 if (cache_resources != (SplayTreeInfo *) NULL)
1497 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
cristy5b8de732009-09-10 23:50:40 +00001498 if (cache_info->debug != MagickFalse)
1499 {
1500 char
1501 message[MaxTextExtent];
1502
1503 (void) FormatMagickString(message,MaxTextExtent,"destroy %s",
1504 cache_info->filename);
1505 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1506 }
cristyc2e1bdd2009-09-10 23:43:34 +00001507 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1508 (cache_info->type != DiskCache)))
1509 RelinquishPixelCachePixels(cache_info);
1510 else
1511 {
1512 RelinquishPixelCachePixels(cache_info);
1513 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1514 }
cristy3ed852e2009-09-05 21:47:34 +00001515 *cache_info->cache_filename='\0';
1516 if (cache_info->nexus_info != (NexusInfo **) NULL)
1517 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1518 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001519 if (cache_info->random_info != (RandomInfo *) NULL)
1520 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001521 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1522 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1523 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1524 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001525 cache_info->signature=(~MagickSignature);
cristyb41ee102010-10-04 16:46:15 +00001526 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001527 cache=(Cache) NULL;
1528 return(cache);
1529}
1530
1531/*
1532%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1533% %
1534% %
1535% %
1536+ D e s t r o y P i x e l C a c h e N e x u s %
1537% %
1538% %
1539% %
1540%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1541%
1542% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1543%
1544% The format of the DestroyPixelCacheNexus() method is:
1545%
1546% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001547% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001548%
1549% A description of each parameter follows:
1550%
1551% o nexus_info: the nexus to destroy.
1552%
1553% o number_threads: the number of nexus threads.
1554%
1555*/
1556
1557static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1558{
1559 if (nexus_info->mapped == MagickFalse)
1560 (void) RelinquishMagickMemory(nexus_info->cache);
1561 else
1562 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1563 nexus_info->cache=(PixelPacket *) NULL;
1564 nexus_info->pixels=(PixelPacket *) NULL;
1565 nexus_info->indexes=(IndexPacket *) NULL;
1566 nexus_info->length=0;
1567 nexus_info->mapped=MagickFalse;
1568}
1569
1570MagickExport NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001571 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001572{
cristybb503372010-05-27 20:51:26 +00001573 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001574 i;
1575
1576 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001577 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001578 {
1579 if (nexus_info[i]->cache != (PixelPacket *) NULL)
1580 RelinquishCacheNexusPixels(nexus_info[i]);
1581 nexus_info[i]->signature=(~MagickSignature);
1582 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
1583 }
cristyb41ee102010-10-04 16:46:15 +00001584 nexus_info=(NexusInfo **) RelinquishMagickMemory(nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00001585 return(nexus_info);
1586}
1587
1588/*
1589%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1590% %
1591% %
1592% %
cristy3ed852e2009-09-05 21:47:34 +00001593+ 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 %
1594% %
1595% %
1596% %
1597%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1598%
1599% GetAuthenticIndexesFromCache() returns the indexes associated with the last
1600% call to QueueAuthenticPixelsCache() or GetAuthenticPixelsCache().
1601%
1602% The format of the GetAuthenticIndexesFromCache() method is:
1603%
1604% IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1605%
1606% A description of each parameter follows:
1607%
1608% o image: the image.
1609%
1610*/
1611static IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1612{
1613 CacheInfo
1614 *cache_info;
1615
cristy5c9e6f22010-09-17 17:31:01 +00001616 const int
1617 id = GetOpenMPThreadId();
1618
cristye7cc7cf2010-09-21 13:26:47 +00001619 assert(image != (const Image *) NULL);
1620 assert(image->signature == MagickSignature);
1621 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001622 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001623 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001624 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001625 return(GetPixelCacheNexusIndexes(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001626}
1627
1628/*
1629%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1630% %
1631% %
1632% %
1633% G e t A u t h e n t i c I n d e x Q u e u e %
1634% %
1635% %
1636% %
1637%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1638%
1639% GetAuthenticIndexQueue() returns the authentic black channel or the colormap
1640% indexes associated with the last call to QueueAuthenticPixels() or
1641% GetVirtualPixels(). NULL is returned if the black channel or colormap
1642% indexes are not available.
1643%
1644% The format of the GetAuthenticIndexQueue() method is:
1645%
1646% IndexPacket *GetAuthenticIndexQueue(const Image *image)
1647%
1648% A description of each parameter follows:
1649%
1650% o image: the image.
1651%
1652*/
1653MagickExport IndexPacket *GetAuthenticIndexQueue(const Image *image)
1654{
1655 CacheInfo
1656 *cache_info;
1657
cristy2036f5c2010-09-19 21:18:17 +00001658 const int
1659 id = GetOpenMPThreadId();
1660
cristy3ed852e2009-09-05 21:47:34 +00001661 assert(image != (const Image *) NULL);
1662 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001663 assert(image->cache != (Cache) NULL);
1664 cache_info=(CacheInfo *) image->cache;
1665 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001666 if (cache_info->methods.get_authentic_indexes_from_handler !=
cristy3ed852e2009-09-05 21:47:34 +00001667 (GetAuthenticIndexesFromHandler) NULL)
cristyd317f372010-09-18 01:42:20 +00001668 return(cache_info->methods.get_authentic_indexes_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001669 assert(id < (int) cache_info->number_threads);
1670 return(GetPixelCacheNexusIndexes(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001671}
1672
1673/*
1674%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1675% %
1676% %
1677% %
1678+ 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 %
1679% %
1680% %
1681% %
1682%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1683%
1684% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1685% disk pixel cache as defined by the geometry parameters. A pointer to the
1686% pixels is returned if the pixels are transferred, otherwise a NULL is
1687% returned.
1688%
1689% The format of the GetAuthenticPixelCacheNexus() method is:
1690%
cristybb503372010-05-27 20:51:26 +00001691% PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1692% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001693% NexusInfo *nexus_info,ExceptionInfo *exception)
1694%
1695% A description of each parameter follows:
1696%
1697% o image: the image.
1698%
1699% o x,y,columns,rows: These values define the perimeter of a region of
1700% pixels.
1701%
1702% o nexus_info: the cache nexus to return.
1703%
1704% o exception: return any errors or warnings in this structure.
1705%
1706*/
1707
1708static inline MagickBooleanType IsNexusInCore(const CacheInfo *cache_info,
1709 NexusInfo *nexus_info)
1710{
1711 MagickOffsetType
1712 offset;
1713
cristy73724512010-04-12 14:43:14 +00001714 if (cache_info->type == PingCache)
1715 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001716 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1717 nexus_info->region.x;
cristy096bf2c2010-09-22 11:55:02 +00001718 return(nexus_info->pixels == (cache_info->pixels+offset) ? MagickTrue :
1719 MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +00001720}
1721
cristye076a6e2010-08-15 19:59:43 +00001722MagickExport PixelPacket *GetAuthenticPixelCacheNexus(Image *image,
1723 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001724 NexusInfo *nexus_info,ExceptionInfo *exception)
1725{
1726 CacheInfo
1727 *cache_info;
1728
1729 PixelPacket
1730 *pixels;
1731
1732 /*
1733 Transfer pixels from the cache.
1734 */
1735 assert(image != (Image *) NULL);
1736 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001737 pixels=QueueAuthenticNexus(image,x,y,columns,rows,nexus_info,exception);
1738 if (pixels == (PixelPacket *) NULL)
1739 return((PixelPacket *) NULL);
1740 cache_info=(CacheInfo *) image->cache;
1741 assert(cache_info->signature == MagickSignature);
1742 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
1743 return(pixels);
1744 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1745 return((PixelPacket *) NULL);
1746 if (cache_info->active_index_channel != MagickFalse)
1747 if (ReadPixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse)
1748 return((PixelPacket *) NULL);
1749 return(pixels);
1750}
1751
1752/*
1753%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1754% %
1755% %
1756% %
1757+ 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 %
1758% %
1759% %
1760% %
1761%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1762%
1763% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1764% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1765%
1766% The format of the GetAuthenticPixelsFromCache() method is:
1767%
1768% PixelPacket *GetAuthenticPixelsFromCache(const Image image)
1769%
1770% A description of each parameter follows:
1771%
1772% o image: the image.
1773%
1774*/
1775static PixelPacket *GetAuthenticPixelsFromCache(const Image *image)
1776{
1777 CacheInfo
1778 *cache_info;
1779
cristy5c9e6f22010-09-17 17:31:01 +00001780 const int
1781 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001782
cristye7cc7cf2010-09-21 13:26:47 +00001783 assert(image != (const Image *) NULL);
1784 assert(image->signature == MagickSignature);
1785 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001786 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001787 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001788 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001789 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001790}
1791
1792/*
1793%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1794% %
1795% %
1796% %
1797% G e t A u t h e n t i c P i x e l Q u e u e %
1798% %
1799% %
1800% %
1801%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1802%
1803% GetAuthenticPixelQueue() returns the authentic pixels associated with the
1804% last call to QueueAuthenticPixels() or GetAuthenticPixels().
1805%
1806% The format of the GetAuthenticPixelQueue() method is:
1807%
1808% PixelPacket *GetAuthenticPixelQueue(const Image image)
1809%
1810% A description of each parameter follows:
1811%
1812% o image: the image.
1813%
1814*/
1815MagickExport PixelPacket *GetAuthenticPixelQueue(const Image *image)
1816{
1817 CacheInfo
1818 *cache_info;
1819
cristy2036f5c2010-09-19 21:18:17 +00001820 const int
1821 id = GetOpenMPThreadId();
1822
cristy3ed852e2009-09-05 21:47:34 +00001823 assert(image != (const Image *) NULL);
1824 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001825 assert(image->cache != (Cache) NULL);
1826 cache_info=(CacheInfo *) image->cache;
1827 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001828 if (cache_info->methods.get_authentic_pixels_from_handler !=
1829 (GetAuthenticPixelsFromHandler) NULL)
1830 return(cache_info->methods.get_authentic_pixels_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001831 assert(id < (int) cache_info->number_threads);
1832 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001833}
1834
1835/*
1836%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1837% %
1838% %
1839% %
1840% G e t A u t h e n t i c P i x e l s %
1841% %
1842% %
1843% %
1844%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1845%
1846% GetAuthenticPixels() obtains a pixel region for read/write access. If the
1847% region is successfully accessed, a pointer to a PixelPacket array
1848% representing the region is returned, otherwise NULL is returned.
1849%
1850% The returned pointer may point to a temporary working copy of the pixels
1851% or it may point to the original pixels in memory. Performance is maximized
1852% if the selected region is part of one row, or one or more full rows, since
1853% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001854% if the image is in memory, or in a memory-mapped file. The returned pointer
1855% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001856%
1857% Pixels accessed via the returned pointer represent a simple array of type
1858% PixelPacket. If the image type is CMYK or if the storage class is
1859% PseduoClass, call GetAuthenticIndexQueue() after invoking
1860% GetAuthenticPixels() to obtain the black color component or colormap indexes
1861% (of type IndexPacket) corresponding to the region. Once the PixelPacket
1862% (and/or IndexPacket) array has been updated, the changes must be saved back
1863% to the underlying image using SyncAuthenticPixels() or they may be lost.
1864%
1865% The format of the GetAuthenticPixels() method is:
1866%
cristy5f959472010-05-27 22:19:46 +00001867% PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1868% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001869% ExceptionInfo *exception)
1870%
1871% A description of each parameter follows:
1872%
1873% o image: the image.
1874%
1875% o x,y,columns,rows: These values define the perimeter of a region of
1876% pixels.
1877%
1878% o exception: return any errors or warnings in this structure.
1879%
1880*/
cristybb503372010-05-27 20:51:26 +00001881MagickExport PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1882 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001883 ExceptionInfo *exception)
1884{
1885 CacheInfo
1886 *cache_info;
1887
cristy2036f5c2010-09-19 21:18:17 +00001888 const int
1889 id = GetOpenMPThreadId();
1890
cristy3ed852e2009-09-05 21:47:34 +00001891 assert(image != (Image *) NULL);
1892 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001893 assert(image->cache != (Cache) NULL);
1894 cache_info=(CacheInfo *) image->cache;
1895 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001896 if (cache_info->methods.get_authentic_pixels_handler !=
1897 (GetAuthenticPixelsHandler) NULL)
1898 return(cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1899 rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00001900 assert(id < (int) cache_info->number_threads);
1901 return(GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1902 cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00001903}
1904
1905/*
1906%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1907% %
1908% %
1909% %
1910+ G e t A u t h e n t i c P i x e l s C a c h e %
1911% %
1912% %
1913% %
1914%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1915%
1916% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1917% as defined by the geometry parameters. A pointer to the pixels is returned
1918% if the pixels are transferred, otherwise a NULL is returned.
1919%
1920% The format of the GetAuthenticPixelsCache() method is:
1921%
cristybb503372010-05-27 20:51:26 +00001922% PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1923% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001924% ExceptionInfo *exception)
1925%
1926% A description of each parameter follows:
1927%
1928% o image: the image.
1929%
1930% o x,y,columns,rows: These values define the perimeter of a region of
1931% pixels.
1932%
1933% o exception: return any errors or warnings in this structure.
1934%
1935*/
cristybb503372010-05-27 20:51:26 +00001936static PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1937 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001938 ExceptionInfo *exception)
1939{
1940 CacheInfo
1941 *cache_info;
1942
cristy5c9e6f22010-09-17 17:31:01 +00001943 const int
1944 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001945
cristye7cc7cf2010-09-21 13:26:47 +00001946 assert(image != (const Image *) NULL);
1947 assert(image->signature == MagickSignature);
1948 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00001949 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001950 if (cache_info == (Cache) NULL)
1951 return((PixelPacket *) NULL);
cristye7cc7cf2010-09-21 13:26:47 +00001952 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001953 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001954 return(GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1955 cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00001956}
1957
1958/*
1959%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1960% %
1961% %
1962% %
1963+ G e t I m a g e E x t e n t %
1964% %
1965% %
1966% %
1967%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1968%
1969% GetImageExtent() returns the extent of the pixels associated with the
1970% last call to QueueAuthenticPixels() or GetAuthenticPixels().
1971%
1972% The format of the GetImageExtent() method is:
1973%
1974% MagickSizeType GetImageExtent(const Image *image)
1975%
1976% A description of each parameter follows:
1977%
1978% o image: the image.
1979%
1980*/
1981MagickExport MagickSizeType GetImageExtent(const Image *image)
1982{
1983 CacheInfo
1984 *cache_info;
1985
cristy5c9e6f22010-09-17 17:31:01 +00001986 const int
1987 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001988
cristy3ed852e2009-09-05 21:47:34 +00001989 assert(image != (Image *) NULL);
1990 assert(image->signature == MagickSignature);
1991 if (image->debug != MagickFalse)
1992 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1993 assert(image->cache != (Cache) NULL);
1994 cache_info=(CacheInfo *) image->cache;
1995 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001996 assert(id < (int) cache_info->number_threads);
cristy2036f5c2010-09-19 21:18:17 +00001997 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001998}
1999
2000/*
2001%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2002% %
2003% %
2004% %
2005+ G e t I m a g e P i x e l C a c h e %
2006% %
2007% %
2008% %
2009%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2010%
2011% GetImagePixelCache() ensures that there is only a single reference to the
2012% pixel cache to be modified, updating the provided cache pointer to point to
2013% a clone of the original pixel cache if necessary.
2014%
2015% The format of the GetImagePixelCache method is:
2016%
2017% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2018% ExceptionInfo *exception)
2019%
2020% A description of each parameter follows:
2021%
2022% o image: the image.
2023%
2024% o clone: any value other than MagickFalse clones the cache pixels.
2025%
2026% o exception: return any errors or warnings in this structure.
2027%
2028*/
cristy3ed852e2009-09-05 21:47:34 +00002029static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
2030{
2031 CacheInfo
2032 *cache_info;
2033
2034 /*
2035 Does the image match the pixel cache morphology?
2036 */
2037 cache_info=(CacheInfo *) image->cache;
2038 if ((image->storage_class != cache_info->storage_class) ||
2039 (image->colorspace != cache_info->colorspace) ||
2040 (image->columns != cache_info->columns) ||
2041 (image->rows != cache_info->rows) ||
2042 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2043 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2044 return(MagickFalse);
2045 return(MagickTrue);
2046}
2047
cristy77ff0282010-09-13 00:51:10 +00002048static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2049 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002050{
2051 CacheInfo
2052 *cache_info;
2053
cristy3ed852e2009-09-05 21:47:34 +00002054 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00002055 destroy,
cristy3ed852e2009-09-05 21:47:34 +00002056 status;
2057
cristy50a10922010-02-15 18:35:25 +00002058 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00002059 cpu_throttle = 0,
2060 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00002061 time_limit = 0;
2062
cristy1ea34962010-07-01 19:49:21 +00002063 static time_t
cristya21afde2010-07-02 00:45:40 +00002064 cache_genesis = 0;
cristy1ea34962010-07-01 19:49:21 +00002065
cristyc4f9f132010-03-04 18:50:01 +00002066 status=MagickTrue;
2067 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00002068 if (cpu_throttle == 0)
2069 {
2070 char
2071 *limit;
2072
2073 /*
2074 Set CPU throttle in milleseconds.
2075 */
2076 cpu_throttle=MagickResourceInfinity;
2077 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2078 if (limit == (char *) NULL)
2079 limit=GetPolicyValue("throttle");
2080 if (limit != (char *) NULL)
2081 {
2082 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2083 limit=DestroyString(limit);
2084 }
2085 }
2086 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2087 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00002088 if (time_limit == 0)
2089 {
cristy6ebe97c2010-07-03 01:17:28 +00002090 /*
2091 Set the exire time in seconds.
2092 */
cristy1ea34962010-07-01 19:49:21 +00002093 time_limit=GetMagickResourceLimit(TimeResource);
cristya21afde2010-07-02 00:45:40 +00002094 cache_genesis=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00002095 }
2096 if ((time_limit != MagickResourceInfinity) &&
cristya21afde2010-07-02 00:45:40 +00002097 ((MagickSizeType) (time((time_t *) NULL)-cache_genesis) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00002098 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00002099 assert(image->cache != (Cache) NULL);
2100 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002101 destroy=MagickFalse;
cristy0cb42c72010-11-06 15:53:41 +00002102 if (cache_info->type != PingCache)
cristy3ed852e2009-09-05 21:47:34 +00002103 {
cristyaaa0cb62010-02-15 17:47:27 +00002104 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002105 {
cristy0cb42c72010-11-06 15:53:41 +00002106 LockSemaphoreInfo(cache_info->semaphore);
2107 if ((cache_info->reference_count > 1) ||
2108 (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002109 {
cristy0cb42c72010-11-06 15:53:41 +00002110 Image
2111 clone_image;
2112
2113 CacheInfo
2114 *clone_info;
2115
2116 /*
2117 Clone pixel cache.
2118 */
2119 clone_image=(*image);
2120 clone_image.semaphore=AllocateSemaphoreInfo();
2121 clone_image.reference_count=1;
2122 clone_image.cache=ClonePixelCache(cache_info);
2123 clone_info=(CacheInfo *) clone_image.cache;
2124 status=OpenPixelCache(&clone_image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00002125 if (status != MagickFalse)
2126 {
cristy0cb42c72010-11-06 15:53:41 +00002127 if (clone != MagickFalse)
2128 status=ClonePixelCachePixels(clone_info,cache_info,
2129 exception);
2130 if (status != MagickFalse)
2131 {
2132 destroy=MagickTrue;
2133 image->cache=clone_image.cache;
2134 }
cristy3ed852e2009-09-05 21:47:34 +00002135 }
cristy0cb42c72010-11-06 15:53:41 +00002136 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002137 }
cristy0cb42c72010-11-06 15:53:41 +00002138 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002139 }
2140 }
cristy4320e0e2009-09-10 15:00:08 +00002141 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002142 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002143 if (status != MagickFalse)
2144 {
2145 /*
2146 Ensure the image matches the pixel cache morphology.
2147 */
2148 image->taint=MagickTrue;
2149 image->type=UndefinedType;
cristydd438462010-05-06 13:44:04 +00002150 if (image->colorspace == GRAYColorspace)
2151 image->colorspace=RGBColorspace;
cristy3ed852e2009-09-05 21:47:34 +00002152 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2153 status=OpenPixelCache(image,IOMode,exception);
2154 }
cristyf84a1932010-01-03 18:00:18 +00002155 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002156 if (status == MagickFalse)
2157 return((Cache) NULL);
2158 return(image->cache);
2159}
2160
2161/*
2162%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2163% %
2164% %
2165% %
2166% G e t O n e A u t h e n t i c P i x e l %
2167% %
2168% %
2169% %
2170%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2171%
2172% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2173% location. The image background color is returned if an error occurs.
2174%
2175% The format of the GetOneAuthenticPixel() method is:
2176%
cristybb503372010-05-27 20:51:26 +00002177% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2178% const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002179%
2180% A description of each parameter follows:
2181%
2182% o image: the image.
2183%
2184% o x,y: These values define the location of the pixel to return.
2185%
2186% o pixel: return a pixel at the specified (x,y) location.
2187%
2188% o exception: return any errors or warnings in this structure.
2189%
2190*/
cristyacbbb7c2010-06-30 18:56:48 +00002191MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2192 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002193{
2194 CacheInfo
2195 *cache_info;
2196
cristy2036f5c2010-09-19 21:18:17 +00002197 PixelPacket
2198 *pixels;
2199
cristy3ed852e2009-09-05 21:47:34 +00002200 assert(image != (Image *) NULL);
2201 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002202 assert(image->cache != (Cache) NULL);
2203 cache_info=(CacheInfo *) image->cache;
2204 assert(cache_info->signature == MagickSignature);
2205 *pixel=image->background_color;
cristyd317f372010-09-18 01:42:20 +00002206 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2207 (GetOneAuthenticPixelFromHandler) NULL)
2208 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2209 pixel,exception));
cristy2036f5c2010-09-19 21:18:17 +00002210 *pixel=image->background_color;
2211 pixels=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2212 if (pixels == (PixelPacket *) NULL)
2213 return(MagickFalse);
2214 *pixel=(*pixels);
2215 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002216}
2217
2218/*
2219%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2220% %
2221% %
2222% %
2223+ 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 %
2224% %
2225% %
2226% %
2227%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2228%
2229% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2230% location. The image background color is returned if an error occurs.
2231%
2232% The format of the GetOneAuthenticPixelFromCache() method is:
2233%
2234% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy5f959472010-05-27 22:19:46 +00002235% const ssize_t x,const ssize_t y,PixelPacket *pixel,
2236% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002237%
2238% A description of each parameter follows:
2239%
2240% o image: the image.
2241%
2242% o x,y: These values define the location of the pixel to return.
2243%
2244% o pixel: return a pixel at the specified (x,y) location.
2245%
2246% o exception: return any errors or warnings in this structure.
2247%
2248*/
2249static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristybb503372010-05-27 20:51:26 +00002250 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002251{
cristy098f78c2010-09-23 17:28:44 +00002252 CacheInfo
2253 *cache_info;
2254
2255 const int
2256 id = GetOpenMPThreadId();
2257
cristy3ed852e2009-09-05 21:47:34 +00002258 PixelPacket
2259 *pixels;
2260
cristy0158a4b2010-09-20 13:59:45 +00002261 assert(image != (const Image *) NULL);
2262 assert(image->signature == MagickSignature);
2263 assert(image->cache != (Cache) NULL);
cristy098f78c2010-09-23 17:28:44 +00002264 cache_info=(CacheInfo *) image->cache;
2265 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002266 *pixel=image->background_color;
cristy098f78c2010-09-23 17:28:44 +00002267 assert(id < (int) cache_info->number_threads);
2268 pixels=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,
2269 cache_info->nexus_info[id],exception);
cristy3ed852e2009-09-05 21:47:34 +00002270 if (pixels == (PixelPacket *) NULL)
2271 return(MagickFalse);
2272 *pixel=(*pixels);
2273 return(MagickTrue);
2274}
2275
2276/*
2277%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2278% %
2279% %
2280% %
2281% G e t O n e V i r t u a l M a g i c k P i x e l %
2282% %
2283% %
2284% %
2285%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2286%
2287% GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2288% location. The image background color is returned if an error occurs. If
2289% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2290%
2291% The format of the GetOneVirtualMagickPixel() method is:
2292%
2293% MagickBooleanType GetOneVirtualMagickPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002294% const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
cristy3ed852e2009-09-05 21:47:34 +00002295% ExceptionInfo exception)
2296%
2297% A description of each parameter follows:
2298%
2299% o image: the image.
2300%
2301% o x,y: these values define the location of the pixel to return.
2302%
2303% o pixel: return a pixel at the specified (x,y) location.
2304%
2305% o exception: return any errors or warnings in this structure.
2306%
2307*/
2308MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
cristyacbbb7c2010-06-30 18:56:48 +00002309 const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
2310 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002311{
2312 CacheInfo
2313 *cache_info;
2314
cristy0158a4b2010-09-20 13:59:45 +00002315 const int
2316 id = GetOpenMPThreadId();
2317
cristy3ed852e2009-09-05 21:47:34 +00002318 register const IndexPacket
2319 *indexes;
2320
2321 register const PixelPacket
cristy0158a4b2010-09-20 13:59:45 +00002322 *pixels;
cristy3ed852e2009-09-05 21:47:34 +00002323
2324 assert(image != (const Image *) NULL);
2325 assert(image->signature == MagickSignature);
2326 assert(image->cache != (Cache) NULL);
2327 cache_info=(CacheInfo *) image->cache;
2328 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002329 assert(id < (int) cache_info->number_threads);
2330 pixels=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2331 1UL,1UL,cache_info->nexus_info[id],exception);
cristye7cc7cf2010-09-21 13:26:47 +00002332 GetMagickPixelPacket(image,pixel);
cristy0158a4b2010-09-20 13:59:45 +00002333 if (pixels == (const PixelPacket *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002334 return(MagickFalse);
cristy098f78c2010-09-23 17:28:44 +00002335 indexes=GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[id]);
cristy0158a4b2010-09-20 13:59:45 +00002336 SetMagickPixelPacket(image,pixels,indexes,pixel);
cristy3ed852e2009-09-05 21:47:34 +00002337 return(MagickTrue);
2338}
2339
2340/*
2341%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2342% %
2343% %
2344% %
2345% G e t O n e V i r t u a l M e t h o d P i x e l %
2346% %
2347% %
2348% %
2349%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2350%
2351% GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2352% location as defined by specified pixel method. The image background color
2353% is returned if an error occurs. If you plan to modify the pixel, use
2354% GetOneAuthenticPixel() instead.
2355%
2356% The format of the GetOneVirtualMethodPixel() method is:
2357%
2358% MagickBooleanType GetOneVirtualMethodPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002359% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2360% const ssize_t y,Pixelpacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002361%
2362% A description of each parameter follows:
2363%
2364% o image: the image.
2365%
2366% o virtual_pixel_method: the virtual pixel method.
2367%
2368% o x,y: These values define the location of the pixel to return.
2369%
2370% o pixel: return a pixel at the specified (x,y) location.
2371%
2372% o exception: return any errors or warnings in this structure.
2373%
2374*/
2375MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002376 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002377 PixelPacket *pixel,ExceptionInfo *exception)
2378{
cristy3ed852e2009-09-05 21:47:34 +00002379 CacheInfo
2380 *cache_info;
2381
cristy0158a4b2010-09-20 13:59:45 +00002382 const int
2383 id = GetOpenMPThreadId();
2384
cristy2036f5c2010-09-19 21:18:17 +00002385 const PixelPacket
2386 *pixels;
2387
cristy3ed852e2009-09-05 21:47:34 +00002388 assert(image != (const Image *) NULL);
2389 assert(image->signature == MagickSignature);
2390 assert(image->cache != (Cache) NULL);
2391 cache_info=(CacheInfo *) image->cache;
2392 assert(cache_info->signature == MagickSignature);
2393 *pixel=image->background_color;
cristyd317f372010-09-18 01:42:20 +00002394 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2395 (GetOneVirtualPixelFromHandler) NULL)
2396 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2397 virtual_pixel_method,x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002398 assert(id < (int) cache_info->number_threads);
2399 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2400 cache_info->nexus_info[id],exception);
cristy2036f5c2010-09-19 21:18:17 +00002401 if (pixels == (const PixelPacket *) NULL)
2402 return(MagickFalse);
2403 *pixel=(*pixels);
2404 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002405}
2406
2407/*
2408%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2409% %
2410% %
2411% %
2412% G e t O n e V i r t u a l P i x e l %
2413% %
2414% %
2415% %
2416%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2417%
2418% GetOneVirtualPixel() returns a single virtual pixel at the specified
2419% (x,y) location. The image background color is returned if an error occurs.
2420% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2421%
2422% The format of the GetOneVirtualPixel() method is:
2423%
cristybb503372010-05-27 20:51:26 +00002424% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2425% const ssize_t y,PixelPacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002426%
2427% A description of each parameter follows:
2428%
2429% o image: the image.
2430%
2431% o x,y: These values define the location of the pixel to return.
2432%
2433% o pixel: return a pixel at the specified (x,y) location.
2434%
2435% o exception: return any errors or warnings in this structure.
2436%
2437*/
2438MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002439 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002440{
cristy3ed852e2009-09-05 21:47:34 +00002441 CacheInfo
2442 *cache_info;
2443
cristy0158a4b2010-09-20 13:59:45 +00002444 const int
2445 id = GetOpenMPThreadId();
2446
cristy2036f5c2010-09-19 21:18:17 +00002447 const PixelPacket
2448 *pixels;
2449
cristy3ed852e2009-09-05 21:47:34 +00002450 assert(image != (const Image *) NULL);
2451 assert(image->signature == MagickSignature);
2452 assert(image->cache != (Cache) NULL);
2453 cache_info=(CacheInfo *) image->cache;
2454 assert(cache_info->signature == MagickSignature);
2455 *pixel=image->background_color;
cristyd317f372010-09-18 01:42:20 +00002456 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2457 (GetOneVirtualPixelFromHandler) NULL)
2458 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2459 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002460 assert(id < (int) cache_info->number_threads);
2461 pixels=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2462 1UL,1UL,cache_info->nexus_info[id],exception);
cristy2036f5c2010-09-19 21:18:17 +00002463 if (pixels == (const PixelPacket *) NULL)
2464 return(MagickFalse);
2465 *pixel=(*pixels);
2466 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002467}
2468
2469/*
2470%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2471% %
2472% %
2473% %
2474+ 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 %
2475% %
2476% %
2477% %
2478%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2479%
2480% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2481% specified (x,y) location. The image background color is returned if an
2482% error occurs.
2483%
2484% The format of the GetOneVirtualPixelFromCache() method is:
2485%
2486% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristybb503372010-05-27 20:51:26 +00002487% const VirtualPixelPacket method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002488% PixelPacket *pixel,ExceptionInfo *exception)
2489%
2490% A description of each parameter follows:
2491%
2492% o image: the image.
2493%
2494% o virtual_pixel_method: the virtual pixel method.
2495%
2496% o x,y: These values define the location of the pixel to return.
2497%
2498% o pixel: return a pixel at the specified (x,y) location.
2499%
2500% o exception: return any errors or warnings in this structure.
2501%
2502*/
2503static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002504 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002505 PixelPacket *pixel,ExceptionInfo *exception)
2506{
cristy0158a4b2010-09-20 13:59:45 +00002507 CacheInfo
2508 *cache_info;
2509
2510 const int
2511 id = GetOpenMPThreadId();
2512
cristy3ed852e2009-09-05 21:47:34 +00002513 const PixelPacket
2514 *pixels;
2515
cristye7cc7cf2010-09-21 13:26:47 +00002516 assert(image != (const Image *) NULL);
2517 assert(image->signature == MagickSignature);
2518 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002519 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002520 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002521 assert(id < (int) cache_info->number_threads);
cristye7cc7cf2010-09-21 13:26:47 +00002522 *pixel=image->background_color;
cristy0158a4b2010-09-20 13:59:45 +00002523 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2524 cache_info->nexus_info[id],exception);
cristy3ed852e2009-09-05 21:47:34 +00002525 if (pixels == (const PixelPacket *) NULL)
2526 return(MagickFalse);
2527 *pixel=(*pixels);
2528 return(MagickTrue);
2529}
2530
2531/*
2532%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2533% %
2534% %
2535% %
2536+ G e t P i x e l C a c h e C o l o r s p a c e %
2537% %
2538% %
2539% %
2540%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2541%
2542% GetPixelCacheColorspace() returns the class type of the pixel cache.
2543%
2544% The format of the GetPixelCacheColorspace() method is:
2545%
2546% Colorspace GetPixelCacheColorspace(Cache cache)
2547%
2548% A description of each parameter follows:
2549%
2550% o cache: the pixel cache.
2551%
2552*/
2553MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
2554{
2555 CacheInfo
2556 *cache_info;
2557
2558 assert(cache != (Cache) NULL);
2559 cache_info=(CacheInfo *) cache;
2560 assert(cache_info->signature == MagickSignature);
2561 if (cache_info->debug != MagickFalse)
2562 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2563 cache_info->filename);
2564 return(cache_info->colorspace);
2565}
2566
2567/*
2568%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2569% %
2570% %
2571% %
2572+ G e t P i x e l C a c h e M e t h o d s %
2573% %
2574% %
2575% %
2576%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2577%
2578% GetPixelCacheMethods() initializes the CacheMethods structure.
2579%
2580% The format of the GetPixelCacheMethods() method is:
2581%
2582% void GetPixelCacheMethods(CacheMethods *cache_methods)
2583%
2584% A description of each parameter follows:
2585%
2586% o cache_methods: Specifies a pointer to a CacheMethods structure.
2587%
2588*/
2589MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
2590{
2591 assert(cache_methods != (CacheMethods *) NULL);
2592 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2593 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2594 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2595 cache_methods->get_virtual_indexes_from_handler=GetVirtualIndexesFromCache;
2596 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2597 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2598 cache_methods->get_authentic_indexes_from_handler=
2599 GetAuthenticIndexesFromCache;
2600 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2601 cache_methods->get_one_authentic_pixel_from_handler=
2602 GetOneAuthenticPixelFromCache;
2603 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2604 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2605 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2606}
2607
2608/*
2609%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2610% %
2611% %
2612% %
2613+ G e t P i x e l C a c h e N e x u s E x t e n t %
2614% %
2615% %
2616% %
2617%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2618%
2619% GetPixelCacheNexusExtent() returns the extent of the pixels associated with
2620% the last call to SetPixelCacheNexusPixels() or GetPixelCacheNexusPixels().
2621%
2622% The format of the GetPixelCacheNexusExtent() method is:
2623%
2624% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2625% NexusInfo *nexus_info)
2626%
2627% A description of each parameter follows:
2628%
2629% o nexus_info: the nexus info.
2630%
2631*/
2632MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2633 NexusInfo *nexus_info)
2634{
2635 CacheInfo
2636 *cache_info;
2637
2638 MagickSizeType
2639 extent;
2640
cristye7cc7cf2010-09-21 13:26:47 +00002641 assert(cache != (const Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002642 cache_info=(CacheInfo *) cache;
2643 assert(cache_info->signature == MagickSignature);
2644 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2645 if (extent == 0)
2646 return((MagickSizeType) cache_info->columns*cache_info->rows);
2647 return(extent);
2648}
2649
2650/*
2651%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2652% %
2653% %
2654% %
2655+ 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 %
2656% %
2657% %
2658% %
2659%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2660%
2661% GetPixelCacheNexusIndexes() returns the indexes associated with the
2662% specified cache nexus.
2663%
2664% The format of the GetPixelCacheNexusIndexes() method is:
2665%
2666% IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2667% NexusInfo *nexus_info)
2668%
2669% A description of each parameter follows:
2670%
2671% o cache: the pixel cache.
2672%
2673% o nexus_info: the cache nexus to return the colormap indexes.
2674%
2675*/
2676MagickExport IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2677 NexusInfo *nexus_info)
2678{
2679 CacheInfo
2680 *cache_info;
2681
cristye7cc7cf2010-09-21 13:26:47 +00002682 assert(cache != (const Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002683 cache_info=(CacheInfo *) cache;
2684 assert(cache_info->signature == MagickSignature);
2685 if (cache_info->storage_class == UndefinedClass)
2686 return((IndexPacket *) NULL);
2687 return(nexus_info->indexes);
2688}
2689
2690/*
2691%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2692% %
2693% %
2694% %
2695+ G e t P i x e l C a c h e N e x u s P i x e l s %
2696% %
2697% %
2698% %
2699%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2700%
2701% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2702% cache nexus.
2703%
2704% The format of the GetPixelCacheNexusPixels() method is:
2705%
2706% PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2707% NexusInfo *nexus_info)
2708%
2709% A description of each parameter follows:
2710%
2711% o cache: the pixel cache.
2712%
2713% o nexus_info: the cache nexus to return the pixels.
2714%
2715*/
2716MagickExport PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2717 NexusInfo *nexus_info)
2718{
2719 CacheInfo
2720 *cache_info;
2721
cristye7cc7cf2010-09-21 13:26:47 +00002722 assert(cache != (const Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002723 cache_info=(CacheInfo *) cache;
2724 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002725 if (cache_info->storage_class == UndefinedClass)
2726 return((PixelPacket *) NULL);
2727 return(nexus_info->pixels);
2728}
2729
2730/*
2731%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2732% %
2733% %
2734% %
cristy056ba772010-01-02 23:33:54 +00002735+ G e t P i x e l C a c h e P i x e l s %
2736% %
2737% %
2738% %
2739%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2740%
2741% GetPixelCachePixels() returns the pixels associated with the specified image.
2742%
2743% The format of the GetPixelCachePixels() method is:
2744%
cristyf84a1932010-01-03 18:00:18 +00002745% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2746% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002747%
2748% A description of each parameter follows:
2749%
2750% o image: the image.
2751%
2752% o length: the pixel cache length.
2753%
cristyf84a1932010-01-03 18:00:18 +00002754% o exception: return any errors or warnings in this structure.
2755%
cristy056ba772010-01-02 23:33:54 +00002756*/
cristyf84a1932010-01-03 18:00:18 +00002757MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2758 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002759{
2760 CacheInfo
2761 *cache_info;
2762
2763 assert(image != (const Image *) NULL);
2764 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002765 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00002766 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002767 assert(cache_info->signature == MagickSignature);
2768 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002769 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002770 return((void *) NULL);
2771 *length=cache_info->length;
2772 return((void *) cache_info->pixels);
2773}
2774
2775/*
2776%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2777% %
2778% %
2779% %
cristyb32b90a2009-09-07 21:45:48 +00002780+ 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 +00002781% %
2782% %
2783% %
2784%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2785%
2786% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2787%
2788% The format of the GetPixelCacheStorageClass() method is:
2789%
2790% ClassType GetPixelCacheStorageClass(Cache cache)
2791%
2792% A description of each parameter follows:
2793%
2794% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2795%
2796% o cache: the pixel cache.
2797%
2798*/
2799MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
2800{
2801 CacheInfo
2802 *cache_info;
2803
2804 assert(cache != (Cache) NULL);
2805 cache_info=(CacheInfo *) cache;
2806 assert(cache_info->signature == MagickSignature);
2807 if (cache_info->debug != MagickFalse)
2808 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2809 cache_info->filename);
2810 return(cache_info->storage_class);
2811}
2812
2813/*
2814%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2815% %
2816% %
2817% %
cristyb32b90a2009-09-07 21:45:48 +00002818+ G e t P i x e l C a c h e T i l e S i z e %
2819% %
2820% %
2821% %
2822%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2823%
2824% GetPixelCacheTileSize() returns the pixel cache tile size.
2825%
2826% The format of the GetPixelCacheTileSize() method is:
2827%
cristybb503372010-05-27 20:51:26 +00002828% void GetPixelCacheTileSize(const Image *image,size_t *width,
2829% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002830%
2831% A description of each parameter follows:
2832%
2833% o image: the image.
2834%
2835% o width: the optimize cache tile width in pixels.
2836%
2837% o height: the optimize cache tile height in pixels.
2838%
2839*/
cristybb503372010-05-27 20:51:26 +00002840MagickExport void GetPixelCacheTileSize(const Image *image,size_t *width,
2841 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002842{
cristyb32b90a2009-09-07 21:45:48 +00002843 assert(image != (Image *) NULL);
2844 assert(image->signature == MagickSignature);
2845 if (image->debug != MagickFalse)
2846 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristyb32b90a2009-09-07 21:45:48 +00002847 *width=2048UL/sizeof(PixelPacket);
2848 if (GetPixelCacheType(image) == DiskCache)
cristydaa97692009-09-13 02:10:35 +00002849 *width=8192UL/sizeof(PixelPacket);
cristyb32b90a2009-09-07 21:45:48 +00002850 *height=(*width);
2851}
2852
2853/*
2854%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2855% %
2856% %
2857% %
2858+ G e t P i x e l C a c h e T y p e %
2859% %
2860% %
2861% %
2862%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2863%
2864% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2865%
2866% The format of the GetPixelCacheType() method is:
2867%
2868% CacheType GetPixelCacheType(const Image *image)
2869%
2870% A description of each parameter follows:
2871%
2872% o image: the image.
2873%
2874*/
2875MagickExport CacheType GetPixelCacheType(const Image *image)
2876{
2877 CacheInfo
2878 *cache_info;
2879
2880 assert(image != (Image *) NULL);
2881 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002882 assert(image->cache != (Cache) NULL);
2883 cache_info=(CacheInfo *) image->cache;
2884 assert(cache_info->signature == MagickSignature);
2885 return(cache_info->type);
2886}
2887
2888/*
2889%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2890% %
2891% %
2892% %
cristy3ed852e2009-09-05 21:47:34 +00002893+ 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 %
2894% %
2895% %
2896% %
2897%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2898%
2899% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2900% pixel cache. A virtual pixel is any pixel access that is outside the
2901% boundaries of the image cache.
2902%
2903% The format of the GetPixelCacheVirtualMethod() method is:
2904%
2905% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2906%
2907% A description of each parameter follows:
2908%
2909% o image: the image.
2910%
2911*/
2912MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2913{
2914 CacheInfo
2915 *cache_info;
2916
2917 assert(image != (Image *) NULL);
2918 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002919 assert(image->cache != (Cache) NULL);
2920 cache_info=(CacheInfo *) image->cache;
2921 assert(cache_info->signature == MagickSignature);
2922 return(cache_info->virtual_pixel_method);
2923}
2924
2925/*
2926%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2927% %
2928% %
2929% %
2930+ 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 %
2931% %
2932% %
2933% %
2934%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2935%
2936% GetVirtualIndexesFromCache() returns the indexes associated with the last
2937% call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2938%
2939% The format of the GetVirtualIndexesFromCache() method is:
2940%
2941% IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2942%
2943% A description of each parameter follows:
2944%
2945% o image: the image.
2946%
2947*/
2948static const IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2949{
2950 CacheInfo
2951 *cache_info;
2952
cristy5c9e6f22010-09-17 17:31:01 +00002953 const int
2954 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002955
cristye7cc7cf2010-09-21 13:26:47 +00002956 assert(image != (const Image *) NULL);
2957 assert(image->signature == MagickSignature);
2958 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002959 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002960 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002961 assert(id < (int) cache_info->number_threads);
cristye7cc7cf2010-09-21 13:26:47 +00002962 return(GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00002963}
2964
2965/*
2966%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2967% %
2968% %
2969% %
2970+ 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 %
2971% %
2972% %
2973% %
2974%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2975%
2976% GetVirtualIndexesFromNexus() returns the indexes associated with the
2977% specified cache nexus.
2978%
2979% The format of the GetVirtualIndexesFromNexus() method is:
2980%
2981% const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2982% NexusInfo *nexus_info)
2983%
2984% A description of each parameter follows:
2985%
2986% o cache: the pixel cache.
2987%
2988% o nexus_info: the cache nexus to return the colormap indexes.
2989%
2990*/
2991MagickExport const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2992 NexusInfo *nexus_info)
2993{
2994 CacheInfo
2995 *cache_info;
2996
cristye7cc7cf2010-09-21 13:26:47 +00002997 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002998 cache_info=(CacheInfo *) cache;
2999 assert(cache_info->signature == MagickSignature);
3000 if (cache_info->storage_class == UndefinedClass)
3001 return((IndexPacket *) NULL);
3002 return(nexus_info->indexes);
3003}
3004
3005/*
3006%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3007% %
3008% %
3009% %
3010% G e t V i r t u a l I n d e x Q u e u e %
3011% %
3012% %
3013% %
3014%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3015%
3016% GetVirtualIndexQueue() returns the virtual black channel or the
3017% colormap indexes associated with the last call to QueueAuthenticPixels() or
3018% GetVirtualPixels(). NULL is returned if the black channel or colormap
3019% indexes are not available.
3020%
3021% The format of the GetVirtualIndexQueue() method is:
3022%
3023% const IndexPacket *GetVirtualIndexQueue(const Image *image)
3024%
3025% A description of each parameter follows:
3026%
3027% o image: the image.
3028%
3029*/
3030MagickExport const IndexPacket *GetVirtualIndexQueue(const Image *image)
3031{
3032 CacheInfo
3033 *cache_info;
3034
cristy2036f5c2010-09-19 21:18:17 +00003035 const int
3036 id = GetOpenMPThreadId();
3037
cristy3ed852e2009-09-05 21:47:34 +00003038 assert(image != (const Image *) NULL);
3039 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003040 assert(image->cache != (Cache) NULL);
3041 cache_info=(CacheInfo *) image->cache;
3042 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003043 if (cache_info->methods.get_virtual_indexes_from_handler !=
3044 (GetVirtualIndexesFromHandler) NULL)
3045 return(cache_info->methods.get_virtual_indexes_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003046 assert(id < (int) cache_info->number_threads);
3047 return(GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003048}
3049
3050/*
3051%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3052% %
3053% %
3054% %
3055+ 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 %
3056% %
3057% %
3058% %
3059%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3060%
3061% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3062% pixel cache as defined by the geometry parameters. A pointer to the pixels
3063% is returned if the pixels are transferred, otherwise a NULL is returned.
3064%
3065% The format of the GetVirtualPixelsFromNexus() method is:
3066%
3067% PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003068% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00003069% const size_t columns,const size_t rows,NexusInfo *nexus_info,
3070% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003071%
3072% A description of each parameter follows:
3073%
3074% o image: the image.
3075%
3076% o virtual_pixel_method: the virtual pixel method.
3077%
3078% o x,y,columns,rows: These values define the perimeter of a region of
3079% pixels.
3080%
3081% o nexus_info: the cache nexus to acquire.
3082%
3083% o exception: return any errors or warnings in this structure.
3084%
3085*/
3086
cristybb503372010-05-27 20:51:26 +00003087static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003088 DitherMatrix[64] =
3089 {
3090 0, 48, 12, 60, 3, 51, 15, 63,
3091 32, 16, 44, 28, 35, 19, 47, 31,
3092 8, 56, 4, 52, 11, 59, 7, 55,
3093 40, 24, 36, 20, 43, 27, 39, 23,
3094 2, 50, 14, 62, 1, 49, 13, 61,
3095 34, 18, 46, 30, 33, 17, 45, 29,
3096 10, 58, 6, 54, 9, 57, 5, 53,
3097 42, 26, 38, 22, 41, 25, 37, 21
3098 };
3099
cristybb503372010-05-27 20:51:26 +00003100static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003101{
cristybb503372010-05-27 20:51:26 +00003102 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003103 index;
3104
3105 index=x+DitherMatrix[x & 0x07]-32L;
3106 if (index < 0L)
3107 return(0L);
cristybb503372010-05-27 20:51:26 +00003108 if (index >= (ssize_t) columns)
3109 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00003110 return(index);
3111}
3112
cristybb503372010-05-27 20:51:26 +00003113static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003114{
cristybb503372010-05-27 20:51:26 +00003115 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003116 index;
3117
3118 index=y+DitherMatrix[y & 0x07]-32L;
3119 if (index < 0L)
3120 return(0L);
cristybb503372010-05-27 20:51:26 +00003121 if (index >= (ssize_t) rows)
3122 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00003123 return(index);
3124}
3125
cristybb503372010-05-27 20:51:26 +00003126static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003127{
3128 if (x < 0L)
3129 return(0L);
cristybb503372010-05-27 20:51:26 +00003130 if (x >= (ssize_t) columns)
3131 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003132 return(x);
3133}
3134
cristybb503372010-05-27 20:51:26 +00003135static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003136{
3137 if (y < 0L)
3138 return(0L);
cristybb503372010-05-27 20:51:26 +00003139 if (y >= (ssize_t) rows)
3140 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003141 return(y);
3142}
3143
cristybb503372010-05-27 20:51:26 +00003144static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003145{
cristybb503372010-05-27 20:51:26 +00003146 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003147}
3148
cristybb503372010-05-27 20:51:26 +00003149static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003150{
cristybb503372010-05-27 20:51:26 +00003151 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003152}
3153
3154/*
3155 VirtualPixelModulo() computes the remainder of dividing offset by extent. It
3156 returns not only the quotient (tile the offset falls in) but also the positive
3157 remainer within that tile such that 0 <= remainder < extent. This method is
3158 essentially a ldiv() using a floored modulo division rather than the normal
3159 default truncated modulo division.
3160*/
cristybb503372010-05-27 20:51:26 +00003161static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3162 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003163{
3164 MagickModulo
3165 modulo;
3166
cristybb503372010-05-27 20:51:26 +00003167 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003168 if (offset < 0L)
3169 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003170 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003171 return(modulo);
3172}
3173
3174MagickExport const PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003175 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3176 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003177 ExceptionInfo *exception)
3178{
3179 CacheInfo
3180 *cache_info;
3181
cristyc3ec0d42010-04-07 01:18:08 +00003182 IndexPacket
3183 virtual_index;
3184
cristy3ed852e2009-09-05 21:47:34 +00003185 MagickOffsetType
3186 offset;
3187
3188 MagickSizeType
3189 length,
3190 number_pixels;
3191
3192 NexusInfo
3193 **virtual_nexus;
3194
3195 PixelPacket
3196 *pixels,
3197 virtual_pixel;
3198
3199 RectangleInfo
3200 region;
3201
3202 register const IndexPacket
cristyc3ec0d42010-04-07 01:18:08 +00003203 *restrict virtual_indexes;
cristy3ed852e2009-09-05 21:47:34 +00003204
3205 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003206 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003207
3208 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003209 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003210
cristye076a6e2010-08-15 19:59:43 +00003211 register PixelPacket
3212 *restrict q;
3213
cristybb503372010-05-27 20:51:26 +00003214 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003215 u,
3216 v;
3217
cristy3ed852e2009-09-05 21:47:34 +00003218 /*
3219 Acquire pixels.
3220 */
cristye7cc7cf2010-09-21 13:26:47 +00003221 assert(image != (const Image *) NULL);
3222 assert(image->signature == MagickSignature);
3223 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003224 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003225 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003226 if (cache_info->type == UndefinedCache)
cristy3ed852e2009-09-05 21:47:34 +00003227 return((const PixelPacket *) NULL);
3228 region.x=x;
3229 region.y=y;
3230 region.width=columns;
3231 region.height=rows;
3232 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
3233 if (pixels == (PixelPacket *) NULL)
3234 return((const PixelPacket *) NULL);
cristydf415c82010-03-11 16:47:50 +00003235 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3236 nexus_info->region.x;
3237 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3238 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003239 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3240 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003241 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3242 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003243 {
3244 MagickBooleanType
3245 status;
3246
3247 /*
3248 Pixel request is inside cache extents.
3249 */
3250 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
3251 return(pixels);
3252 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3253 if (status == MagickFalse)
3254 return((const PixelPacket *) NULL);
3255 if ((cache_info->storage_class == PseudoClass) ||
3256 (cache_info->colorspace == CMYKColorspace))
3257 {
3258 status=ReadPixelCacheIndexes(cache_info,nexus_info,exception);
3259 if (status == MagickFalse)
3260 return((const PixelPacket *) NULL);
3261 }
3262 return(pixels);
3263 }
3264 /*
3265 Pixel request is outside cache extents.
3266 */
3267 q=pixels;
3268 indexes=GetPixelCacheNexusIndexes(cache_info,nexus_info);
3269 virtual_nexus=AcquirePixelCacheNexus(1);
3270 if (virtual_nexus == (NexusInfo **) NULL)
3271 {
3272 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3273 "UnableToGetCacheNexus","`%s'",image->filename);
3274 return((const PixelPacket *) NULL);
3275 }
3276 switch (virtual_pixel_method)
3277 {
3278 case BlackVirtualPixelMethod:
3279 {
cristy4789f0d2010-01-10 00:01:06 +00003280 SetRedPixelComponent(&virtual_pixel,0);
3281 SetGreenPixelComponent(&virtual_pixel,0);
3282 SetBluePixelComponent(&virtual_pixel,0);
3283 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003284 break;
3285 }
3286 case GrayVirtualPixelMethod:
3287 {
cristy4789f0d2010-01-10 00:01:06 +00003288 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3289 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3290 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3291 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003292 break;
3293 }
3294 case TransparentVirtualPixelMethod:
3295 {
cristy4789f0d2010-01-10 00:01:06 +00003296 SetRedPixelComponent(&virtual_pixel,0);
3297 SetGreenPixelComponent(&virtual_pixel,0);
3298 SetBluePixelComponent(&virtual_pixel,0);
3299 SetOpacityPixelComponent(&virtual_pixel,TransparentOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003300 break;
3301 }
3302 case MaskVirtualPixelMethod:
3303 case WhiteVirtualPixelMethod:
3304 {
cristy4789f0d2010-01-10 00:01:06 +00003305 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3306 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3307 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3308 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003309 break;
3310 }
3311 default:
3312 {
3313 virtual_pixel=image->background_color;
3314 break;
3315 }
3316 }
cristyc3ec0d42010-04-07 01:18:08 +00003317 virtual_index=0;
cristybb503372010-05-27 20:51:26 +00003318 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003319 {
cristybb503372010-05-27 20:51:26 +00003320 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003321 {
3322 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003323 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003324 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3325 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003326 {
3327 MagickModulo
3328 x_modulo,
3329 y_modulo;
3330
3331 /*
3332 Transfer a single pixel.
3333 */
3334 length=(MagickSizeType) 1;
3335 switch (virtual_pixel_method)
3336 {
3337 case BackgroundVirtualPixelMethod:
3338 case ConstantVirtualPixelMethod:
3339 case BlackVirtualPixelMethod:
3340 case GrayVirtualPixelMethod:
3341 case TransparentVirtualPixelMethod:
3342 case MaskVirtualPixelMethod:
3343 case WhiteVirtualPixelMethod:
3344 {
3345 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003346 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003347 break;
3348 }
3349 case EdgeVirtualPixelMethod:
3350 default:
3351 {
3352 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003353 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003354 1UL,1UL,*virtual_nexus,exception);
cristyc3ec0d42010-04-07 01:18:08 +00003355 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003356 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003357 break;
3358 }
3359 case RandomVirtualPixelMethod:
3360 {
3361 if (cache_info->random_info == (RandomInfo *) NULL)
3362 cache_info->random_info=AcquireRandomInfo();
3363 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003364 RandomX(cache_info->random_info,cache_info->columns),
3365 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003366 *virtual_nexus,exception);
cristyc3ec0d42010-04-07 01:18:08 +00003367 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003368 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003369 break;
3370 }
3371 case DitherVirtualPixelMethod:
3372 {
3373 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003374 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003375 1UL,1UL,*virtual_nexus,exception);
cristyc3ec0d42010-04-07 01:18:08 +00003376 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003377 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003378 break;
3379 }
3380 case TileVirtualPixelMethod:
3381 {
3382 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3383 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3384 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003385 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003386 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003387 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003388 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003389 break;
3390 }
3391 case MirrorVirtualPixelMethod:
3392 {
3393 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3394 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003395 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003396 x_modulo.remainder-1L;
3397 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3398 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003399 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003400 y_modulo.remainder-1L;
3401 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003402 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003403 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003404 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003405 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003406 break;
3407 }
3408 case CheckerTileVirtualPixelMethod:
3409 {
3410 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3411 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3412 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3413 {
3414 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003415 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003416 break;
3417 }
3418 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003419 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003420 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003421 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003422 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003423 break;
3424 }
3425 case HorizontalTileVirtualPixelMethod:
3426 {
cristybb503372010-05-27 20:51:26 +00003427 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003428 {
3429 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003430 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003431 break;
3432 }
3433 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3434 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3435 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003436 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003437 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003438 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003439 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003440 break;
3441 }
3442 case VerticalTileVirtualPixelMethod:
3443 {
cristybb503372010-05-27 20:51:26 +00003444 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
cristy3ed852e2009-09-05 21:47:34 +00003445 {
3446 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003447 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003448 break;
3449 }
3450 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3451 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3452 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003453 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003454 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003455 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003456 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003457 break;
3458 }
3459 case HorizontalTileEdgeVirtualPixelMethod:
3460 {
3461 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3462 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003463 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003464 *virtual_nexus,exception);
cristyc3ec0d42010-04-07 01:18:08 +00003465 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003466 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003467 break;
3468 }
3469 case VerticalTileEdgeVirtualPixelMethod:
3470 {
3471 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3472 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003473 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003474 *virtual_nexus,exception);
cristyc3ec0d42010-04-07 01:18:08 +00003475 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003476 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003477 break;
3478 }
3479 }
3480 if (p == (const PixelPacket *) NULL)
3481 break;
3482 *q++=(*p);
cristyc3ec0d42010-04-07 01:18:08 +00003483 if ((indexes != (IndexPacket *) NULL) &&
3484 (virtual_indexes != (const IndexPacket *) NULL))
3485 *indexes++=(*virtual_indexes);
cristy3ed852e2009-09-05 21:47:34 +00003486 continue;
3487 }
3488 /*
3489 Transfer a run of pixels.
3490 */
3491 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,
cristy0a36c742010-10-03 02:10:53 +00003492 (size_t) length,1UL,*virtual_nexus,exception);
cristy3ed852e2009-09-05 21:47:34 +00003493 if (p == (const PixelPacket *) NULL)
3494 break;
cristy0a36c742010-10-03 02:10:53 +00003495 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,*virtual_nexus);
cristy8f036fe2010-09-18 02:02:00 +00003496 (void) memcpy(q,p,(size_t) length*sizeof(*p));
cristy3ed852e2009-09-05 21:47:34 +00003497 q+=length;
cristyc3ec0d42010-04-07 01:18:08 +00003498 if ((indexes != (IndexPacket *) NULL) &&
3499 (virtual_indexes != (const IndexPacket *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003500 {
cristy8f036fe2010-09-18 02:02:00 +00003501 (void) memcpy(indexes,virtual_indexes,(size_t) length*
cristyc3ec0d42010-04-07 01:18:08 +00003502 sizeof(*virtual_indexes));
3503 indexes+=length;
cristy3ed852e2009-09-05 21:47:34 +00003504 }
3505 }
3506 }
3507 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3508 return(pixels);
3509}
3510
3511/*
3512%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3513% %
3514% %
3515% %
3516+ G e t V i r t u a l P i x e l C a c h e %
3517% %
3518% %
3519% %
3520%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3521%
3522% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3523% cache as defined by the geometry parameters. A pointer to the pixels
3524% is returned if the pixels are transferred, otherwise a NULL is returned.
3525%
3526% The format of the GetVirtualPixelCache() method is:
3527%
3528% const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003529% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3530% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003531% ExceptionInfo *exception)
3532%
3533% A description of each parameter follows:
3534%
3535% o image: the image.
3536%
3537% o virtual_pixel_method: the virtual pixel method.
3538%
3539% o x,y,columns,rows: These values define the perimeter of a region of
3540% pixels.
3541%
3542% o exception: return any errors or warnings in this structure.
3543%
3544*/
3545static const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003546 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3547 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003548{
3549 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003550 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003551
cristy5c9e6f22010-09-17 17:31:01 +00003552 const int
3553 id = GetOpenMPThreadId();
3554
cristye7cc7cf2010-09-21 13:26:47 +00003555 assert(image != (const Image *) NULL);
3556 assert(image->signature == MagickSignature);
3557 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003558 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003559 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003560 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003561 return(GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3562 cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00003563}
3564
3565/*
3566%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3567% %
3568% %
3569% %
3570% G e t V i r t u a l P i x e l Q u e u e %
3571% %
3572% %
3573% %
3574%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3575%
3576% GetVirtualPixelQueue() returns the virtual pixels associated with the
3577% last call to QueueAuthenticPixels() or GetVirtualPixels().
3578%
3579% The format of the GetVirtualPixelQueue() method is:
3580%
3581% const PixelPacket *GetVirtualPixelQueue(const Image image)
3582%
3583% A description of each parameter follows:
3584%
3585% o image: the image.
3586%
3587*/
3588MagickExport const PixelPacket *GetVirtualPixelQueue(const Image *image)
3589{
3590 CacheInfo
3591 *cache_info;
3592
cristy2036f5c2010-09-19 21:18:17 +00003593 const int
3594 id = GetOpenMPThreadId();
3595
cristy3ed852e2009-09-05 21:47:34 +00003596 assert(image != (const Image *) NULL);
3597 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003598 assert(image->cache != (Cache) NULL);
3599 cache_info=(CacheInfo *) image->cache;
3600 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003601 if (cache_info->methods.get_virtual_pixels_handler !=
3602 (GetVirtualPixelsHandler) NULL)
3603 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003604 assert(id < (int) cache_info->number_threads);
3605 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003606}
3607
3608/*
3609%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3610% %
3611% %
3612% %
3613% G e t V i r t u a l P i x e l s %
3614% %
3615% %
3616% %
3617%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3618%
3619% GetVirtualPixels() returns an immutable pixel region. If the
3620% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003621% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003622% copy of the pixels or it may point to the original pixels in memory.
3623% Performance is maximized if the selected region is part of one row, or one
3624% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003625% (without a copy) if the image is in memory, or in a memory-mapped file. The
3626% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003627%
3628% Pixels accessed via the returned pointer represent a simple array of type
3629% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
3630% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to access
3631% the black color component or to obtain the colormap indexes (of type
3632% IndexPacket) corresponding to the region.
3633%
3634% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3635%
3636% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3637% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3638% GetCacheViewAuthenticPixels() instead.
3639%
3640% The format of the GetVirtualPixels() method is:
3641%
cristybb503372010-05-27 20:51:26 +00003642% const PixelPacket *GetVirtualPixels(const Image *image,const ssize_t x,
3643% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003644% ExceptionInfo *exception)
3645%
3646% A description of each parameter follows:
3647%
3648% o image: the image.
3649%
3650% o x,y,columns,rows: These values define the perimeter of a region of
3651% pixels.
3652%
3653% o exception: return any errors or warnings in this structure.
3654%
3655*/
3656MagickExport const PixelPacket *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003657 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3658 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003659{
3660 CacheInfo
3661 *cache_info;
3662
cristy2036f5c2010-09-19 21:18:17 +00003663 const int
3664 id = GetOpenMPThreadId();
3665
cristy3ed852e2009-09-05 21:47:34 +00003666 assert(image != (const Image *) NULL);
3667 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003668 assert(image->cache != (Cache) NULL);
3669 cache_info=(CacheInfo *) image->cache;
3670 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003671 if (cache_info->methods.get_virtual_pixel_handler !=
3672 (GetVirtualPixelHandler) NULL)
3673 return(cache_info->methods.get_virtual_pixel_handler(image,
3674 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003675 assert(id < (int) cache_info->number_threads);
3676 return(GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3677 columns,rows,cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00003678}
3679
3680/*
3681%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3682% %
3683% %
3684% %
3685+ 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 %
3686% %
3687% %
3688% %
3689%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3690%
3691% GetVirtualPixelsCache() returns the pixels associated with the last call
3692% to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3693%
3694% The format of the GetVirtualPixelsCache() method is:
3695%
3696% PixelPacket *GetVirtualPixelsCache(const Image *image)
3697%
3698% A description of each parameter follows:
3699%
3700% o image: the image.
3701%
3702*/
3703static const PixelPacket *GetVirtualPixelsCache(const Image *image)
3704{
3705 CacheInfo
3706 *cache_info;
3707
cristy5c9e6f22010-09-17 17:31:01 +00003708 const int
3709 id = GetOpenMPThreadId();
3710
cristye7cc7cf2010-09-21 13:26:47 +00003711 assert(image != (const Image *) NULL);
3712 assert(image->signature == MagickSignature);
3713 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003714 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003715 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003716 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003717 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003718}
3719
3720/*
3721%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3722% %
3723% %
3724% %
3725+ G e t V i r t u a l P i x e l s N e x u s %
3726% %
3727% %
3728% %
3729%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3730%
3731% GetVirtualPixelsNexus() returns the pixels associated with the specified
3732% cache nexus.
3733%
3734% The format of the GetVirtualPixelsNexus() method is:
3735%
3736% const IndexPacket *GetVirtualPixelsNexus(const Cache cache,
3737% NexusInfo *nexus_info)
3738%
3739% A description of each parameter follows:
3740%
3741% o cache: the pixel cache.
3742%
3743% o nexus_info: the cache nexus to return the colormap pixels.
3744%
3745*/
3746MagickExport const PixelPacket *GetVirtualPixelsNexus(const Cache cache,
3747 NexusInfo *nexus_info)
3748{
3749 CacheInfo
3750 *cache_info;
3751
cristye7cc7cf2010-09-21 13:26:47 +00003752 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003753 cache_info=(CacheInfo *) cache;
3754 assert(cache_info->signature == MagickSignature);
3755 if (cache_info->storage_class == UndefinedClass)
3756 return((PixelPacket *) NULL);
3757 return((const PixelPacket *) nexus_info->pixels);
3758}
3759
3760/*
3761%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3762% %
3763% %
3764% %
3765+ M a s k P i x e l C a c h e N e x u s %
3766% %
3767% %
3768% %
3769%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3770%
3771% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3772% The method returns MagickTrue if the pixel region is masked, otherwise
3773% MagickFalse.
3774%
3775% The format of the MaskPixelCacheNexus() method is:
3776%
3777% MagickBooleanType MaskPixelCacheNexus(Image *image,
3778% NexusInfo *nexus_info,ExceptionInfo *exception)
3779%
3780% A description of each parameter follows:
3781%
3782% o image: the image.
3783%
3784% o nexus_info: the cache nexus to clip.
3785%
3786% o exception: return any errors or warnings in this structure.
3787%
3788*/
3789
3790static inline void MagickPixelCompositeMask(const MagickPixelPacket *p,
3791 const MagickRealType alpha,const MagickPixelPacket *q,
3792 const MagickRealType beta,MagickPixelPacket *composite)
3793{
3794 MagickRealType
3795 gamma;
3796
3797 if (alpha == TransparentOpacity)
3798 {
3799 *composite=(*q);
3800 return;
3801 }
3802 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3803 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3804 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3805 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3806 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3807 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3808 composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
3809}
3810
3811static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3812 ExceptionInfo *exception)
3813{
3814 CacheInfo
3815 *cache_info;
3816
3817 MagickPixelPacket
3818 alpha,
3819 beta;
3820
3821 MagickSizeType
3822 number_pixels;
3823
3824 NexusInfo
3825 **clip_nexus,
3826 **image_nexus;
3827
3828 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003829 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003830
3831 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003832 *restrict nexus_indexes,
3833 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003834
cristy3ed852e2009-09-05 21:47:34 +00003835 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003836 *restrict p,
3837 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003838
cristye076a6e2010-08-15 19:59:43 +00003839 register ssize_t
3840 i;
3841
cristy3ed852e2009-09-05 21:47:34 +00003842 /*
3843 Apply clip mask.
3844 */
3845 if (image->debug != MagickFalse)
3846 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3847 if (image->mask == (Image *) NULL)
3848 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +00003849 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00003850 if (cache_info == (Cache) NULL)
3851 return(MagickFalse);
3852 image_nexus=AcquirePixelCacheNexus(1);
3853 clip_nexus=AcquirePixelCacheNexus(1);
3854 if ((image_nexus == (NexusInfo **) NULL) ||
3855 (clip_nexus == (NexusInfo **) NULL))
3856 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy09449f72010-01-23 03:08:36 +00003857 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,
3858 nexus_info->region.y,nexus_info->region.width,nexus_info->region.height,
3859 image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003860 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
3861 q=nexus_info->pixels;
3862 nexus_indexes=nexus_info->indexes;
3863 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3864 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3865 nexus_info->region.height,clip_nexus[0],&image->exception);
3866 GetMagickPixelPacket(image,&alpha);
3867 GetMagickPixelPacket(image,&beta);
3868 number_pixels=(MagickSizeType) nexus_info->region.width*
3869 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +00003870 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +00003871 {
3872 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
3873 break;
3874 SetMagickPixelPacket(image,p,indexes+i,&alpha);
3875 SetMagickPixelPacket(image,q,nexus_indexes+i,&beta);
3876 MagickPixelCompositeMask(&beta,(MagickRealType) PixelIntensityToQuantum(r),
3877 &alpha,alpha.opacity,&beta);
cristyce70c172010-01-07 17:15:30 +00003878 q->red=ClampToQuantum(beta.red);
3879 q->green=ClampToQuantum(beta.green);
3880 q->blue=ClampToQuantum(beta.blue);
3881 q->opacity=ClampToQuantum(beta.opacity);
cristy3ed852e2009-09-05 21:47:34 +00003882 if (cache_info->active_index_channel != MagickFalse)
3883 nexus_indexes[i]=indexes[i];
3884 p++;
3885 q++;
3886 r++;
3887 }
3888 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3889 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +00003890 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003891 return(MagickFalse);
3892 return(MagickTrue);
3893}
3894
3895/*
3896%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3897% %
3898% %
3899% %
3900+ O p e n P i x e l C a c h e %
3901% %
3902% %
3903% %
3904%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3905%
3906% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3907% dimensions, allocating space for the image pixels and optionally the
3908% colormap indexes, and memory mapping the cache if it is disk based. The
3909% cache nexus array is initialized as well.
3910%
3911% The format of the OpenPixelCache() method is:
3912%
3913% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3914% ExceptionInfo *exception)
3915%
3916% A description of each parameter follows:
3917%
3918% o image: the image.
3919%
3920% o mode: ReadMode, WriteMode, or IOMode.
3921%
3922% o exception: return any errors or warnings in this structure.
3923%
3924*/
3925
cristyd43a46b2010-01-21 02:13:41 +00003926static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003927{
3928 cache_info->mapped=MagickFalse;
3929 cache_info->pixels=(PixelPacket *) AcquireMagickMemory((size_t)
3930 cache_info->length);
3931 if (cache_info->pixels == (PixelPacket *) NULL)
3932 {
3933 cache_info->mapped=MagickTrue;
3934 cache_info->pixels=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
3935 cache_info->length);
3936 }
3937}
3938
3939static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3940{
3941 CacheInfo
3942 *cache_info;
3943
3944 MagickOffsetType
3945 count,
3946 extent,
3947 offset;
3948
3949 cache_info=(CacheInfo *) image->cache;
3950 if (image->debug != MagickFalse)
3951 {
3952 char
3953 format[MaxTextExtent],
3954 message[MaxTextExtent];
3955
cristyb9080c92009-12-01 20:13:26 +00003956 (void) FormatMagickSize(length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00003957 (void) FormatMagickString(message,MaxTextExtent,
cristy2ce15c92010-03-12 14:03:41 +00003958 "extend %s (%s[%d], disk, %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003959 cache_info->cache_filename,cache_info->file,format);
3960 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3961 }
3962 if (length != (MagickSizeType) ((MagickOffsetType) length))
3963 return(MagickFalse);
3964 extent=(MagickOffsetType) MagickSeek(cache_info->file,0,SEEK_END);
3965 if (extent < 0)
3966 return(MagickFalse);
3967 if ((MagickSizeType) extent >= length)
3968 return(MagickTrue);
3969 offset=(MagickOffsetType) length-1;
3970 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3971 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3972}
3973
3974static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3975 ExceptionInfo *exception)
3976{
3977 char
3978 format[MaxTextExtent],
3979 message[MaxTextExtent];
3980
3981 CacheInfo
3982 *cache_info,
3983 source_info;
3984
3985 MagickSizeType
3986 length,
3987 number_pixels;
3988
3989 MagickStatusType
3990 status;
3991
3992 size_t
cristye076a6e2010-08-15 19:59:43 +00003993 columns,
cristy3ed852e2009-09-05 21:47:34 +00003994 packet_size;
3995
cristye7cc7cf2010-09-21 13:26:47 +00003996 assert(image != (const Image *) NULL);
3997 assert(image->signature == MagickSignature);
3998 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003999 if (image->debug != MagickFalse)
4000 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4001 if ((image->columns == 0) || (image->rows == 0))
4002 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
4003 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004004 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004005 source_info=(*cache_info);
4006 source_info.file=(-1);
cristye8c25f92010-06-03 00:53:06 +00004007 (void) FormatMagickString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
4008 image->filename,(double) GetImageIndexInList(image));
cristy87528ea2009-09-10 14:53:56 +00004009 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +00004010 cache_info->rows=image->rows;
4011 cache_info->columns=image->columns;
4012 cache_info->active_index_channel=((image->storage_class == PseudoClass) ||
4013 (image->colorspace == CMYKColorspace)) ? MagickTrue : MagickFalse;
cristy73724512010-04-12 14:43:14 +00004014 if (image->ping != MagickFalse)
4015 {
4016 cache_info->storage_class=image->storage_class;
4017 cache_info->colorspace=image->colorspace;
4018 cache_info->type=PingCache;
4019 cache_info->pixels=(PixelPacket *) NULL;
4020 cache_info->indexes=(IndexPacket *) NULL;
4021 cache_info->length=0;
4022 return(MagickTrue);
4023 }
cristy3ed852e2009-09-05 21:47:34 +00004024 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4025 packet_size=sizeof(PixelPacket);
4026 if (cache_info->active_index_channel != MagickFalse)
4027 packet_size+=sizeof(IndexPacket);
4028 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00004029 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00004030 if (cache_info->columns != columns)
4031 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4032 image->filename);
4033 cache_info->length=length;
4034 status=AcquireMagickResource(AreaResource,cache_info->length);
4035 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4036 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4037 {
4038 status=AcquireMagickResource(MemoryResource,cache_info->length);
4039 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4040 (cache_info->type == MemoryCache))
4041 {
cristyd43a46b2010-01-21 02:13:41 +00004042 AllocatePixelCachePixels(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004043 if (cache_info->pixels == (PixelPacket *) NULL)
4044 cache_info->pixels=source_info.pixels;
4045 else
4046 {
4047 /*
4048 Create memory pixel cache.
4049 */
4050 if (image->debug != MagickFalse)
4051 {
cristy97e7a572009-12-05 15:07:53 +00004052 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004053 format);
cristy3ed852e2009-09-05 21:47:34 +00004054 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004055 "open %s (%s memory, %.20gx%.20g %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00004056 cache_info->mapped != MagickFalse ? "anonymous" : "heap",
cristye8c25f92010-06-03 00:53:06 +00004057 (double) cache_info->columns,(double) cache_info->rows,
4058 format);
cristy3ed852e2009-09-05 21:47:34 +00004059 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4060 message);
4061 }
4062 cache_info->storage_class=image->storage_class;
4063 cache_info->colorspace=image->colorspace;
4064 cache_info->type=MemoryCache;
4065 cache_info->indexes=(IndexPacket *) NULL;
4066 if (cache_info->active_index_channel != MagickFalse)
4067 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4068 number_pixels);
4069 if (source_info.storage_class != UndefinedClass)
4070 {
4071 status|=ClonePixelCachePixels(cache_info,&source_info,
4072 exception);
4073 RelinquishPixelCachePixels(&source_info);
4074 }
4075 return(MagickTrue);
4076 }
4077 }
4078 RelinquishMagickResource(MemoryResource,cache_info->length);
4079 }
4080 /*
4081 Create pixel cache on disk.
4082 */
4083 status=AcquireMagickResource(DiskResource,cache_info->length);
4084 if (status == MagickFalse)
4085 {
4086 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4087 "CacheResourcesExhausted","`%s'",image->filename);
4088 return(MagickFalse);
4089 }
4090 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4091 {
4092 RelinquishMagickResource(DiskResource,cache_info->length);
4093 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4094 image->filename);
4095 return(MagickFalse);
4096 }
4097 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4098 cache_info->length);
4099 if (status == MagickFalse)
4100 {
4101 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4102 image->filename);
4103 return(MagickFalse);
4104 }
4105 cache_info->storage_class=image->storage_class;
4106 cache_info->colorspace=image->colorspace;
4107 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4108 status=AcquireMagickResource(AreaResource,cache_info->length);
4109 if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4110 cache_info->type=DiskCache;
4111 else
4112 {
4113 status=AcquireMagickResource(MapResource,cache_info->length);
4114 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4115 (cache_info->type != MemoryCache))
4116 cache_info->type=DiskCache;
4117 else
4118 {
4119 cache_info->pixels=(PixelPacket *) MapBlob(cache_info->file,mode,
4120 cache_info->offset,(size_t) cache_info->length);
4121 if (cache_info->pixels == (PixelPacket *) NULL)
4122 {
4123 cache_info->pixels=source_info.pixels;
4124 cache_info->type=DiskCache;
4125 }
4126 else
4127 {
4128 /*
4129 Create file-backed memory-mapped pixel cache.
4130 */
4131 (void) ClosePixelCacheOnDisk(cache_info);
4132 cache_info->type=MapCache;
4133 cache_info->mapped=MagickTrue;
4134 cache_info->indexes=(IndexPacket *) NULL;
4135 if (cache_info->active_index_channel != MagickFalse)
4136 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4137 number_pixels);
4138 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4139 {
4140 status=ClonePixelCachePixels(cache_info,&source_info,
4141 exception);
4142 RelinquishPixelCachePixels(&source_info);
4143 }
4144 if (image->debug != MagickFalse)
4145 {
cristy97e7a572009-12-05 15:07:53 +00004146 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004147 format);
cristy3ed852e2009-09-05 21:47:34 +00004148 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004149 "open %s (%s[%d], memory-mapped, %.20gx%.20g %sB)",
cristy3ed852e2009-09-05 21:47:34 +00004150 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004151 cache_info->file,(double) cache_info->columns,(double)
4152 cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004153 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4154 message);
4155 }
4156 return(MagickTrue);
4157 }
4158 }
4159 RelinquishMagickResource(MapResource,cache_info->length);
4160 }
4161 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4162 {
4163 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4164 RelinquishPixelCachePixels(&source_info);
4165 }
4166 if (image->debug != MagickFalse)
4167 {
cristyb9080c92009-12-01 20:13:26 +00004168 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00004169 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004170 "open %s (%s[%d], disk, %.20gx%.20g %sB)",cache_info->filename,
4171 cache_info->cache_filename,cache_info->file,(double)
4172 cache_info->columns,(double) cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004173 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4174 }
4175 return(MagickTrue);
4176}
4177
4178/*
4179%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4180% %
4181% %
4182% %
4183+ P e r s i s t P i x e l C a c h e %
4184% %
4185% %
4186% %
4187%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4188%
4189% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4190% persistent pixel cache is one that resides on disk and is not destroyed
4191% when the program exits.
4192%
4193% The format of the PersistPixelCache() method is:
4194%
4195% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4196% const MagickBooleanType attach,MagickOffsetType *offset,
4197% ExceptionInfo *exception)
4198%
4199% A description of each parameter follows:
4200%
4201% o image: the image.
4202%
4203% o filename: the persistent pixel cache filename.
4204%
cristy01b7eb02009-09-10 23:10:14 +00004205% o attach: A value other than zero initializes the persistent pixel
4206% cache.
4207%
cristy3ed852e2009-09-05 21:47:34 +00004208% o initialize: A value other than zero initializes the persistent pixel
4209% cache.
4210%
4211% o offset: the offset in the persistent cache to store pixels.
4212%
4213% o exception: return any errors or warnings in this structure.
4214%
4215*/
4216MagickExport MagickBooleanType PersistPixelCache(Image *image,
4217 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4218 ExceptionInfo *exception)
4219{
4220 CacheInfo
4221 *cache_info,
4222 *clone_info;
4223
4224 Image
4225 clone_image;
4226
cristy3ed852e2009-09-05 21:47:34 +00004227 MagickBooleanType
4228 status;
4229
cristye076a6e2010-08-15 19:59:43 +00004230 ssize_t
4231 page_size;
4232
cristy3ed852e2009-09-05 21:47:34 +00004233 assert(image != (Image *) NULL);
4234 assert(image->signature == MagickSignature);
4235 if (image->debug != MagickFalse)
4236 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4237 assert(image->cache != (void *) NULL);
4238 assert(filename != (const char *) NULL);
4239 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004240 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004241 cache_info=(CacheInfo *) image->cache;
4242 assert(cache_info->signature == MagickSignature);
4243 if (attach != MagickFalse)
4244 {
4245 /*
cristy01b7eb02009-09-10 23:10:14 +00004246 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004247 */
4248 if (image->debug != MagickFalse)
4249 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004250 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004251 (void) CopyMagickString(cache_info->cache_filename,filename,
4252 MaxTextExtent);
4253 cache_info->type=DiskCache;
4254 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004255 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004256 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004257 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004258 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004259 }
cristy01b7eb02009-09-10 23:10:14 +00004260 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4261 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004262 {
cristyf84a1932010-01-03 18:00:18 +00004263 LockSemaphoreInfo(cache_info->semaphore);
cristy09449f72010-01-23 03:08:36 +00004264 if ((cache_info->mode != ReadMode) &&
4265 (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004266 (cache_info->reference_count == 1))
4267 {
4268 int
4269 status;
4270
4271 /*
cristy01b7eb02009-09-10 23:10:14 +00004272 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004273 */
4274 status=rename(cache_info->cache_filename,filename);
4275 if (status == 0)
4276 {
4277 (void) CopyMagickString(cache_info->cache_filename,filename,
4278 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004279 *offset+=cache_info->length+page_size-(cache_info->length %
4280 page_size);
cristyf84a1932010-01-03 18:00:18 +00004281 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004282 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004283 if (image->debug != MagickFalse)
4284 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4285 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004286 return(MagickTrue);
4287 }
4288 }
cristyf84a1932010-01-03 18:00:18 +00004289 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004290 }
4291 /*
cristy01b7eb02009-09-10 23:10:14 +00004292 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004293 */
4294 clone_image=(*image);
4295 clone_info=(CacheInfo *) clone_image.cache;
4296 image->cache=ClonePixelCache(cache_info);
4297 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4298 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4299 cache_info->type=DiskCache;
4300 cache_info->offset=(*offset);
4301 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004302 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004303 if (status != MagickFalse)
cristycfae90a2010-10-04 14:43:33 +00004304 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
cristy688f07b2009-09-27 15:19:13 +00004305 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004306 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4307 return(status);
4308}
4309
4310/*
4311%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4312% %
4313% %
4314% %
4315+ Q u e u e A u t h e n t i c N e x u s %
4316% %
4317% %
4318% %
4319%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4320%
4321% QueueAuthenticNexus() allocates an region to store image pixels as defined
4322% by the region rectangle and returns a pointer to the region. This region is
4323% subsequently transferred from the pixel cache with
4324% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4325% pixels are transferred, otherwise a NULL is returned.
4326%
4327% The format of the QueueAuthenticNexus() method is:
4328%
cristy5f959472010-05-27 22:19:46 +00004329% PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
4330% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004331% NexusInfo *nexus_info,ExceptionInfo *exception)
4332%
4333% A description of each parameter follows:
4334%
4335% o image: the image.
4336%
4337% o x,y,columns,rows: These values define the perimeter of a region of
4338% pixels.
4339%
4340% o nexus_info: the cache nexus to set.
4341%
4342% o exception: return any errors or warnings in this structure.
4343%
4344*/
cristybb503372010-05-27 20:51:26 +00004345MagickExport PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy30097232010-07-01 02:16:30 +00004346 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
4347 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004348{
4349 CacheInfo
4350 *cache_info;
4351
4352 MagickOffsetType
4353 offset;
4354
4355 MagickSizeType
4356 number_pixels;
4357
4358 RectangleInfo
4359 region;
4360
4361 /*
4362 Validate pixel cache geometry.
4363 */
cristye7cc7cf2010-09-21 13:26:47 +00004364 assert(image != (const Image *) NULL);
4365 assert(image->signature == MagickSignature);
4366 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004367 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
cristye7cc7cf2010-09-21 13:26:47 +00004368 assert(cache_info->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00004369 if (cache_info == (Cache) NULL)
4370 return((PixelPacket *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004371 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4372 {
4373 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4374 "NoPixelsDefinedInCache","`%s'",image->filename);
4375 return((PixelPacket *) NULL);
4376 }
cristybb503372010-05-27 20:51:26 +00004377 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4378 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004379 {
4380 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4381 "PixelsAreNotAuthentic","`%s'",image->filename);
4382 return((PixelPacket *) NULL);
4383 }
4384 offset=(MagickOffsetType) y*cache_info->columns+x;
4385 if (offset < 0)
4386 return((PixelPacket *) NULL);
4387 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4388 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4389 if ((MagickSizeType) offset >= number_pixels)
4390 return((PixelPacket *) NULL);
4391 /*
4392 Return pixel cache.
4393 */
4394 region.x=x;
4395 region.y=y;
4396 region.width=columns;
4397 region.height=rows;
4398 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4399}
4400
4401/*
4402%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4403% %
4404% %
4405% %
4406+ 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 %
4407% %
4408% %
4409% %
4410%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4411%
4412% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4413% defined by the region rectangle and returns a pointer to the region. This
4414% region is subsequently transferred from the pixel cache with
4415% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4416% pixels are transferred, otherwise a NULL is returned.
4417%
4418% The format of the QueueAuthenticPixelsCache() method is:
4419%
cristybb503372010-05-27 20:51:26 +00004420% PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4421% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004422% ExceptionInfo *exception)
4423%
4424% A description of each parameter follows:
4425%
4426% o image: the image.
4427%
4428% o x,y,columns,rows: These values define the perimeter of a region of
4429% pixels.
4430%
4431% o exception: return any errors or warnings in this structure.
4432%
4433*/
cristybb503372010-05-27 20:51:26 +00004434static PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4435 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004436 ExceptionInfo *exception)
4437{
4438 CacheInfo
4439 *cache_info;
4440
cristy5c9e6f22010-09-17 17:31:01 +00004441 const int
4442 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004443
cristye7cc7cf2010-09-21 13:26:47 +00004444 assert(image != (const Image *) NULL);
4445 assert(image->signature == MagickSignature);
4446 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004447 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004448 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004449 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00004450 return(QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4451 exception));
cristy3ed852e2009-09-05 21:47:34 +00004452}
4453
4454/*
4455%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4456% %
4457% %
4458% %
4459% Q u e u e A u t h e n t i c P i x e l s %
4460% %
4461% %
4462% %
4463%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4464%
4465% QueueAuthenticPixels() queues a mutable pixel region. If the region is
4466% successfully intialized a pointer to a PixelPacket array representing the
4467% region is returned, otherwise NULL is returned. The returned pointer may
4468% point to a temporary working buffer for the pixels or it may point to the
4469% final location of the pixels in memory.
4470%
4471% Write-only access means that any existing pixel values corresponding to
4472% the region are ignored. This is useful if the initial image is being
4473% created from scratch, or if the existing pixel values are to be
4474% completely replaced without need to refer to their pre-existing values.
4475% The application is free to read and write the pixel buffer returned by
4476% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4477% initialize the pixel array values. Initializing pixel array values is the
4478% application's responsibility.
4479%
4480% Performance is maximized if the selected region is part of one row, or
4481% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004482% pixels in-place (without a copy) if the image is in memory, or in a
4483% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004484% by the user.
4485%
4486% Pixels accessed via the returned pointer represent a simple array of type
4487% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
4488% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
4489% the black color component or the colormap indexes (of type IndexPacket)
4490% corresponding to the region. Once the PixelPacket (and/or IndexPacket)
4491% array has been updated, the changes must be saved back to the underlying
4492% image using SyncAuthenticPixels() or they may be lost.
4493%
4494% The format of the QueueAuthenticPixels() method is:
4495%
cristy5f959472010-05-27 22:19:46 +00004496% PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4497% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004498% ExceptionInfo *exception)
4499%
4500% A description of each parameter follows:
4501%
4502% o image: the image.
4503%
4504% o x,y,columns,rows: These values define the perimeter of a region of
4505% pixels.
4506%
4507% o exception: return any errors or warnings in this structure.
4508%
4509*/
cristybb503372010-05-27 20:51:26 +00004510MagickExport PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4511 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004512 ExceptionInfo *exception)
4513{
4514 CacheInfo
4515 *cache_info;
4516
cristy2036f5c2010-09-19 21:18:17 +00004517 const int
4518 id = GetOpenMPThreadId();
4519
cristy3ed852e2009-09-05 21:47:34 +00004520 assert(image != (Image *) NULL);
4521 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004522 assert(image->cache != (Cache) NULL);
4523 cache_info=(CacheInfo *) image->cache;
4524 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004525 if (cache_info->methods.queue_authentic_pixels_handler !=
4526 (QueueAuthenticPixelsHandler) NULL)
4527 return(cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4528 rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00004529 assert(id < (int) cache_info->number_threads);
4530 return(QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4531 exception));
cristy3ed852e2009-09-05 21:47:34 +00004532}
4533
4534/*
4535%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4536% %
4537% %
4538% %
4539+ R e a d P i x e l C a c h e I n d e x e s %
4540% %
4541% %
4542% %
4543%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4544%
4545% ReadPixelCacheIndexes() reads colormap indexes from the specified region of
4546% the pixel cache.
4547%
4548% The format of the ReadPixelCacheIndexes() method is:
4549%
4550% MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4551% NexusInfo *nexus_info,ExceptionInfo *exception)
4552%
4553% A description of each parameter follows:
4554%
4555% o cache_info: the pixel cache.
4556%
4557% o nexus_info: the cache nexus to read the colormap indexes.
4558%
4559% o exception: return any errors or warnings in this structure.
4560%
4561*/
4562static MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4563 NexusInfo *nexus_info,ExceptionInfo *exception)
4564{
4565 MagickOffsetType
4566 count,
4567 offset;
4568
4569 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004570 extent,
4571 length;
cristy3ed852e2009-09-05 21:47:34 +00004572
4573 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004574 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004575
cristybb503372010-05-27 20:51:26 +00004576 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004577 y;
4578
cristybb503372010-05-27 20:51:26 +00004579 size_t
cristy3ed852e2009-09-05 21:47:34 +00004580 rows;
4581
cristy3ed852e2009-09-05 21:47:34 +00004582 if (cache_info->active_index_channel == MagickFalse)
4583 return(MagickFalse);
4584 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4585 return(MagickTrue);
4586 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4587 nexus_info->region.x;
4588 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
4589 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004590 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004591 q=nexus_info->indexes;
4592 switch (cache_info->type)
4593 {
4594 case MemoryCache:
4595 case MapCache:
4596 {
4597 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004598 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004599
4600 /*
4601 Read indexes from memory.
4602 */
cristydd341db2010-03-04 19:06:38 +00004603 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004604 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004605 {
cristy48078b12010-09-23 17:11:01 +00004606 length=extent;
cristydd341db2010-03-04 19:06:38 +00004607 rows=1UL;
4608 }
cristy3ed852e2009-09-05 21:47:34 +00004609 p=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00004610 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004611 {
cristy8f036fe2010-09-18 02:02:00 +00004612 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00004613 p+=cache_info->columns;
4614 q+=nexus_info->region.width;
4615 }
4616 break;
4617 }
4618 case DiskCache:
4619 {
4620 /*
4621 Read indexes from disk.
4622 */
4623 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4624 {
4625 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4626 cache_info->cache_filename);
4627 return(MagickFalse);
4628 }
cristydd341db2010-03-04 19:06:38 +00004629 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004630 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004631 {
cristy48078b12010-09-23 17:11:01 +00004632 length=extent;
cristydd341db2010-03-04 19:06:38 +00004633 rows=1UL;
4634 }
cristy48078b12010-09-23 17:11:01 +00004635 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004636 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004637 {
cristy48078b12010-09-23 17:11:01 +00004638 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristy3ed852e2009-09-05 21:47:34 +00004639 sizeof(PixelPacket)+offset*sizeof(*q),length,(unsigned char *) q);
4640 if ((MagickSizeType) count < length)
4641 break;
4642 offset+=cache_info->columns;
4643 q+=nexus_info->region.width;
4644 }
cristybb503372010-05-27 20:51:26 +00004645 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004646 {
4647 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4648 cache_info->cache_filename);
4649 return(MagickFalse);
4650 }
4651 break;
4652 }
4653 default:
4654 break;
4655 }
4656 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004657 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004658 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004659 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004660 nexus_info->region.width,(double) nexus_info->region.height,(double)
4661 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004662 return(MagickTrue);
4663}
4664
4665/*
4666%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4667% %
4668% %
4669% %
4670+ R e a d P i x e l C a c h e P i x e l s %
4671% %
4672% %
4673% %
4674%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4675%
4676% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4677% cache.
4678%
4679% The format of the ReadPixelCachePixels() method is:
4680%
4681% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4682% NexusInfo *nexus_info,ExceptionInfo *exception)
4683%
4684% A description of each parameter follows:
4685%
4686% o cache_info: the pixel cache.
4687%
4688% o nexus_info: the cache nexus to read the pixels.
4689%
4690% o exception: return any errors or warnings in this structure.
4691%
4692*/
4693static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4694 NexusInfo *nexus_info,ExceptionInfo *exception)
4695{
4696 MagickOffsetType
4697 count,
4698 offset;
4699
4700 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004701 extent,
4702 length;
cristy3ed852e2009-09-05 21:47:34 +00004703
cristy3ed852e2009-09-05 21:47:34 +00004704 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004705 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004706
cristye076a6e2010-08-15 19:59:43 +00004707 register ssize_t
4708 y;
4709
cristybb503372010-05-27 20:51:26 +00004710 size_t
cristy3ed852e2009-09-05 21:47:34 +00004711 rows;
4712
cristy3ed852e2009-09-05 21:47:34 +00004713 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4714 return(MagickTrue);
4715 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4716 nexus_info->region.x;
4717 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
4718 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004719 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004720 q=nexus_info->pixels;
4721 switch (cache_info->type)
4722 {
4723 case MemoryCache:
4724 case MapCache:
4725 {
4726 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004727 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004728
4729 /*
4730 Read pixels from memory.
4731 */
cristydd341db2010-03-04 19:06:38 +00004732 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004733 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004734 {
cristy48078b12010-09-23 17:11:01 +00004735 length=extent;
cristydd341db2010-03-04 19:06:38 +00004736 rows=1UL;
4737 }
cristy3ed852e2009-09-05 21:47:34 +00004738 p=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00004739 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004740 {
cristy8f036fe2010-09-18 02:02:00 +00004741 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00004742 p+=cache_info->columns;
4743 q+=nexus_info->region.width;
4744 }
4745 break;
4746 }
4747 case DiskCache:
4748 {
4749 /*
4750 Read pixels from disk.
4751 */
4752 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4753 {
4754 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4755 cache_info->cache_filename);
4756 return(MagickFalse);
4757 }
cristydd341db2010-03-04 19:06:38 +00004758 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004759 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004760 {
cristy48078b12010-09-23 17:11:01 +00004761 length=extent;
cristydd341db2010-03-04 19:06:38 +00004762 rows=1UL;
4763 }
cristybb503372010-05-27 20:51:26 +00004764 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004765 {
4766 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4767 sizeof(*q),length,(unsigned char *) q);
4768 if ((MagickSizeType) count < length)
4769 break;
4770 offset+=cache_info->columns;
4771 q+=nexus_info->region.width;
4772 }
cristybb503372010-05-27 20:51:26 +00004773 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004774 {
4775 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4776 cache_info->cache_filename);
4777 return(MagickFalse);
4778 }
4779 break;
4780 }
4781 default:
4782 break;
4783 }
4784 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004785 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004786 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004787 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004788 nexus_info->region.width,(double) nexus_info->region.height,(double)
4789 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004790 return(MagickTrue);
4791}
4792
4793/*
4794%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4795% %
4796% %
4797% %
4798+ R e f e r e n c e P i x e l C a c h e %
4799% %
4800% %
4801% %
4802%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4803%
4804% ReferencePixelCache() increments the reference count associated with the
4805% pixel cache returning a pointer to the cache.
4806%
4807% The format of the ReferencePixelCache method is:
4808%
4809% Cache ReferencePixelCache(Cache cache_info)
4810%
4811% A description of each parameter follows:
4812%
4813% o cache_info: the pixel cache.
4814%
4815*/
4816MagickExport Cache ReferencePixelCache(Cache cache)
4817{
4818 CacheInfo
4819 *cache_info;
4820
4821 assert(cache != (Cache *) NULL);
4822 cache_info=(CacheInfo *) cache;
4823 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004824 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004825 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004826 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004827 return(cache_info);
4828}
4829
4830/*
4831%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4832% %
4833% %
4834% %
4835+ S e t P i x e l C a c h e M e t h o d s %
4836% %
4837% %
4838% %
4839%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4840%
4841% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4842%
4843% The format of the SetPixelCacheMethods() method is:
4844%
4845% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4846%
4847% A description of each parameter follows:
4848%
4849% o cache: the pixel cache.
4850%
4851% o cache_methods: Specifies a pointer to a CacheMethods structure.
4852%
4853*/
4854MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4855{
4856 CacheInfo
4857 *cache_info;
4858
4859 GetOneAuthenticPixelFromHandler
4860 get_one_authentic_pixel_from_handler;
4861
4862 GetOneVirtualPixelFromHandler
4863 get_one_virtual_pixel_from_handler;
4864
4865 /*
4866 Set cache pixel methods.
4867 */
4868 assert(cache != (Cache) NULL);
4869 assert(cache_methods != (CacheMethods *) NULL);
4870 cache_info=(CacheInfo *) cache;
4871 assert(cache_info->signature == MagickSignature);
4872 if (cache_info->debug != MagickFalse)
4873 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4874 cache_info->filename);
4875 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4876 cache_info->methods.get_virtual_pixel_handler=
4877 cache_methods->get_virtual_pixel_handler;
4878 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4879 cache_info->methods.destroy_pixel_handler=
4880 cache_methods->destroy_pixel_handler;
4881 if (cache_methods->get_virtual_indexes_from_handler !=
4882 (GetVirtualIndexesFromHandler) NULL)
4883 cache_info->methods.get_virtual_indexes_from_handler=
4884 cache_methods->get_virtual_indexes_from_handler;
4885 if (cache_methods->get_authentic_pixels_handler !=
4886 (GetAuthenticPixelsHandler) NULL)
4887 cache_info->methods.get_authentic_pixels_handler=
4888 cache_methods->get_authentic_pixels_handler;
4889 if (cache_methods->queue_authentic_pixels_handler !=
4890 (QueueAuthenticPixelsHandler) NULL)
4891 cache_info->methods.queue_authentic_pixels_handler=
4892 cache_methods->queue_authentic_pixels_handler;
4893 if (cache_methods->sync_authentic_pixels_handler !=
4894 (SyncAuthenticPixelsHandler) NULL)
4895 cache_info->methods.sync_authentic_pixels_handler=
4896 cache_methods->sync_authentic_pixels_handler;
4897 if (cache_methods->get_authentic_pixels_from_handler !=
4898 (GetAuthenticPixelsFromHandler) NULL)
4899 cache_info->methods.get_authentic_pixels_from_handler=
4900 cache_methods->get_authentic_pixels_from_handler;
4901 if (cache_methods->get_authentic_indexes_from_handler !=
4902 (GetAuthenticIndexesFromHandler) NULL)
4903 cache_info->methods.get_authentic_indexes_from_handler=
4904 cache_methods->get_authentic_indexes_from_handler;
4905 get_one_virtual_pixel_from_handler=
4906 cache_info->methods.get_one_virtual_pixel_from_handler;
4907 if (get_one_virtual_pixel_from_handler !=
4908 (GetOneVirtualPixelFromHandler) NULL)
4909 cache_info->methods.get_one_virtual_pixel_from_handler=
4910 cache_methods->get_one_virtual_pixel_from_handler;
4911 get_one_authentic_pixel_from_handler=
4912 cache_methods->get_one_authentic_pixel_from_handler;
4913 if (get_one_authentic_pixel_from_handler !=
4914 (GetOneAuthenticPixelFromHandler) NULL)
4915 cache_info->methods.get_one_authentic_pixel_from_handler=
4916 cache_methods->get_one_authentic_pixel_from_handler;
4917}
4918
4919/*
4920%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4921% %
4922% %
4923% %
4924+ S e t P i x e l C a c h e N e x u s P i x e l s %
4925% %
4926% %
4927% %
4928%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4929%
4930% SetPixelCacheNexusPixels() defines the region of the cache for the
4931% specified cache nexus.
4932%
4933% The format of the SetPixelCacheNexusPixels() method is:
4934%
4935% PixelPacket SetPixelCacheNexusPixels(const Image *image,
4936% const RectangleInfo *region,NexusInfo *nexus_info,
4937% ExceptionInfo *exception)
4938%
4939% A description of each parameter follows:
4940%
4941% o image: the image.
4942%
4943% o region: A pointer to the RectangleInfo structure that defines the
4944% region of this particular cache nexus.
4945%
4946% o nexus_info: the cache nexus to set.
4947%
4948% o exception: return any errors or warnings in this structure.
4949%
4950*/
cristyabd6e372010-09-15 19:11:26 +00004951
4952static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4953 NexusInfo *nexus_info,ExceptionInfo *exception)
4954{
4955 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4956 return(MagickFalse);
4957 nexus_info->mapped=MagickFalse;
4958 nexus_info->cache=(PixelPacket *) AcquireMagickMemory((size_t)
4959 nexus_info->length);
4960 if (nexus_info->cache == (PixelPacket *) NULL)
4961 {
4962 nexus_info->mapped=MagickTrue;
4963 nexus_info->cache=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
4964 nexus_info->length);
4965 }
4966 if (nexus_info->cache == (PixelPacket *) NULL)
4967 {
4968 (void) ThrowMagickException(exception,GetMagickModule(),
4969 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4970 cache_info->filename);
4971 return(MagickFalse);
4972 }
4973 return(MagickTrue);
4974}
4975
cristy3ed852e2009-09-05 21:47:34 +00004976static PixelPacket *SetPixelCacheNexusPixels(const Image *image,
4977 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4978{
4979 CacheInfo
4980 *cache_info;
4981
4982 MagickBooleanType
4983 status;
4984
cristy3ed852e2009-09-05 21:47:34 +00004985 MagickSizeType
4986 length,
4987 number_pixels;
4988
cristy3ed852e2009-09-05 21:47:34 +00004989 cache_info=(CacheInfo *) image->cache;
4990 assert(cache_info->signature == MagickSignature);
4991 if (cache_info->type == UndefinedCache)
4992 return((PixelPacket *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00004993 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00004994 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
4995 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00004996 {
cristybb503372010-05-27 20:51:26 +00004997 ssize_t
cristybad067a2010-02-15 17:20:55 +00004998 x,
4999 y;
cristy3ed852e2009-09-05 21:47:34 +00005000
cristyeaedf062010-05-29 22:36:02 +00005001 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
5002 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00005003 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5004 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00005005 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00005006 ((nexus_info->region.width == cache_info->columns) ||
5007 ((nexus_info->region.width % cache_info->columns) == 0)))))
5008 {
5009 MagickOffsetType
5010 offset;
5011
5012 /*
5013 Pixels are accessed directly from memory.
5014 */
5015 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5016 nexus_info->region.x;
5017 nexus_info->pixels=cache_info->pixels+offset;
5018 nexus_info->indexes=(IndexPacket *) NULL;
5019 if (cache_info->active_index_channel != MagickFalse)
5020 nexus_info->indexes=cache_info->indexes+offset;
5021 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00005022 }
5023 }
5024 /*
5025 Pixels are stored in a cache region until they are synced to the cache.
5026 */
5027 number_pixels=(MagickSizeType) nexus_info->region.width*
5028 nexus_info->region.height;
5029 length=number_pixels*sizeof(PixelPacket);
5030 if (cache_info->active_index_channel != MagickFalse)
5031 length+=number_pixels*sizeof(IndexPacket);
5032 if (nexus_info->cache == (PixelPacket *) NULL)
5033 {
5034 nexus_info->length=length;
5035 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5036 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005037 {
5038 nexus_info->length=0;
5039 return((PixelPacket *) NULL);
5040 }
cristy3ed852e2009-09-05 21:47:34 +00005041 }
5042 else
5043 if (nexus_info->length != length)
5044 {
5045 RelinquishCacheNexusPixels(nexus_info);
5046 nexus_info->length=length;
5047 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5048 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005049 {
5050 nexus_info->length=0;
5051 return((PixelPacket *) NULL);
5052 }
cristy3ed852e2009-09-05 21:47:34 +00005053 }
5054 nexus_info->pixels=nexus_info->cache;
5055 nexus_info->indexes=(IndexPacket *) NULL;
5056 if (cache_info->active_index_channel != MagickFalse)
5057 nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
5058 return(nexus_info->pixels);
5059}
5060
5061/*
5062%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5063% %
5064% %
5065% %
5066% 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 %
5067% %
5068% %
5069% %
5070%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5071%
5072% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5073% pixel cache and returns the previous setting. A virtual pixel is any pixel
5074% access that is outside the boundaries of the image cache.
5075%
5076% The format of the SetPixelCacheVirtualMethod() method is:
5077%
5078% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5079% const VirtualPixelMethod virtual_pixel_method)
5080%
5081% A description of each parameter follows:
5082%
5083% o image: the image.
5084%
5085% o virtual_pixel_method: choose the type of virtual pixel.
5086%
5087*/
5088MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5089 const VirtualPixelMethod virtual_pixel_method)
5090{
5091 CacheInfo
5092 *cache_info;
5093
5094 VirtualPixelMethod
5095 method;
5096
5097 assert(image != (Image *) NULL);
5098 assert(image->signature == MagickSignature);
5099 if (image->debug != MagickFalse)
5100 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5101 assert(image->cache != (Cache) NULL);
5102 cache_info=(CacheInfo *) image->cache;
5103 assert(cache_info->signature == MagickSignature);
5104 method=cache_info->virtual_pixel_method;
5105 cache_info->virtual_pixel_method=virtual_pixel_method;
5106 return(method);
5107}
5108
5109/*
5110%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5111% %
5112% %
5113% %
5114+ 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 %
5115% %
5116% %
5117% %
5118%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5119%
5120% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5121% in-memory or disk cache. The method returns MagickTrue if the pixel region
5122% is synced, otherwise MagickFalse.
5123%
5124% The format of the SyncAuthenticPixelCacheNexus() method is:
5125%
5126% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5127% NexusInfo *nexus_info,ExceptionInfo *exception)
5128%
5129% A description of each parameter follows:
5130%
5131% o image: the image.
5132%
5133% o nexus_info: the cache nexus to sync.
5134%
5135% o exception: return any errors or warnings in this structure.
5136%
5137*/
5138MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5139 NexusInfo *nexus_info,ExceptionInfo *exception)
5140{
5141 CacheInfo
5142 *cache_info;
5143
5144 MagickBooleanType
5145 status;
5146
5147 /*
5148 Transfer pixels to the cache.
5149 */
5150 assert(image != (Image *) NULL);
5151 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005152 if (image->cache == (Cache) NULL)
5153 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5154 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005155 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005156 if (cache_info->type == UndefinedCache)
5157 return(MagickFalse);
5158 if ((image->clip_mask != (Image *) NULL) &&
5159 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5160 return(MagickFalse);
5161 if ((image->mask != (Image *) NULL) &&
5162 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5163 return(MagickFalse);
5164 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5165 return(MagickTrue);
5166 assert(cache_info->signature == MagickSignature);
5167 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5168 if ((cache_info->active_index_channel != MagickFalse) &&
5169 (WritePixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse))
5170 return(MagickFalse);
5171 return(status);
5172}
5173
5174/*
5175%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5176% %
5177% %
5178% %
5179+ S y n c A u t h e n t i c P i x e l C a c h e %
5180% %
5181% %
5182% %
5183%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5184%
5185% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5186% or disk cache. The method returns MagickTrue if the pixel region is synced,
5187% otherwise MagickFalse.
5188%
5189% The format of the SyncAuthenticPixelsCache() method is:
5190%
5191% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5192% ExceptionInfo *exception)
5193%
5194% A description of each parameter follows:
5195%
5196% o image: the image.
5197%
5198% o exception: return any errors or warnings in this structure.
5199%
5200*/
5201static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5202 ExceptionInfo *exception)
5203{
5204 CacheInfo
5205 *cache_info;
5206
cristy5c9e6f22010-09-17 17:31:01 +00005207 const int
5208 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005209
cristye7cc7cf2010-09-21 13:26:47 +00005210 assert(image != (Image *) NULL);
5211 assert(image->signature == MagickSignature);
5212 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005213 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005214 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005215 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00005216 return(SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5217 exception));
cristy3ed852e2009-09-05 21:47:34 +00005218}
5219
5220/*
5221%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5222% %
5223% %
5224% %
5225% S y n c A u t h e n t i c P i x e l s %
5226% %
5227% %
5228% %
5229%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5230%
5231% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5232% The method returns MagickTrue if the pixel region is flushed, otherwise
5233% MagickFalse.
5234%
5235% The format of the SyncAuthenticPixels() method is:
5236%
5237% MagickBooleanType SyncAuthenticPixels(Image *image,
5238% ExceptionInfo *exception)
5239%
5240% A description of each parameter follows:
5241%
5242% o image: the image.
5243%
5244% o exception: return any errors or warnings in this structure.
5245%
5246*/
5247MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5248 ExceptionInfo *exception)
5249{
5250 CacheInfo
5251 *cache_info;
5252
cristy2036f5c2010-09-19 21:18:17 +00005253 const int
5254 id = GetOpenMPThreadId();
5255
cristy3ed852e2009-09-05 21:47:34 +00005256 assert(image != (Image *) NULL);
5257 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005258 assert(image->cache != (Cache) NULL);
5259 cache_info=(CacheInfo *) image->cache;
5260 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005261 if (cache_info->methods.sync_authentic_pixels_handler !=
5262 (SyncAuthenticPixelsHandler) NULL)
5263 return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
cristy2036f5c2010-09-19 21:18:17 +00005264 assert(id < (int) cache_info->number_threads);
5265 return(SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5266 exception));
cristy3ed852e2009-09-05 21:47:34 +00005267}
5268
5269/*
5270%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5271% %
5272% %
5273% %
5274+ W r i t e P i x e l C a c h e I n d e x e s %
5275% %
5276% %
5277% %
5278%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5279%
5280% WritePixelCacheIndexes() writes the colormap indexes to the specified
5281% region of the pixel cache.
5282%
5283% The format of the WritePixelCacheIndexes() method is:
5284%
5285% MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5286% NexusInfo *nexus_info,ExceptionInfo *exception)
5287%
5288% A description of each parameter follows:
5289%
5290% o cache_info: the pixel cache.
5291%
5292% o nexus_info: the cache nexus to write the colormap indexes.
5293%
5294% o exception: return any errors or warnings in this structure.
5295%
5296*/
5297static MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5298 NexusInfo *nexus_info,ExceptionInfo *exception)
5299{
5300 MagickOffsetType
5301 count,
5302 offset;
5303
5304 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005305 extent,
5306 length;
cristy3ed852e2009-09-05 21:47:34 +00005307
5308 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005309 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005310
cristybb503372010-05-27 20:51:26 +00005311 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005312 y;
5313
cristybb503372010-05-27 20:51:26 +00005314 size_t
cristy3ed852e2009-09-05 21:47:34 +00005315 rows;
5316
cristy3ed852e2009-09-05 21:47:34 +00005317 if (cache_info->active_index_channel == MagickFalse)
5318 return(MagickFalse);
5319 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5320 return(MagickTrue);
5321 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5322 nexus_info->region.x;
5323 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
5324 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005325 extent=(MagickSizeType) length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005326 p=nexus_info->indexes;
5327 switch (cache_info->type)
5328 {
5329 case MemoryCache:
5330 case MapCache:
5331 {
5332 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005333 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005334
5335 /*
5336 Write indexes to memory.
5337 */
cristydd341db2010-03-04 19:06:38 +00005338 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005339 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005340 {
cristy48078b12010-09-23 17:11:01 +00005341 length=extent;
cristydd341db2010-03-04 19:06:38 +00005342 rows=1UL;
5343 }
cristy3ed852e2009-09-05 21:47:34 +00005344 q=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00005345 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005346 {
cristy8f036fe2010-09-18 02:02:00 +00005347 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00005348 p+=nexus_info->region.width;
5349 q+=cache_info->columns;
5350 }
5351 break;
5352 }
5353 case DiskCache:
5354 {
5355 /*
5356 Write indexes to disk.
5357 */
5358 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5359 {
5360 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5361 cache_info->cache_filename);
5362 return(MagickFalse);
5363 }
cristydd341db2010-03-04 19:06:38 +00005364 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005365 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005366 {
cristy48078b12010-09-23 17:11:01 +00005367 length=extent;
cristydd341db2010-03-04 19:06:38 +00005368 rows=1UL;
5369 }
cristy48078b12010-09-23 17:11:01 +00005370 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005371 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005372 {
cristy48078b12010-09-23 17:11:01 +00005373 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5374 sizeof(PixelPacket)+offset*sizeof(*p),length,(const unsigned char *)
5375 p);
cristy3ed852e2009-09-05 21:47:34 +00005376 if ((MagickSizeType) count < length)
5377 break;
5378 p+=nexus_info->region.width;
5379 offset+=cache_info->columns;
5380 }
cristybb503372010-05-27 20:51:26 +00005381 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005382 {
5383 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5384 cache_info->cache_filename);
5385 return(MagickFalse);
5386 }
5387 break;
5388 }
5389 default:
5390 break;
5391 }
5392 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005393 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005394 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005395 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005396 nexus_info->region.width,(double) nexus_info->region.height,(double)
5397 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005398 return(MagickTrue);
5399}
5400
5401/*
5402%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5403% %
5404% %
5405% %
5406+ W r i t e C a c h e P i x e l s %
5407% %
5408% %
5409% %
5410%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5411%
5412% WritePixelCachePixels() writes image pixels to the specified region of the
5413% pixel cache.
5414%
5415% The format of the WritePixelCachePixels() method is:
5416%
5417% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5418% NexusInfo *nexus_info,ExceptionInfo *exception)
5419%
5420% A description of each parameter follows:
5421%
5422% o cache_info: the pixel cache.
5423%
5424% o nexus_info: the cache nexus to write the pixels.
5425%
5426% o exception: return any errors or warnings in this structure.
5427%
5428*/
5429static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5430 NexusInfo *nexus_info,ExceptionInfo *exception)
5431{
5432 MagickOffsetType
5433 count,
5434 offset;
5435
5436 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005437 extent,
5438 length;
cristy3ed852e2009-09-05 21:47:34 +00005439
cristy3ed852e2009-09-05 21:47:34 +00005440 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005441 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005442
cristybb503372010-05-27 20:51:26 +00005443 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005444 y;
5445
cristybb503372010-05-27 20:51:26 +00005446 size_t
cristy3ed852e2009-09-05 21:47:34 +00005447 rows;
5448
cristy3ed852e2009-09-05 21:47:34 +00005449 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5450 return(MagickTrue);
5451 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5452 nexus_info->region.x;
5453 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
5454 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005455 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005456 p=nexus_info->pixels;
5457 switch (cache_info->type)
5458 {
5459 case MemoryCache:
5460 case MapCache:
5461 {
5462 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005463 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005464
5465 /*
5466 Write pixels to memory.
5467 */
cristydd341db2010-03-04 19:06:38 +00005468 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005469 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005470 {
cristy48078b12010-09-23 17:11:01 +00005471 length=extent;
cristydd341db2010-03-04 19:06:38 +00005472 rows=1UL;
5473 }
cristy3ed852e2009-09-05 21:47:34 +00005474 q=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00005475 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005476 {
cristy8f036fe2010-09-18 02:02:00 +00005477 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00005478 p+=nexus_info->region.width;
5479 q+=cache_info->columns;
5480 }
5481 break;
5482 }
5483 case DiskCache:
5484 {
5485 /*
5486 Write pixels to disk.
5487 */
5488 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5489 {
5490 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5491 cache_info->cache_filename);
5492 return(MagickFalse);
5493 }
cristydd341db2010-03-04 19:06:38 +00005494 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005495 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005496 {
cristy48078b12010-09-23 17:11:01 +00005497 length=extent;
cristydd341db2010-03-04 19:06:38 +00005498 rows=1UL;
5499 }
cristybb503372010-05-27 20:51:26 +00005500 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005501 {
5502 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5503 sizeof(*p),length,(const unsigned char *) p);
5504 if ((MagickSizeType) count < length)
5505 break;
5506 p+=nexus_info->region.width;
5507 offset+=cache_info->columns;
5508 }
cristybb503372010-05-27 20:51:26 +00005509 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005510 {
5511 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5512 cache_info->cache_filename);
5513 return(MagickFalse);
5514 }
5515 break;
5516 }
5517 default:
5518 break;
5519 }
5520 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005521 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005522 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005523 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005524 nexus_info->region.width,(double) nexus_info->region.height,(double)
5525 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005526 return(MagickTrue);
5527}