blob: ab076db7a04110e0d09ab6cf0ad9b8da91b203c9 [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
188 cache_info=(CacheInfo *) AcquireAlignedMemory(1,sizeof(*cache_info));
189 if (cache_info == (CacheInfo *) NULL)
190 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
191 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
192 cache_info->type=UndefinedCache;
cristy87528ea2009-09-10 14:53:56 +0000193 cache_info->mode=IOMode;
cristy3ed852e2009-09-05 21:47:34 +0000194 cache_info->colorspace=RGBColorspace;
195 cache_info->file=(-1);
196 cache_info->id=GetMagickThreadId();
197 cache_info->number_threads=number_threads;
198 if (number_threads == 0)
199 cache_info->number_threads=GetOpenMPMaximumThreads();
200 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
201 if (cache_info->nexus_info == (NexusInfo **) NULL)
202 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
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
cristy3ed852e2009-09-05 21:47:34 +0000257 nexus_info=(NexusInfo **) AcquireAlignedMemory(number_threads,
258 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);
cristy3ed852e2009-09-05 21:47:34 +00001526 cache_info=(CacheInfo *) RelinquishAlignedMemory(cache_info);
1527 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 }
1584 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
1585 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));
cristye7cc7cf2010-09-21 13:26:47 +00001900 return(GetAuthenticPixelsCache(image,x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00001901 assert(id < (int) cache_info->number_threads);
1902 return(GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1903 cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00001904}
1905
1906/*
1907%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1908% %
1909% %
1910% %
1911+ G e t A u t h e n t i c P i x e l s C a c h e %
1912% %
1913% %
1914% %
1915%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1916%
1917% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1918% as defined by the geometry parameters. A pointer to the pixels is returned
1919% if the pixels are transferred, otherwise a NULL is returned.
1920%
1921% The format of the GetAuthenticPixelsCache() method is:
1922%
cristybb503372010-05-27 20:51:26 +00001923% PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1924% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001925% ExceptionInfo *exception)
1926%
1927% A description of each parameter follows:
1928%
1929% o image: the image.
1930%
1931% o x,y,columns,rows: These values define the perimeter of a region of
1932% pixels.
1933%
1934% o exception: return any errors or warnings in this structure.
1935%
1936*/
cristybb503372010-05-27 20:51:26 +00001937static PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1938 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001939 ExceptionInfo *exception)
1940{
1941 CacheInfo
1942 *cache_info;
1943
cristy5c9e6f22010-09-17 17:31:01 +00001944 const int
1945 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001946
cristye7cc7cf2010-09-21 13:26:47 +00001947 assert(image != (const Image *) NULL);
1948 assert(image->signature == MagickSignature);
1949 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00001950 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001951 if (cache_info == (Cache) NULL)
1952 return((PixelPacket *) NULL);
cristye7cc7cf2010-09-21 13:26:47 +00001953 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001954 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001955 return(GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1956 cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00001957}
1958
1959/*
1960%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1961% %
1962% %
1963% %
1964+ G e t I m a g e E x t e n t %
1965% %
1966% %
1967% %
1968%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1969%
1970% GetImageExtent() returns the extent of the pixels associated with the
1971% last call to QueueAuthenticPixels() or GetAuthenticPixels().
1972%
1973% The format of the GetImageExtent() method is:
1974%
1975% MagickSizeType GetImageExtent(const Image *image)
1976%
1977% A description of each parameter follows:
1978%
1979% o image: the image.
1980%
1981*/
1982MagickExport MagickSizeType GetImageExtent(const Image *image)
1983{
1984 CacheInfo
1985 *cache_info;
1986
cristy5c9e6f22010-09-17 17:31:01 +00001987 const int
1988 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001989
cristy3ed852e2009-09-05 21:47:34 +00001990 assert(image != (Image *) NULL);
1991 assert(image->signature == MagickSignature);
1992 if (image->debug != MagickFalse)
1993 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1994 assert(image->cache != (Cache) NULL);
1995 cache_info=(CacheInfo *) image->cache;
1996 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001997 assert(id < (int) cache_info->number_threads);
cristy2036f5c2010-09-19 21:18:17 +00001998 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001999}
2000
2001/*
2002%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2003% %
2004% %
2005% %
2006+ G e t I m a g e P i x e l C a c h e %
2007% %
2008% %
2009% %
2010%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2011%
2012% GetImagePixelCache() ensures that there is only a single reference to the
2013% pixel cache to be modified, updating the provided cache pointer to point to
2014% a clone of the original pixel cache if necessary.
2015%
2016% The format of the GetImagePixelCache method is:
2017%
2018% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2019% ExceptionInfo *exception)
2020%
2021% A description of each parameter follows:
2022%
2023% o image: the image.
2024%
2025% o clone: any value other than MagickFalse clones the cache pixels.
2026%
2027% o exception: return any errors or warnings in this structure.
2028%
2029*/
cristy3ed852e2009-09-05 21:47:34 +00002030static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
2031{
2032 CacheInfo
2033 *cache_info;
2034
2035 /*
2036 Does the image match the pixel cache morphology?
2037 */
2038 cache_info=(CacheInfo *) image->cache;
2039 if ((image->storage_class != cache_info->storage_class) ||
2040 (image->colorspace != cache_info->colorspace) ||
2041 (image->columns != cache_info->columns) ||
2042 (image->rows != cache_info->rows) ||
2043 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2044 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2045 return(MagickFalse);
2046 return(MagickTrue);
2047}
2048
cristy77ff0282010-09-13 00:51:10 +00002049static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2050 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002051{
2052 CacheInfo
2053 *cache_info;
2054
cristy3ed852e2009-09-05 21:47:34 +00002055 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00002056 destroy,
cristy3ed852e2009-09-05 21:47:34 +00002057 status;
2058
cristy50a10922010-02-15 18:35:25 +00002059 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00002060 cpu_throttle = 0,
2061 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00002062 time_limit = 0;
2063
cristy1ea34962010-07-01 19:49:21 +00002064 static time_t
cristya21afde2010-07-02 00:45:40 +00002065 cache_genesis = 0;
cristy1ea34962010-07-01 19:49:21 +00002066
cristyc4f9f132010-03-04 18:50:01 +00002067 status=MagickTrue;
2068 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00002069 if (cpu_throttle == 0)
2070 {
2071 char
2072 *limit;
2073
2074 /*
2075 Set CPU throttle in milleseconds.
2076 */
2077 cpu_throttle=MagickResourceInfinity;
2078 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2079 if (limit == (char *) NULL)
2080 limit=GetPolicyValue("throttle");
2081 if (limit != (char *) NULL)
2082 {
2083 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2084 limit=DestroyString(limit);
2085 }
2086 }
2087 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2088 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00002089 if (time_limit == 0)
2090 {
cristy6ebe97c2010-07-03 01:17:28 +00002091 /*
2092 Set the exire time in seconds.
2093 */
cristy1ea34962010-07-01 19:49:21 +00002094 time_limit=GetMagickResourceLimit(TimeResource);
cristya21afde2010-07-02 00:45:40 +00002095 cache_genesis=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00002096 }
2097 if ((time_limit != MagickResourceInfinity) &&
cristya21afde2010-07-02 00:45:40 +00002098 ((MagickSizeType) (time((time_t *) NULL)-cache_genesis) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00002099 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00002100 assert(image->cache != (Cache) NULL);
2101 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002102 destroy=MagickFalse;
cristy01b7eb02009-09-10 23:10:14 +00002103 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002104 {
cristyaaa0cb62010-02-15 17:47:27 +00002105 LockSemaphoreInfo(cache_info->semaphore);
2106 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002107 {
cristyaaa0cb62010-02-15 17:47:27 +00002108 Image
2109 clone_image;
2110
2111 CacheInfo
2112 *clone_info;
2113
2114 /*
2115 Clone pixel cache.
2116 */
2117 clone_image=(*image);
cristy93505cf2010-08-10 21:37:49 +00002118 clone_image.semaphore=AllocateSemaphoreInfo();
2119 clone_image.reference_count=1;
cristyaaa0cb62010-02-15 17:47:27 +00002120 clone_image.cache=ClonePixelCache(cache_info);
2121 clone_info=(CacheInfo *) clone_image.cache;
cristyabd6e372010-09-15 19:11:26 +00002122 status=OpenPixelCache(&clone_image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00002123 if (status != MagickFalse)
2124 {
cristyabd6e372010-09-15 19:11:26 +00002125 if (clone != MagickFalse)
2126 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00002127 if (status != MagickFalse)
2128 {
cristyabd6e372010-09-15 19:11:26 +00002129 destroy=MagickTrue;
2130 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00002131 }
2132 }
cristy93505cf2010-08-10 21:37:49 +00002133 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002134 }
cristyaaa0cb62010-02-15 17:47:27 +00002135 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002136 }
cristy4320e0e2009-09-10 15:00:08 +00002137 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002138 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002139 if (status != MagickFalse)
2140 {
2141 /*
2142 Ensure the image matches the pixel cache morphology.
2143 */
2144 image->taint=MagickTrue;
2145 image->type=UndefinedType;
cristydd438462010-05-06 13:44:04 +00002146 if (image->colorspace == GRAYColorspace)
2147 image->colorspace=RGBColorspace;
cristy3ed852e2009-09-05 21:47:34 +00002148 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2149 status=OpenPixelCache(image,IOMode,exception);
2150 }
cristyf84a1932010-01-03 18:00:18 +00002151 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002152 if (status == MagickFalse)
2153 return((Cache) NULL);
2154 return(image->cache);
2155}
2156
2157/*
2158%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2159% %
2160% %
2161% %
2162% G e t O n e A u t h e n t i c P i x e l %
2163% %
2164% %
2165% %
2166%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2167%
2168% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2169% location. The image background color is returned if an error occurs.
2170%
2171% The format of the GetOneAuthenticPixel() method is:
2172%
cristybb503372010-05-27 20:51:26 +00002173% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2174% const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002175%
2176% A description of each parameter follows:
2177%
2178% o image: the image.
2179%
2180% o x,y: These values define the location of the pixel to return.
2181%
2182% o pixel: return a pixel at the specified (x,y) location.
2183%
2184% o exception: return any errors or warnings in this structure.
2185%
2186*/
cristyacbbb7c2010-06-30 18:56:48 +00002187MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2188 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002189{
2190 CacheInfo
2191 *cache_info;
2192
cristy2036f5c2010-09-19 21:18:17 +00002193 PixelPacket
2194 *pixels;
2195
cristy3ed852e2009-09-05 21:47:34 +00002196 assert(image != (Image *) NULL);
2197 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002198 assert(image->cache != (Cache) NULL);
2199 cache_info=(CacheInfo *) image->cache;
2200 assert(cache_info->signature == MagickSignature);
2201 *pixel=image->background_color;
cristyd317f372010-09-18 01:42:20 +00002202 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2203 (GetOneAuthenticPixelFromHandler) NULL)
2204 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2205 pixel,exception));
cristy2036f5c2010-09-19 21:18:17 +00002206 *pixel=image->background_color;
2207 pixels=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2208 if (pixels == (PixelPacket *) NULL)
2209 return(MagickFalse);
2210 *pixel=(*pixels);
2211 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002212}
2213
2214/*
2215%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2216% %
2217% %
2218% %
2219+ 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 %
2220% %
2221% %
2222% %
2223%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2224%
2225% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2226% location. The image background color is returned if an error occurs.
2227%
2228% The format of the GetOneAuthenticPixelFromCache() method is:
2229%
2230% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy5f959472010-05-27 22:19:46 +00002231% const ssize_t x,const ssize_t y,PixelPacket *pixel,
2232% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002233%
2234% A description of each parameter follows:
2235%
2236% o image: the image.
2237%
2238% o x,y: These values define the location of the pixel to return.
2239%
2240% o pixel: return a pixel at the specified (x,y) location.
2241%
2242% o exception: return any errors or warnings in this structure.
2243%
2244*/
2245static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristybb503372010-05-27 20:51:26 +00002246 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002247{
2248 PixelPacket
2249 *pixels;
2250
cristy0158a4b2010-09-20 13:59:45 +00002251 assert(image != (const Image *) NULL);
2252 assert(image->signature == MagickSignature);
2253 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002254 *pixel=image->background_color;
cristye7cc7cf2010-09-21 13:26:47 +00002255 pixels=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
cristy3ed852e2009-09-05 21:47:34 +00002256 if (pixels == (PixelPacket *) NULL)
2257 return(MagickFalse);
2258 *pixel=(*pixels);
2259 return(MagickTrue);
2260}
2261
2262/*
2263%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2264% %
2265% %
2266% %
2267% G e t O n e V i r t u a l M a g i c k P i x e l %
2268% %
2269% %
2270% %
2271%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2272%
2273% GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2274% location. The image background color is returned if an error occurs. If
2275% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2276%
2277% The format of the GetOneVirtualMagickPixel() method is:
2278%
2279% MagickBooleanType GetOneVirtualMagickPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002280% const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
cristy3ed852e2009-09-05 21:47:34 +00002281% ExceptionInfo exception)
2282%
2283% A description of each parameter follows:
2284%
2285% o image: the image.
2286%
2287% o x,y: these values define the location of the pixel to return.
2288%
2289% o pixel: return a pixel at the specified (x,y) location.
2290%
2291% o exception: return any errors or warnings in this structure.
2292%
2293*/
2294MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
cristyacbbb7c2010-06-30 18:56:48 +00002295 const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
2296 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002297{
2298 CacheInfo
2299 *cache_info;
2300
cristy0158a4b2010-09-20 13:59:45 +00002301 const int
2302 id = GetOpenMPThreadId();
2303
cristy3ed852e2009-09-05 21:47:34 +00002304 register const IndexPacket
2305 *indexes;
2306
2307 register const PixelPacket
cristy0158a4b2010-09-20 13:59:45 +00002308 *pixels;
cristy3ed852e2009-09-05 21:47:34 +00002309
2310 assert(image != (const Image *) NULL);
2311 assert(image->signature == MagickSignature);
2312 assert(image->cache != (Cache) NULL);
2313 cache_info=(CacheInfo *) image->cache;
2314 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002315 assert(id < (int) cache_info->number_threads);
2316 pixels=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2317 1UL,1UL,cache_info->nexus_info[id],exception);
cristye7cc7cf2010-09-21 13:26:47 +00002318 GetMagickPixelPacket(image,pixel);
cristy0158a4b2010-09-20 13:59:45 +00002319 if (pixels == (const PixelPacket *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002320 return(MagickFalse);
cristye7cc7cf2010-09-21 13:26:47 +00002321 indexes=GetVirtualIndexQueue(image);
cristy0158a4b2010-09-20 13:59:45 +00002322 SetMagickPixelPacket(image,pixels,indexes,pixel);
cristy3ed852e2009-09-05 21:47:34 +00002323 return(MagickTrue);
2324}
2325
2326/*
2327%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2328% %
2329% %
2330% %
2331% G e t O n e V i r t u a l M e t h o d P i x e l %
2332% %
2333% %
2334% %
2335%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2336%
2337% GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2338% location as defined by specified pixel method. The image background color
2339% is returned if an error occurs. If you plan to modify the pixel, use
2340% GetOneAuthenticPixel() instead.
2341%
2342% The format of the GetOneVirtualMethodPixel() method is:
2343%
2344% MagickBooleanType GetOneVirtualMethodPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002345% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2346% const ssize_t y,Pixelpacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002347%
2348% A description of each parameter follows:
2349%
2350% o image: the image.
2351%
2352% o virtual_pixel_method: the virtual pixel method.
2353%
2354% o x,y: These values define the location of the pixel to return.
2355%
2356% o pixel: return a pixel at the specified (x,y) location.
2357%
2358% o exception: return any errors or warnings in this structure.
2359%
2360*/
2361MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002362 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002363 PixelPacket *pixel,ExceptionInfo *exception)
2364{
cristy3ed852e2009-09-05 21:47:34 +00002365 CacheInfo
2366 *cache_info;
2367
cristy0158a4b2010-09-20 13:59:45 +00002368 const int
2369 id = GetOpenMPThreadId();
2370
cristy2036f5c2010-09-19 21:18:17 +00002371 const PixelPacket
2372 *pixels;
2373
cristy3ed852e2009-09-05 21:47:34 +00002374 assert(image != (const Image *) NULL);
2375 assert(image->signature == MagickSignature);
2376 assert(image->cache != (Cache) NULL);
2377 cache_info=(CacheInfo *) image->cache;
2378 assert(cache_info->signature == MagickSignature);
2379 *pixel=image->background_color;
cristyd317f372010-09-18 01:42:20 +00002380 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2381 (GetOneVirtualPixelFromHandler) NULL)
2382 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2383 virtual_pixel_method,x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002384 assert(id < (int) cache_info->number_threads);
2385 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2386 cache_info->nexus_info[id],exception);
cristy2036f5c2010-09-19 21:18:17 +00002387 if (pixels == (const PixelPacket *) NULL)
2388 return(MagickFalse);
2389 *pixel=(*pixels);
2390 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002391}
2392
2393/*
2394%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2395% %
2396% %
2397% %
2398% G e t O n e V i r t u a l P i x e l %
2399% %
2400% %
2401% %
2402%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2403%
2404% GetOneVirtualPixel() returns a single virtual pixel at the specified
2405% (x,y) location. The image background color is returned if an error occurs.
2406% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2407%
2408% The format of the GetOneVirtualPixel() method is:
2409%
cristybb503372010-05-27 20:51:26 +00002410% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2411% const ssize_t y,PixelPacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002412%
2413% A description of each parameter follows:
2414%
2415% o image: the image.
2416%
2417% o x,y: These values define the location of the pixel to return.
2418%
2419% o pixel: return a pixel at the specified (x,y) location.
2420%
2421% o exception: return any errors or warnings in this structure.
2422%
2423*/
2424MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002425 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002426{
cristy3ed852e2009-09-05 21:47:34 +00002427 CacheInfo
2428 *cache_info;
2429
cristy0158a4b2010-09-20 13:59:45 +00002430 const int
2431 id = GetOpenMPThreadId();
2432
cristy2036f5c2010-09-19 21:18:17 +00002433 const PixelPacket
2434 *pixels;
2435
cristy3ed852e2009-09-05 21:47:34 +00002436 assert(image != (const Image *) NULL);
2437 assert(image->signature == MagickSignature);
2438 assert(image->cache != (Cache) NULL);
2439 cache_info=(CacheInfo *) image->cache;
2440 assert(cache_info->signature == MagickSignature);
2441 *pixel=image->background_color;
cristyd317f372010-09-18 01:42:20 +00002442 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2443 (GetOneVirtualPixelFromHandler) NULL)
2444 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2445 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002446 assert(id < (int) cache_info->number_threads);
2447 pixels=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2448 1UL,1UL,cache_info->nexus_info[id],exception);
cristy2036f5c2010-09-19 21:18:17 +00002449 if (pixels == (const PixelPacket *) NULL)
2450 return(MagickFalse);
2451 *pixel=(*pixels);
2452 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002453}
2454
2455/*
2456%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2457% %
2458% %
2459% %
2460+ 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 %
2461% %
2462% %
2463% %
2464%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2465%
2466% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2467% specified (x,y) location. The image background color is returned if an
2468% error occurs.
2469%
2470% The format of the GetOneVirtualPixelFromCache() method is:
2471%
2472% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristybb503372010-05-27 20:51:26 +00002473% const VirtualPixelPacket method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002474% PixelPacket *pixel,ExceptionInfo *exception)
2475%
2476% A description of each parameter follows:
2477%
2478% o image: the image.
2479%
2480% o virtual_pixel_method: the virtual pixel method.
2481%
2482% o x,y: These values define the location of the pixel to return.
2483%
2484% o pixel: return a pixel at the specified (x,y) location.
2485%
2486% o exception: return any errors or warnings in this structure.
2487%
2488*/
2489static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002490 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002491 PixelPacket *pixel,ExceptionInfo *exception)
2492{
cristy0158a4b2010-09-20 13:59:45 +00002493 CacheInfo
2494 *cache_info;
2495
2496 const int
2497 id = GetOpenMPThreadId();
2498
cristy3ed852e2009-09-05 21:47:34 +00002499 const PixelPacket
2500 *pixels;
2501
cristye7cc7cf2010-09-21 13:26:47 +00002502 assert(image != (const Image *) NULL);
2503 assert(image->signature == MagickSignature);
2504 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002505 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002506 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002507 assert(id < (int) cache_info->number_threads);
cristye7cc7cf2010-09-21 13:26:47 +00002508 *pixel=image->background_color;
cristy0158a4b2010-09-20 13:59:45 +00002509 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2510 cache_info->nexus_info[id],exception);
cristy3ed852e2009-09-05 21:47:34 +00002511 if (pixels == (const PixelPacket *) NULL)
2512 return(MagickFalse);
2513 *pixel=(*pixels);
2514 return(MagickTrue);
2515}
2516
2517/*
2518%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2519% %
2520% %
2521% %
2522+ G e t P i x e l C a c h e C o l o r s p a c e %
2523% %
2524% %
2525% %
2526%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2527%
2528% GetPixelCacheColorspace() returns the class type of the pixel cache.
2529%
2530% The format of the GetPixelCacheColorspace() method is:
2531%
2532% Colorspace GetPixelCacheColorspace(Cache cache)
2533%
2534% A description of each parameter follows:
2535%
2536% o cache: the pixel cache.
2537%
2538*/
2539MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
2540{
2541 CacheInfo
2542 *cache_info;
2543
2544 assert(cache != (Cache) NULL);
2545 cache_info=(CacheInfo *) cache;
2546 assert(cache_info->signature == MagickSignature);
2547 if (cache_info->debug != MagickFalse)
2548 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2549 cache_info->filename);
2550 return(cache_info->colorspace);
2551}
2552
2553/*
2554%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2555% %
2556% %
2557% %
2558+ G e t P i x e l C a c h e M e t h o d s %
2559% %
2560% %
2561% %
2562%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2563%
2564% GetPixelCacheMethods() initializes the CacheMethods structure.
2565%
2566% The format of the GetPixelCacheMethods() method is:
2567%
2568% void GetPixelCacheMethods(CacheMethods *cache_methods)
2569%
2570% A description of each parameter follows:
2571%
2572% o cache_methods: Specifies a pointer to a CacheMethods structure.
2573%
2574*/
2575MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
2576{
2577 assert(cache_methods != (CacheMethods *) NULL);
2578 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2579 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2580 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2581 cache_methods->get_virtual_indexes_from_handler=GetVirtualIndexesFromCache;
2582 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2583 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2584 cache_methods->get_authentic_indexes_from_handler=
2585 GetAuthenticIndexesFromCache;
2586 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2587 cache_methods->get_one_authentic_pixel_from_handler=
2588 GetOneAuthenticPixelFromCache;
2589 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2590 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2591 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2592}
2593
2594/*
2595%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2596% %
2597% %
2598% %
2599+ G e t P i x e l C a c h e N e x u s E x t e n t %
2600% %
2601% %
2602% %
2603%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2604%
2605% GetPixelCacheNexusExtent() returns the extent of the pixels associated with
2606% the last call to SetPixelCacheNexusPixels() or GetPixelCacheNexusPixels().
2607%
2608% The format of the GetPixelCacheNexusExtent() method is:
2609%
2610% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2611% NexusInfo *nexus_info)
2612%
2613% A description of each parameter follows:
2614%
2615% o nexus_info: the nexus info.
2616%
2617*/
2618MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2619 NexusInfo *nexus_info)
2620{
2621 CacheInfo
2622 *cache_info;
2623
2624 MagickSizeType
2625 extent;
2626
cristye7cc7cf2010-09-21 13:26:47 +00002627 assert(cache != (const Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002628 cache_info=(CacheInfo *) cache;
2629 assert(cache_info->signature == MagickSignature);
2630 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2631 if (extent == 0)
2632 return((MagickSizeType) cache_info->columns*cache_info->rows);
2633 return(extent);
2634}
2635
2636/*
2637%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2638% %
2639% %
2640% %
2641+ 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 %
2642% %
2643% %
2644% %
2645%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2646%
2647% GetPixelCacheNexusIndexes() returns the indexes associated with the
2648% specified cache nexus.
2649%
2650% The format of the GetPixelCacheNexusIndexes() method is:
2651%
2652% IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2653% NexusInfo *nexus_info)
2654%
2655% A description of each parameter follows:
2656%
2657% o cache: the pixel cache.
2658%
2659% o nexus_info: the cache nexus to return the colormap indexes.
2660%
2661*/
2662MagickExport IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2663 NexusInfo *nexus_info)
2664{
2665 CacheInfo
2666 *cache_info;
2667
cristye7cc7cf2010-09-21 13:26:47 +00002668 assert(cache != (const Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002669 cache_info=(CacheInfo *) cache;
2670 assert(cache_info->signature == MagickSignature);
2671 if (cache_info->storage_class == UndefinedClass)
2672 return((IndexPacket *) NULL);
2673 return(nexus_info->indexes);
2674}
2675
2676/*
2677%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2678% %
2679% %
2680% %
2681+ G e t P i x e l C a c h e N e x u s P i x e l s %
2682% %
2683% %
2684% %
2685%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2686%
2687% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2688% cache nexus.
2689%
2690% The format of the GetPixelCacheNexusPixels() method is:
2691%
2692% PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2693% NexusInfo *nexus_info)
2694%
2695% A description of each parameter follows:
2696%
2697% o cache: the pixel cache.
2698%
2699% o nexus_info: the cache nexus to return the pixels.
2700%
2701*/
2702MagickExport PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2703 NexusInfo *nexus_info)
2704{
2705 CacheInfo
2706 *cache_info;
2707
cristye7cc7cf2010-09-21 13:26:47 +00002708 assert(cache != (const Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002709 cache_info=(CacheInfo *) cache;
2710 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002711 if (cache_info->storage_class == UndefinedClass)
2712 return((PixelPacket *) NULL);
2713 return(nexus_info->pixels);
2714}
2715
2716/*
2717%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2718% %
2719% %
2720% %
cristy056ba772010-01-02 23:33:54 +00002721+ G e t P i x e l C a c h e P i x e l s %
2722% %
2723% %
2724% %
2725%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2726%
2727% GetPixelCachePixels() returns the pixels associated with the specified image.
2728%
2729% The format of the GetPixelCachePixels() method is:
2730%
cristyf84a1932010-01-03 18:00:18 +00002731% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2732% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002733%
2734% A description of each parameter follows:
2735%
2736% o image: the image.
2737%
2738% o length: the pixel cache length.
2739%
cristyf84a1932010-01-03 18:00:18 +00002740% o exception: return any errors or warnings in this structure.
2741%
cristy056ba772010-01-02 23:33:54 +00002742*/
cristyf84a1932010-01-03 18:00:18 +00002743MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2744 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002745{
2746 CacheInfo
2747 *cache_info;
2748
2749 assert(image != (const Image *) NULL);
2750 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002751 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00002752 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002753 assert(cache_info->signature == MagickSignature);
2754 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002755 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002756 return((void *) NULL);
2757 *length=cache_info->length;
2758 return((void *) cache_info->pixels);
2759}
2760
2761/*
2762%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2763% %
2764% %
2765% %
cristyb32b90a2009-09-07 21:45:48 +00002766+ 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 +00002767% %
2768% %
2769% %
2770%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2771%
2772% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2773%
2774% The format of the GetPixelCacheStorageClass() method is:
2775%
2776% ClassType GetPixelCacheStorageClass(Cache cache)
2777%
2778% A description of each parameter follows:
2779%
2780% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2781%
2782% o cache: the pixel cache.
2783%
2784*/
2785MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
2786{
2787 CacheInfo
2788 *cache_info;
2789
2790 assert(cache != (Cache) NULL);
2791 cache_info=(CacheInfo *) cache;
2792 assert(cache_info->signature == MagickSignature);
2793 if (cache_info->debug != MagickFalse)
2794 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2795 cache_info->filename);
2796 return(cache_info->storage_class);
2797}
2798
2799/*
2800%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2801% %
2802% %
2803% %
cristyb32b90a2009-09-07 21:45:48 +00002804+ G e t P i x e l C a c h e T i l e S i z e %
2805% %
2806% %
2807% %
2808%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2809%
2810% GetPixelCacheTileSize() returns the pixel cache tile size.
2811%
2812% The format of the GetPixelCacheTileSize() method is:
2813%
cristybb503372010-05-27 20:51:26 +00002814% void GetPixelCacheTileSize(const Image *image,size_t *width,
2815% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002816%
2817% A description of each parameter follows:
2818%
2819% o image: the image.
2820%
2821% o width: the optimize cache tile width in pixels.
2822%
2823% o height: the optimize cache tile height in pixels.
2824%
2825*/
cristybb503372010-05-27 20:51:26 +00002826MagickExport void GetPixelCacheTileSize(const Image *image,size_t *width,
2827 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002828{
cristyb32b90a2009-09-07 21:45:48 +00002829 assert(image != (Image *) NULL);
2830 assert(image->signature == MagickSignature);
2831 if (image->debug != MagickFalse)
2832 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristyb32b90a2009-09-07 21:45:48 +00002833 *width=2048UL/sizeof(PixelPacket);
2834 if (GetPixelCacheType(image) == DiskCache)
cristydaa97692009-09-13 02:10:35 +00002835 *width=8192UL/sizeof(PixelPacket);
cristyb32b90a2009-09-07 21:45:48 +00002836 *height=(*width);
2837}
2838
2839/*
2840%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2841% %
2842% %
2843% %
2844+ G e t P i x e l C a c h e T y p e %
2845% %
2846% %
2847% %
2848%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2849%
2850% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2851%
2852% The format of the GetPixelCacheType() method is:
2853%
2854% CacheType GetPixelCacheType(const Image *image)
2855%
2856% A description of each parameter follows:
2857%
2858% o image: the image.
2859%
2860*/
2861MagickExport CacheType GetPixelCacheType(const Image *image)
2862{
2863 CacheInfo
2864 *cache_info;
2865
2866 assert(image != (Image *) NULL);
2867 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002868 assert(image->cache != (Cache) NULL);
2869 cache_info=(CacheInfo *) image->cache;
2870 assert(cache_info->signature == MagickSignature);
2871 return(cache_info->type);
2872}
2873
2874/*
2875%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2876% %
2877% %
2878% %
cristy3ed852e2009-09-05 21:47:34 +00002879+ 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 %
2880% %
2881% %
2882% %
2883%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2884%
2885% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2886% pixel cache. A virtual pixel is any pixel access that is outside the
2887% boundaries of the image cache.
2888%
2889% The format of the GetPixelCacheVirtualMethod() method is:
2890%
2891% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2892%
2893% A description of each parameter follows:
2894%
2895% o image: the image.
2896%
2897*/
2898MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2899{
2900 CacheInfo
2901 *cache_info;
2902
2903 assert(image != (Image *) NULL);
2904 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002905 assert(image->cache != (Cache) NULL);
2906 cache_info=(CacheInfo *) image->cache;
2907 assert(cache_info->signature == MagickSignature);
2908 return(cache_info->virtual_pixel_method);
2909}
2910
2911/*
2912%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2913% %
2914% %
2915% %
2916+ 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 %
2917% %
2918% %
2919% %
2920%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2921%
2922% GetVirtualIndexesFromCache() returns the indexes associated with the last
2923% call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2924%
2925% The format of the GetVirtualIndexesFromCache() method is:
2926%
2927% IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2928%
2929% A description of each parameter follows:
2930%
2931% o image: the image.
2932%
2933*/
2934static const IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2935{
2936 CacheInfo
2937 *cache_info;
2938
cristy5c9e6f22010-09-17 17:31:01 +00002939 const int
2940 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002941
cristye7cc7cf2010-09-21 13:26:47 +00002942 assert(image != (const Image *) NULL);
2943 assert(image->signature == MagickSignature);
2944 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002945 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002946 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002947 assert(id < (int) cache_info->number_threads);
cristye7cc7cf2010-09-21 13:26:47 +00002948 return(GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00002949}
2950
2951/*
2952%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2953% %
2954% %
2955% %
2956+ 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 %
2957% %
2958% %
2959% %
2960%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2961%
2962% GetVirtualIndexesFromNexus() returns the indexes associated with the
2963% specified cache nexus.
2964%
2965% The format of the GetVirtualIndexesFromNexus() method is:
2966%
2967% const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2968% NexusInfo *nexus_info)
2969%
2970% A description of each parameter follows:
2971%
2972% o cache: the pixel cache.
2973%
2974% o nexus_info: the cache nexus to return the colormap indexes.
2975%
2976*/
2977MagickExport const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2978 NexusInfo *nexus_info)
2979{
2980 CacheInfo
2981 *cache_info;
2982
cristye7cc7cf2010-09-21 13:26:47 +00002983 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002984 cache_info=(CacheInfo *) cache;
2985 assert(cache_info->signature == MagickSignature);
2986 if (cache_info->storage_class == UndefinedClass)
2987 return((IndexPacket *) NULL);
2988 return(nexus_info->indexes);
2989}
2990
2991/*
2992%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2993% %
2994% %
2995% %
2996% G e t V i r t u a l I n d e x Q u e u e %
2997% %
2998% %
2999% %
3000%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3001%
3002% GetVirtualIndexQueue() returns the virtual black channel or the
3003% colormap indexes associated with the last call to QueueAuthenticPixels() or
3004% GetVirtualPixels(). NULL is returned if the black channel or colormap
3005% indexes are not available.
3006%
3007% The format of the GetVirtualIndexQueue() method is:
3008%
3009% const IndexPacket *GetVirtualIndexQueue(const Image *image)
3010%
3011% A description of each parameter follows:
3012%
3013% o image: the image.
3014%
3015*/
3016MagickExport const IndexPacket *GetVirtualIndexQueue(const Image *image)
3017{
3018 CacheInfo
3019 *cache_info;
3020
cristy2036f5c2010-09-19 21:18:17 +00003021 const int
3022 id = GetOpenMPThreadId();
3023
cristy3ed852e2009-09-05 21:47:34 +00003024 assert(image != (const Image *) NULL);
3025 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003026 assert(image->cache != (Cache) NULL);
3027 cache_info=(CacheInfo *) image->cache;
3028 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003029 if (cache_info->methods.get_virtual_indexes_from_handler !=
3030 (GetVirtualIndexesFromHandler) NULL)
3031 return(cache_info->methods.get_virtual_indexes_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003032 assert(id < (int) cache_info->number_threads);
3033 return(GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003034}
3035
3036/*
3037%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3038% %
3039% %
3040% %
3041+ 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 %
3042% %
3043% %
3044% %
3045%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3046%
3047% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3048% pixel cache as defined by the geometry parameters. A pointer to the pixels
3049% is returned if the pixels are transferred, otherwise a NULL is returned.
3050%
3051% The format of the GetVirtualPixelsFromNexus() method is:
3052%
3053% PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003054% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00003055% const size_t columns,const size_t rows,NexusInfo *nexus_info,
3056% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003057%
3058% A description of each parameter follows:
3059%
3060% o image: the image.
3061%
3062% o virtual_pixel_method: the virtual pixel method.
3063%
3064% o x,y,columns,rows: These values define the perimeter of a region of
3065% pixels.
3066%
3067% o nexus_info: the cache nexus to acquire.
3068%
3069% o exception: return any errors or warnings in this structure.
3070%
3071*/
3072
cristybb503372010-05-27 20:51:26 +00003073static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003074 DitherMatrix[64] =
3075 {
3076 0, 48, 12, 60, 3, 51, 15, 63,
3077 32, 16, 44, 28, 35, 19, 47, 31,
3078 8, 56, 4, 52, 11, 59, 7, 55,
3079 40, 24, 36, 20, 43, 27, 39, 23,
3080 2, 50, 14, 62, 1, 49, 13, 61,
3081 34, 18, 46, 30, 33, 17, 45, 29,
3082 10, 58, 6, 54, 9, 57, 5, 53,
3083 42, 26, 38, 22, 41, 25, 37, 21
3084 };
3085
cristybb503372010-05-27 20:51:26 +00003086static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003087{
cristybb503372010-05-27 20:51:26 +00003088 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003089 index;
3090
3091 index=x+DitherMatrix[x & 0x07]-32L;
3092 if (index < 0L)
3093 return(0L);
cristybb503372010-05-27 20:51:26 +00003094 if (index >= (ssize_t) columns)
3095 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00003096 return(index);
3097}
3098
cristybb503372010-05-27 20:51:26 +00003099static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003100{
cristybb503372010-05-27 20:51:26 +00003101 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003102 index;
3103
3104 index=y+DitherMatrix[y & 0x07]-32L;
3105 if (index < 0L)
3106 return(0L);
cristybb503372010-05-27 20:51:26 +00003107 if (index >= (ssize_t) rows)
3108 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00003109 return(index);
3110}
3111
cristybb503372010-05-27 20:51:26 +00003112static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003113{
3114 if (x < 0L)
3115 return(0L);
cristybb503372010-05-27 20:51:26 +00003116 if (x >= (ssize_t) columns)
3117 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003118 return(x);
3119}
3120
cristybb503372010-05-27 20:51:26 +00003121static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003122{
3123 if (y < 0L)
3124 return(0L);
cristybb503372010-05-27 20:51:26 +00003125 if (y >= (ssize_t) rows)
3126 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003127 return(y);
3128}
3129
cristybb503372010-05-27 20:51:26 +00003130static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003131{
cristybb503372010-05-27 20:51:26 +00003132 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003133}
3134
cristybb503372010-05-27 20:51:26 +00003135static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003136{
cristybb503372010-05-27 20:51:26 +00003137 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003138}
3139
3140/*
3141 VirtualPixelModulo() computes the remainder of dividing offset by extent. It
3142 returns not only the quotient (tile the offset falls in) but also the positive
3143 remainer within that tile such that 0 <= remainder < extent. This method is
3144 essentially a ldiv() using a floored modulo division rather than the normal
3145 default truncated modulo division.
3146*/
cristybb503372010-05-27 20:51:26 +00003147static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3148 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003149{
3150 MagickModulo
3151 modulo;
3152
cristybb503372010-05-27 20:51:26 +00003153 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003154 if (offset < 0L)
3155 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003156 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003157 return(modulo);
3158}
3159
3160MagickExport const PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003161 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3162 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003163 ExceptionInfo *exception)
3164{
3165 CacheInfo
3166 *cache_info;
3167
cristyc3ec0d42010-04-07 01:18:08 +00003168 IndexPacket
3169 virtual_index;
3170
cristy3ed852e2009-09-05 21:47:34 +00003171 MagickOffsetType
3172 offset;
3173
3174 MagickSizeType
3175 length,
3176 number_pixels;
3177
3178 NexusInfo
3179 **virtual_nexus;
3180
3181 PixelPacket
3182 *pixels,
3183 virtual_pixel;
3184
3185 RectangleInfo
3186 region;
3187
3188 register const IndexPacket
cristyc3ec0d42010-04-07 01:18:08 +00003189 *restrict virtual_indexes;
cristy3ed852e2009-09-05 21:47:34 +00003190
3191 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003192 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003193
3194 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003195 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003196
cristye076a6e2010-08-15 19:59:43 +00003197 register PixelPacket
3198 *restrict q;
3199
cristybb503372010-05-27 20:51:26 +00003200 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003201 u,
3202 v;
3203
cristy3ed852e2009-09-05 21:47:34 +00003204 /*
3205 Acquire pixels.
3206 */
cristye7cc7cf2010-09-21 13:26:47 +00003207 assert(image != (const Image *) NULL);
3208 assert(image->signature == MagickSignature);
3209 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003210 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003211 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003212 if (cache_info->type == UndefinedCache)
cristy3ed852e2009-09-05 21:47:34 +00003213 return((const PixelPacket *) NULL);
3214 region.x=x;
3215 region.y=y;
3216 region.width=columns;
3217 region.height=rows;
3218 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
3219 if (pixels == (PixelPacket *) NULL)
3220 return((const PixelPacket *) NULL);
cristydf415c82010-03-11 16:47:50 +00003221 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3222 nexus_info->region.x;
3223 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3224 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003225 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3226 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003227 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3228 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003229 {
3230 MagickBooleanType
3231 status;
3232
3233 /*
3234 Pixel request is inside cache extents.
3235 */
3236 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
3237 return(pixels);
3238 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3239 if (status == MagickFalse)
3240 return((const PixelPacket *) NULL);
3241 if ((cache_info->storage_class == PseudoClass) ||
3242 (cache_info->colorspace == CMYKColorspace))
3243 {
3244 status=ReadPixelCacheIndexes(cache_info,nexus_info,exception);
3245 if (status == MagickFalse)
3246 return((const PixelPacket *) NULL);
3247 }
3248 return(pixels);
3249 }
3250 /*
3251 Pixel request is outside cache extents.
3252 */
3253 q=pixels;
3254 indexes=GetPixelCacheNexusIndexes(cache_info,nexus_info);
3255 virtual_nexus=AcquirePixelCacheNexus(1);
3256 if (virtual_nexus == (NexusInfo **) NULL)
3257 {
3258 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3259 "UnableToGetCacheNexus","`%s'",image->filename);
3260 return((const PixelPacket *) NULL);
3261 }
3262 switch (virtual_pixel_method)
3263 {
3264 case BlackVirtualPixelMethod:
3265 {
cristy4789f0d2010-01-10 00:01:06 +00003266 SetRedPixelComponent(&virtual_pixel,0);
3267 SetGreenPixelComponent(&virtual_pixel,0);
3268 SetBluePixelComponent(&virtual_pixel,0);
3269 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003270 break;
3271 }
3272 case GrayVirtualPixelMethod:
3273 {
cristy4789f0d2010-01-10 00:01:06 +00003274 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3275 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3276 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3277 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003278 break;
3279 }
3280 case TransparentVirtualPixelMethod:
3281 {
cristy4789f0d2010-01-10 00:01:06 +00003282 SetRedPixelComponent(&virtual_pixel,0);
3283 SetGreenPixelComponent(&virtual_pixel,0);
3284 SetBluePixelComponent(&virtual_pixel,0);
3285 SetOpacityPixelComponent(&virtual_pixel,TransparentOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003286 break;
3287 }
3288 case MaskVirtualPixelMethod:
3289 case WhiteVirtualPixelMethod:
3290 {
cristy4789f0d2010-01-10 00:01:06 +00003291 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3292 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3293 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3294 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003295 break;
3296 }
3297 default:
3298 {
3299 virtual_pixel=image->background_color;
3300 break;
3301 }
3302 }
cristyc3ec0d42010-04-07 01:18:08 +00003303 virtual_index=0;
cristybb503372010-05-27 20:51:26 +00003304 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003305 {
cristybb503372010-05-27 20:51:26 +00003306 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003307 {
3308 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003309 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003310 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3311 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003312 {
3313 MagickModulo
3314 x_modulo,
3315 y_modulo;
3316
3317 /*
3318 Transfer a single pixel.
3319 */
3320 length=(MagickSizeType) 1;
3321 switch (virtual_pixel_method)
3322 {
3323 case BackgroundVirtualPixelMethod:
3324 case ConstantVirtualPixelMethod:
3325 case BlackVirtualPixelMethod:
3326 case GrayVirtualPixelMethod:
3327 case TransparentVirtualPixelMethod:
3328 case MaskVirtualPixelMethod:
3329 case WhiteVirtualPixelMethod:
3330 {
3331 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003332 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003333 break;
3334 }
3335 case EdgeVirtualPixelMethod:
3336 default:
3337 {
3338 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003339 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003340 1UL,1UL,virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003341 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3342 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003343 break;
3344 }
3345 case RandomVirtualPixelMethod:
3346 {
3347 if (cache_info->random_info == (RandomInfo *) NULL)
3348 cache_info->random_info=AcquireRandomInfo();
3349 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003350 RandomX(cache_info->random_info,cache_info->columns),
3351 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003352 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003353 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3354 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003355 break;
3356 }
3357 case DitherVirtualPixelMethod:
3358 {
3359 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003360 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003361 1UL,1UL,virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003362 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3363 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003364 break;
3365 }
3366 case TileVirtualPixelMethod:
3367 {
3368 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3369 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3370 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3371 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3372 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003373 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3374 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003375 break;
3376 }
3377 case MirrorVirtualPixelMethod:
3378 {
3379 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3380 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003381 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003382 x_modulo.remainder-1L;
3383 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3384 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003385 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003386 y_modulo.remainder-1L;
3387 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3388 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3389 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003390 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3391 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003392 break;
3393 }
3394 case CheckerTileVirtualPixelMethod:
3395 {
3396 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3397 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3398 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3399 {
3400 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003401 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003402 break;
3403 }
3404 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3405 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3406 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003407 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3408 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003409 break;
3410 }
3411 case HorizontalTileVirtualPixelMethod:
3412 {
cristybb503372010-05-27 20:51:26 +00003413 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003414 {
3415 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003416 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003417 break;
3418 }
3419 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3420 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3421 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3422 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3423 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003424 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3425 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003426 break;
3427 }
3428 case VerticalTileVirtualPixelMethod:
3429 {
cristybb503372010-05-27 20:51:26 +00003430 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
cristy3ed852e2009-09-05 21:47:34 +00003431 {
3432 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003433 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003434 break;
3435 }
3436 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3437 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3438 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3439 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3440 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003441 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3442 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003443 break;
3444 }
3445 case HorizontalTileEdgeVirtualPixelMethod:
3446 {
3447 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3448 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003449 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003450 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003451 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3452 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003453 break;
3454 }
3455 case VerticalTileEdgeVirtualPixelMethod:
3456 {
3457 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3458 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003459 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003460 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003461 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3462 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003463 break;
3464 }
3465 }
3466 if (p == (const PixelPacket *) NULL)
3467 break;
3468 *q++=(*p);
cristyc3ec0d42010-04-07 01:18:08 +00003469 if ((indexes != (IndexPacket *) NULL) &&
3470 (virtual_indexes != (const IndexPacket *) NULL))
3471 *indexes++=(*virtual_indexes);
cristy3ed852e2009-09-05 21:47:34 +00003472 continue;
3473 }
3474 /*
3475 Transfer a run of pixels.
3476 */
3477 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,
cristybb503372010-05-27 20:51:26 +00003478 (size_t) length,1UL,virtual_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003479 if (p == (const PixelPacket *) NULL)
3480 break;
cristyc3ec0d42010-04-07 01:18:08 +00003481 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,virtual_nexus[0]);
cristy8f036fe2010-09-18 02:02:00 +00003482 (void) memcpy(q,p,(size_t) length*sizeof(*p));
cristy3ed852e2009-09-05 21:47:34 +00003483 q+=length;
cristyc3ec0d42010-04-07 01:18:08 +00003484 if ((indexes != (IndexPacket *) NULL) &&
3485 (virtual_indexes != (const IndexPacket *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003486 {
cristy8f036fe2010-09-18 02:02:00 +00003487 (void) memcpy(indexes,virtual_indexes,(size_t) length*
cristyc3ec0d42010-04-07 01:18:08 +00003488 sizeof(*virtual_indexes));
3489 indexes+=length;
cristy3ed852e2009-09-05 21:47:34 +00003490 }
3491 }
3492 }
3493 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3494 return(pixels);
3495}
3496
3497/*
3498%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3499% %
3500% %
3501% %
3502+ G e t V i r t u a l P i x e l C a c h e %
3503% %
3504% %
3505% %
3506%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3507%
3508% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3509% cache as defined by the geometry parameters. A pointer to the pixels
3510% is returned if the pixels are transferred, otherwise a NULL is returned.
3511%
3512% The format of the GetVirtualPixelCache() method is:
3513%
3514% const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003515% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3516% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003517% ExceptionInfo *exception)
3518%
3519% A description of each parameter follows:
3520%
3521% o image: the image.
3522%
3523% o virtual_pixel_method: the virtual pixel method.
3524%
3525% o x,y,columns,rows: These values define the perimeter of a region of
3526% pixels.
3527%
3528% o exception: return any errors or warnings in this structure.
3529%
3530*/
3531static const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003532 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3533 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003534{
3535 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003536 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003537
cristy5c9e6f22010-09-17 17:31:01 +00003538 const int
3539 id = GetOpenMPThreadId();
3540
cristye7cc7cf2010-09-21 13:26:47 +00003541 assert(image != (const Image *) NULL);
3542 assert(image->signature == MagickSignature);
3543 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003544 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003545 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003546 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003547 return(GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3548 cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00003549}
3550
3551/*
3552%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3553% %
3554% %
3555% %
3556% G e t V i r t u a l P i x e l Q u e u e %
3557% %
3558% %
3559% %
3560%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3561%
3562% GetVirtualPixelQueue() returns the virtual pixels associated with the
3563% last call to QueueAuthenticPixels() or GetVirtualPixels().
3564%
3565% The format of the GetVirtualPixelQueue() method is:
3566%
3567% const PixelPacket *GetVirtualPixelQueue(const Image image)
3568%
3569% A description of each parameter follows:
3570%
3571% o image: the image.
3572%
3573*/
3574MagickExport const PixelPacket *GetVirtualPixelQueue(const Image *image)
3575{
3576 CacheInfo
3577 *cache_info;
3578
cristy2036f5c2010-09-19 21:18:17 +00003579 const int
3580 id = GetOpenMPThreadId();
3581
cristy3ed852e2009-09-05 21:47:34 +00003582 assert(image != (const Image *) NULL);
3583 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003584 assert(image->cache != (Cache) NULL);
3585 cache_info=(CacheInfo *) image->cache;
3586 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003587 if (cache_info->methods.get_virtual_pixels_handler !=
3588 (GetVirtualPixelsHandler) NULL)
3589 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003590 assert(id < (int) cache_info->number_threads);
3591 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003592}
3593
3594/*
3595%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3596% %
3597% %
3598% %
3599% G e t V i r t u a l P i x e l s %
3600% %
3601% %
3602% %
3603%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3604%
3605% GetVirtualPixels() returns an immutable pixel region. If the
3606% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003607% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003608% copy of the pixels or it may point to the original pixels in memory.
3609% Performance is maximized if the selected region is part of one row, or one
3610% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003611% (without a copy) if the image is in memory, or in a memory-mapped file. The
3612% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003613%
3614% Pixels accessed via the returned pointer represent a simple array of type
3615% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
3616% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to access
3617% the black color component or to obtain the colormap indexes (of type
3618% IndexPacket) corresponding to the region.
3619%
3620% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3621%
3622% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3623% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3624% GetCacheViewAuthenticPixels() instead.
3625%
3626% The format of the GetVirtualPixels() method is:
3627%
cristybb503372010-05-27 20:51:26 +00003628% const PixelPacket *GetVirtualPixels(const Image *image,const ssize_t x,
3629% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003630% ExceptionInfo *exception)
3631%
3632% A description of each parameter follows:
3633%
3634% o image: the image.
3635%
3636% o x,y,columns,rows: These values define the perimeter of a region of
3637% pixels.
3638%
3639% o exception: return any errors or warnings in this structure.
3640%
3641*/
3642MagickExport const PixelPacket *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003643 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3644 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003645{
3646 CacheInfo
3647 *cache_info;
3648
cristy2036f5c2010-09-19 21:18:17 +00003649 const int
3650 id = GetOpenMPThreadId();
3651
cristy3ed852e2009-09-05 21:47:34 +00003652 assert(image != (const Image *) NULL);
3653 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003654 assert(image->cache != (Cache) NULL);
3655 cache_info=(CacheInfo *) image->cache;
3656 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003657 if (cache_info->methods.get_virtual_pixel_handler !=
3658 (GetVirtualPixelHandler) NULL)
3659 return(cache_info->methods.get_virtual_pixel_handler(image,
3660 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003661 assert(id < (int) cache_info->number_threads);
3662 return(GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3663 columns,rows,cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00003664}
3665
3666/*
3667%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3668% %
3669% %
3670% %
3671+ 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 %
3672% %
3673% %
3674% %
3675%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3676%
3677% GetVirtualPixelsCache() returns the pixels associated with the last call
3678% to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3679%
3680% The format of the GetVirtualPixelsCache() method is:
3681%
3682% PixelPacket *GetVirtualPixelsCache(const Image *image)
3683%
3684% A description of each parameter follows:
3685%
3686% o image: the image.
3687%
3688*/
3689static const PixelPacket *GetVirtualPixelsCache(const Image *image)
3690{
3691 CacheInfo
3692 *cache_info;
3693
cristy5c9e6f22010-09-17 17:31:01 +00003694 const int
3695 id = GetOpenMPThreadId();
3696
cristye7cc7cf2010-09-21 13:26:47 +00003697 assert(image != (const Image *) NULL);
3698 assert(image->signature == MagickSignature);
3699 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003700 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003701 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003702 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003703 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003704}
3705
3706/*
3707%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3708% %
3709% %
3710% %
3711+ G e t V i r t u a l P i x e l s N e x u s %
3712% %
3713% %
3714% %
3715%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3716%
3717% GetVirtualPixelsNexus() returns the pixels associated with the specified
3718% cache nexus.
3719%
3720% The format of the GetVirtualPixelsNexus() method is:
3721%
3722% const IndexPacket *GetVirtualPixelsNexus(const Cache cache,
3723% NexusInfo *nexus_info)
3724%
3725% A description of each parameter follows:
3726%
3727% o cache: the pixel cache.
3728%
3729% o nexus_info: the cache nexus to return the colormap pixels.
3730%
3731*/
3732MagickExport const PixelPacket *GetVirtualPixelsNexus(const Cache cache,
3733 NexusInfo *nexus_info)
3734{
3735 CacheInfo
3736 *cache_info;
3737
cristye7cc7cf2010-09-21 13:26:47 +00003738 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003739 cache_info=(CacheInfo *) cache;
3740 assert(cache_info->signature == MagickSignature);
3741 if (cache_info->storage_class == UndefinedClass)
3742 return((PixelPacket *) NULL);
3743 return((const PixelPacket *) nexus_info->pixels);
3744}
3745
3746/*
3747%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3748% %
3749% %
3750% %
3751+ M a s k P i x e l C a c h e N e x u s %
3752% %
3753% %
3754% %
3755%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3756%
3757% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3758% The method returns MagickTrue if the pixel region is masked, otherwise
3759% MagickFalse.
3760%
3761% The format of the MaskPixelCacheNexus() method is:
3762%
3763% MagickBooleanType MaskPixelCacheNexus(Image *image,
3764% NexusInfo *nexus_info,ExceptionInfo *exception)
3765%
3766% A description of each parameter follows:
3767%
3768% o image: the image.
3769%
3770% o nexus_info: the cache nexus to clip.
3771%
3772% o exception: return any errors or warnings in this structure.
3773%
3774*/
3775
3776static inline void MagickPixelCompositeMask(const MagickPixelPacket *p,
3777 const MagickRealType alpha,const MagickPixelPacket *q,
3778 const MagickRealType beta,MagickPixelPacket *composite)
3779{
3780 MagickRealType
3781 gamma;
3782
3783 if (alpha == TransparentOpacity)
3784 {
3785 *composite=(*q);
3786 return;
3787 }
3788 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3789 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3790 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3791 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3792 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3793 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3794 composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
3795}
3796
3797static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3798 ExceptionInfo *exception)
3799{
3800 CacheInfo
3801 *cache_info;
3802
3803 MagickPixelPacket
3804 alpha,
3805 beta;
3806
3807 MagickSizeType
3808 number_pixels;
3809
3810 NexusInfo
3811 **clip_nexus,
3812 **image_nexus;
3813
3814 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003815 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003816
3817 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003818 *restrict nexus_indexes,
3819 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003820
cristy3ed852e2009-09-05 21:47:34 +00003821 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003822 *restrict p,
3823 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003824
cristye076a6e2010-08-15 19:59:43 +00003825 register ssize_t
3826 i;
3827
cristy3ed852e2009-09-05 21:47:34 +00003828 /*
3829 Apply clip mask.
3830 */
3831 if (image->debug != MagickFalse)
3832 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3833 if (image->mask == (Image *) NULL)
3834 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +00003835 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00003836 if (cache_info == (Cache) NULL)
3837 return(MagickFalse);
3838 image_nexus=AcquirePixelCacheNexus(1);
3839 clip_nexus=AcquirePixelCacheNexus(1);
3840 if ((image_nexus == (NexusInfo **) NULL) ||
3841 (clip_nexus == (NexusInfo **) NULL))
3842 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy09449f72010-01-23 03:08:36 +00003843 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,
3844 nexus_info->region.y,nexus_info->region.width,nexus_info->region.height,
3845 image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003846 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
3847 q=nexus_info->pixels;
3848 nexus_indexes=nexus_info->indexes;
3849 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3850 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3851 nexus_info->region.height,clip_nexus[0],&image->exception);
3852 GetMagickPixelPacket(image,&alpha);
3853 GetMagickPixelPacket(image,&beta);
3854 number_pixels=(MagickSizeType) nexus_info->region.width*
3855 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +00003856 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +00003857 {
3858 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
3859 break;
3860 SetMagickPixelPacket(image,p,indexes+i,&alpha);
3861 SetMagickPixelPacket(image,q,nexus_indexes+i,&beta);
3862 MagickPixelCompositeMask(&beta,(MagickRealType) PixelIntensityToQuantum(r),
3863 &alpha,alpha.opacity,&beta);
cristyce70c172010-01-07 17:15:30 +00003864 q->red=ClampToQuantum(beta.red);
3865 q->green=ClampToQuantum(beta.green);
3866 q->blue=ClampToQuantum(beta.blue);
3867 q->opacity=ClampToQuantum(beta.opacity);
cristy3ed852e2009-09-05 21:47:34 +00003868 if (cache_info->active_index_channel != MagickFalse)
3869 nexus_indexes[i]=indexes[i];
3870 p++;
3871 q++;
3872 r++;
3873 }
3874 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3875 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +00003876 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003877 return(MagickFalse);
3878 return(MagickTrue);
3879}
3880
3881/*
3882%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3883% %
3884% %
3885% %
3886+ O p e n P i x e l C a c h e %
3887% %
3888% %
3889% %
3890%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3891%
3892% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3893% dimensions, allocating space for the image pixels and optionally the
3894% colormap indexes, and memory mapping the cache if it is disk based. The
3895% cache nexus array is initialized as well.
3896%
3897% The format of the OpenPixelCache() method is:
3898%
3899% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3900% ExceptionInfo *exception)
3901%
3902% A description of each parameter follows:
3903%
3904% o image: the image.
3905%
3906% o mode: ReadMode, WriteMode, or IOMode.
3907%
3908% o exception: return any errors or warnings in this structure.
3909%
3910*/
3911
cristyd43a46b2010-01-21 02:13:41 +00003912static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003913{
3914 cache_info->mapped=MagickFalse;
3915 cache_info->pixels=(PixelPacket *) AcquireMagickMemory((size_t)
3916 cache_info->length);
3917 if (cache_info->pixels == (PixelPacket *) NULL)
3918 {
3919 cache_info->mapped=MagickTrue;
3920 cache_info->pixels=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
3921 cache_info->length);
3922 }
3923}
3924
3925static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3926{
3927 CacheInfo
3928 *cache_info;
3929
3930 MagickOffsetType
3931 count,
3932 extent,
3933 offset;
3934
3935 cache_info=(CacheInfo *) image->cache;
3936 if (image->debug != MagickFalse)
3937 {
3938 char
3939 format[MaxTextExtent],
3940 message[MaxTextExtent];
3941
cristyb9080c92009-12-01 20:13:26 +00003942 (void) FormatMagickSize(length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00003943 (void) FormatMagickString(message,MaxTextExtent,
cristy2ce15c92010-03-12 14:03:41 +00003944 "extend %s (%s[%d], disk, %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003945 cache_info->cache_filename,cache_info->file,format);
3946 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3947 }
3948 if (length != (MagickSizeType) ((MagickOffsetType) length))
3949 return(MagickFalse);
3950 extent=(MagickOffsetType) MagickSeek(cache_info->file,0,SEEK_END);
3951 if (extent < 0)
3952 return(MagickFalse);
3953 if ((MagickSizeType) extent >= length)
3954 return(MagickTrue);
3955 offset=(MagickOffsetType) length-1;
3956 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3957 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3958}
3959
3960static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3961 ExceptionInfo *exception)
3962{
3963 char
3964 format[MaxTextExtent],
3965 message[MaxTextExtent];
3966
3967 CacheInfo
3968 *cache_info,
3969 source_info;
3970
3971 MagickSizeType
3972 length,
3973 number_pixels;
3974
3975 MagickStatusType
3976 status;
3977
3978 size_t
cristye076a6e2010-08-15 19:59:43 +00003979 columns,
cristy3ed852e2009-09-05 21:47:34 +00003980 packet_size;
3981
cristye7cc7cf2010-09-21 13:26:47 +00003982 assert(image != (const Image *) NULL);
3983 assert(image->signature == MagickSignature);
3984 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003985 if (image->debug != MagickFalse)
3986 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3987 if ((image->columns == 0) || (image->rows == 0))
3988 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3989 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003990 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003991 source_info=(*cache_info);
3992 source_info.file=(-1);
cristye8c25f92010-06-03 00:53:06 +00003993 (void) FormatMagickString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3994 image->filename,(double) GetImageIndexInList(image));
cristy87528ea2009-09-10 14:53:56 +00003995 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +00003996 cache_info->rows=image->rows;
3997 cache_info->columns=image->columns;
3998 cache_info->active_index_channel=((image->storage_class == PseudoClass) ||
3999 (image->colorspace == CMYKColorspace)) ? MagickTrue : MagickFalse;
cristy73724512010-04-12 14:43:14 +00004000 if (image->ping != MagickFalse)
4001 {
4002 cache_info->storage_class=image->storage_class;
4003 cache_info->colorspace=image->colorspace;
4004 cache_info->type=PingCache;
4005 cache_info->pixels=(PixelPacket *) NULL;
4006 cache_info->indexes=(IndexPacket *) NULL;
4007 cache_info->length=0;
4008 return(MagickTrue);
4009 }
cristy3ed852e2009-09-05 21:47:34 +00004010 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4011 packet_size=sizeof(PixelPacket);
4012 if (cache_info->active_index_channel != MagickFalse)
4013 packet_size+=sizeof(IndexPacket);
4014 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00004015 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00004016 if (cache_info->columns != columns)
4017 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4018 image->filename);
4019 cache_info->length=length;
4020 status=AcquireMagickResource(AreaResource,cache_info->length);
4021 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4022 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4023 {
4024 status=AcquireMagickResource(MemoryResource,cache_info->length);
4025 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4026 (cache_info->type == MemoryCache))
4027 {
cristyd43a46b2010-01-21 02:13:41 +00004028 AllocatePixelCachePixels(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004029 if (cache_info->pixels == (PixelPacket *) NULL)
4030 cache_info->pixels=source_info.pixels;
4031 else
4032 {
4033 /*
4034 Create memory pixel cache.
4035 */
4036 if (image->debug != MagickFalse)
4037 {
cristy97e7a572009-12-05 15:07:53 +00004038 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004039 format);
cristy3ed852e2009-09-05 21:47:34 +00004040 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004041 "open %s (%s memory, %.20gx%.20g %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00004042 cache_info->mapped != MagickFalse ? "anonymous" : "heap",
cristye8c25f92010-06-03 00:53:06 +00004043 (double) cache_info->columns,(double) cache_info->rows,
4044 format);
cristy3ed852e2009-09-05 21:47:34 +00004045 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4046 message);
4047 }
4048 cache_info->storage_class=image->storage_class;
4049 cache_info->colorspace=image->colorspace;
4050 cache_info->type=MemoryCache;
4051 cache_info->indexes=(IndexPacket *) NULL;
4052 if (cache_info->active_index_channel != MagickFalse)
4053 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4054 number_pixels);
4055 if (source_info.storage_class != UndefinedClass)
4056 {
4057 status|=ClonePixelCachePixels(cache_info,&source_info,
4058 exception);
4059 RelinquishPixelCachePixels(&source_info);
4060 }
4061 return(MagickTrue);
4062 }
4063 }
4064 RelinquishMagickResource(MemoryResource,cache_info->length);
4065 }
4066 /*
4067 Create pixel cache on disk.
4068 */
4069 status=AcquireMagickResource(DiskResource,cache_info->length);
4070 if (status == MagickFalse)
4071 {
4072 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4073 "CacheResourcesExhausted","`%s'",image->filename);
4074 return(MagickFalse);
4075 }
4076 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4077 {
4078 RelinquishMagickResource(DiskResource,cache_info->length);
4079 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4080 image->filename);
4081 return(MagickFalse);
4082 }
4083 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4084 cache_info->length);
4085 if (status == MagickFalse)
4086 {
4087 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4088 image->filename);
4089 return(MagickFalse);
4090 }
4091 cache_info->storage_class=image->storage_class;
4092 cache_info->colorspace=image->colorspace;
4093 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4094 status=AcquireMagickResource(AreaResource,cache_info->length);
4095 if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4096 cache_info->type=DiskCache;
4097 else
4098 {
4099 status=AcquireMagickResource(MapResource,cache_info->length);
4100 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4101 (cache_info->type != MemoryCache))
4102 cache_info->type=DiskCache;
4103 else
4104 {
4105 cache_info->pixels=(PixelPacket *) MapBlob(cache_info->file,mode,
4106 cache_info->offset,(size_t) cache_info->length);
4107 if (cache_info->pixels == (PixelPacket *) NULL)
4108 {
4109 cache_info->pixels=source_info.pixels;
4110 cache_info->type=DiskCache;
4111 }
4112 else
4113 {
4114 /*
4115 Create file-backed memory-mapped pixel cache.
4116 */
4117 (void) ClosePixelCacheOnDisk(cache_info);
4118 cache_info->type=MapCache;
4119 cache_info->mapped=MagickTrue;
4120 cache_info->indexes=(IndexPacket *) NULL;
4121 if (cache_info->active_index_channel != MagickFalse)
4122 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4123 number_pixels);
4124 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4125 {
4126 status=ClonePixelCachePixels(cache_info,&source_info,
4127 exception);
4128 RelinquishPixelCachePixels(&source_info);
4129 }
4130 if (image->debug != MagickFalse)
4131 {
cristy97e7a572009-12-05 15:07:53 +00004132 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004133 format);
cristy3ed852e2009-09-05 21:47:34 +00004134 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004135 "open %s (%s[%d], memory-mapped, %.20gx%.20g %sB)",
cristy3ed852e2009-09-05 21:47:34 +00004136 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004137 cache_info->file,(double) cache_info->columns,(double)
4138 cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004139 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4140 message);
4141 }
4142 return(MagickTrue);
4143 }
4144 }
4145 RelinquishMagickResource(MapResource,cache_info->length);
4146 }
4147 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4148 {
4149 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4150 RelinquishPixelCachePixels(&source_info);
4151 }
4152 if (image->debug != MagickFalse)
4153 {
cristyb9080c92009-12-01 20:13:26 +00004154 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00004155 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004156 "open %s (%s[%d], disk, %.20gx%.20g %sB)",cache_info->filename,
4157 cache_info->cache_filename,cache_info->file,(double)
4158 cache_info->columns,(double) cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004159 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4160 }
4161 return(MagickTrue);
4162}
4163
4164/*
4165%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4166% %
4167% %
4168% %
4169+ P e r s i s t P i x e l C a c h e %
4170% %
4171% %
4172% %
4173%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4174%
4175% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4176% persistent pixel cache is one that resides on disk and is not destroyed
4177% when the program exits.
4178%
4179% The format of the PersistPixelCache() method is:
4180%
4181% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4182% const MagickBooleanType attach,MagickOffsetType *offset,
4183% ExceptionInfo *exception)
4184%
4185% A description of each parameter follows:
4186%
4187% o image: the image.
4188%
4189% o filename: the persistent pixel cache filename.
4190%
cristy01b7eb02009-09-10 23:10:14 +00004191% o attach: A value other than zero initializes the persistent pixel
4192% cache.
4193%
cristy3ed852e2009-09-05 21:47:34 +00004194% o initialize: A value other than zero initializes the persistent pixel
4195% cache.
4196%
4197% o offset: the offset in the persistent cache to store pixels.
4198%
4199% o exception: return any errors or warnings in this structure.
4200%
4201*/
4202MagickExport MagickBooleanType PersistPixelCache(Image *image,
4203 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4204 ExceptionInfo *exception)
4205{
4206 CacheInfo
4207 *cache_info,
4208 *clone_info;
4209
4210 Image
4211 clone_image;
4212
cristy3ed852e2009-09-05 21:47:34 +00004213 MagickBooleanType
4214 status;
4215
cristye076a6e2010-08-15 19:59:43 +00004216 ssize_t
4217 page_size;
4218
cristy3ed852e2009-09-05 21:47:34 +00004219 assert(image != (Image *) NULL);
4220 assert(image->signature == MagickSignature);
4221 if (image->debug != MagickFalse)
4222 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4223 assert(image->cache != (void *) NULL);
4224 assert(filename != (const char *) NULL);
4225 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004226 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004227 cache_info=(CacheInfo *) image->cache;
4228 assert(cache_info->signature == MagickSignature);
4229 if (attach != MagickFalse)
4230 {
4231 /*
cristy01b7eb02009-09-10 23:10:14 +00004232 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004233 */
4234 if (image->debug != MagickFalse)
4235 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004236 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004237 (void) CopyMagickString(cache_info->cache_filename,filename,
4238 MaxTextExtent);
4239 cache_info->type=DiskCache;
4240 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004241 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004242 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004243 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004244 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004245 }
cristy01b7eb02009-09-10 23:10:14 +00004246 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4247 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004248 {
cristyf84a1932010-01-03 18:00:18 +00004249 LockSemaphoreInfo(cache_info->semaphore);
cristy09449f72010-01-23 03:08:36 +00004250 if ((cache_info->mode != ReadMode) &&
4251 (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004252 (cache_info->reference_count == 1))
4253 {
4254 int
4255 status;
4256
4257 /*
cristy01b7eb02009-09-10 23:10:14 +00004258 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004259 */
4260 status=rename(cache_info->cache_filename,filename);
4261 if (status == 0)
4262 {
4263 (void) CopyMagickString(cache_info->cache_filename,filename,
4264 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004265 *offset+=cache_info->length+page_size-(cache_info->length %
4266 page_size);
cristyf84a1932010-01-03 18:00:18 +00004267 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004268 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004269 if (image->debug != MagickFalse)
4270 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4271 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004272 return(MagickTrue);
4273 }
4274 }
cristyf84a1932010-01-03 18:00:18 +00004275 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004276 }
4277 /*
cristy01b7eb02009-09-10 23:10:14 +00004278 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004279 */
4280 clone_image=(*image);
4281 clone_info=(CacheInfo *) clone_image.cache;
4282 image->cache=ClonePixelCache(cache_info);
4283 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4284 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4285 cache_info->type=DiskCache;
4286 cache_info->offset=(*offset);
4287 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004288 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004289 if (status != MagickFalse)
cristye7cc7cf2010-09-21 13:26:47 +00004290 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
cristy688f07b2009-09-27 15:19:13 +00004291 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004292 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4293 return(status);
4294}
4295
4296/*
4297%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4298% %
4299% %
4300% %
4301+ Q u e u e A u t h e n t i c N e x u s %
4302% %
4303% %
4304% %
4305%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4306%
4307% QueueAuthenticNexus() allocates an region to store image pixels as defined
4308% by the region rectangle and returns a pointer to the region. This region is
4309% subsequently transferred from the pixel cache with
4310% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4311% pixels are transferred, otherwise a NULL is returned.
4312%
4313% The format of the QueueAuthenticNexus() method is:
4314%
cristy5f959472010-05-27 22:19:46 +00004315% PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
4316% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004317% NexusInfo *nexus_info,ExceptionInfo *exception)
4318%
4319% A description of each parameter follows:
4320%
4321% o image: the image.
4322%
4323% o x,y,columns,rows: These values define the perimeter of a region of
4324% pixels.
4325%
4326% o nexus_info: the cache nexus to set.
4327%
4328% o exception: return any errors or warnings in this structure.
4329%
4330*/
cristybb503372010-05-27 20:51:26 +00004331MagickExport PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy30097232010-07-01 02:16:30 +00004332 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
4333 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004334{
4335 CacheInfo
4336 *cache_info;
4337
4338 MagickOffsetType
4339 offset;
4340
4341 MagickSizeType
4342 number_pixels;
4343
4344 RectangleInfo
4345 region;
4346
4347 /*
4348 Validate pixel cache geometry.
4349 */
cristye7cc7cf2010-09-21 13:26:47 +00004350 assert(image != (const Image *) NULL);
4351 assert(image->signature == MagickSignature);
4352 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004353 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
cristye7cc7cf2010-09-21 13:26:47 +00004354 assert(cache_info->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00004355 if (cache_info == (Cache) NULL)
4356 return((PixelPacket *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004357 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4358 {
4359 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4360 "NoPixelsDefinedInCache","`%s'",image->filename);
4361 return((PixelPacket *) NULL);
4362 }
cristybb503372010-05-27 20:51:26 +00004363 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4364 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004365 {
4366 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4367 "PixelsAreNotAuthentic","`%s'",image->filename);
4368 return((PixelPacket *) NULL);
4369 }
4370 offset=(MagickOffsetType) y*cache_info->columns+x;
4371 if (offset < 0)
4372 return((PixelPacket *) NULL);
4373 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4374 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4375 if ((MagickSizeType) offset >= number_pixels)
4376 return((PixelPacket *) NULL);
4377 /*
4378 Return pixel cache.
4379 */
4380 region.x=x;
4381 region.y=y;
4382 region.width=columns;
4383 region.height=rows;
4384 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4385}
4386
4387/*
4388%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4389% %
4390% %
4391% %
4392+ 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 %
4393% %
4394% %
4395% %
4396%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4397%
4398% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4399% defined by the region rectangle and returns a pointer to the region. This
4400% region is subsequently transferred from the pixel cache with
4401% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4402% pixels are transferred, otherwise a NULL is returned.
4403%
4404% The format of the QueueAuthenticPixelsCache() method is:
4405%
cristybb503372010-05-27 20:51:26 +00004406% PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4407% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004408% ExceptionInfo *exception)
4409%
4410% A description of each parameter follows:
4411%
4412% o image: the image.
4413%
4414% o x,y,columns,rows: These values define the perimeter of a region of
4415% pixels.
4416%
4417% o exception: return any errors or warnings in this structure.
4418%
4419*/
cristybb503372010-05-27 20:51:26 +00004420static 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 CacheInfo
4425 *cache_info;
4426
cristy5c9e6f22010-09-17 17:31:01 +00004427 const int
4428 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004429
cristye7cc7cf2010-09-21 13:26:47 +00004430 assert(image != (const Image *) NULL);
4431 assert(image->signature == MagickSignature);
4432 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004433 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004434 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004435 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00004436 return(QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4437 exception));
cristy3ed852e2009-09-05 21:47:34 +00004438}
4439
4440/*
4441%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4442% %
4443% %
4444% %
4445% Q u e u e A u t h e n t i c P i x e l s %
4446% %
4447% %
4448% %
4449%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4450%
4451% QueueAuthenticPixels() queues a mutable pixel region. If the region is
4452% successfully intialized a pointer to a PixelPacket array representing the
4453% region is returned, otherwise NULL is returned. The returned pointer may
4454% point to a temporary working buffer for the pixels or it may point to the
4455% final location of the pixels in memory.
4456%
4457% Write-only access means that any existing pixel values corresponding to
4458% the region are ignored. This is useful if the initial image is being
4459% created from scratch, or if the existing pixel values are to be
4460% completely replaced without need to refer to their pre-existing values.
4461% The application is free to read and write the pixel buffer returned by
4462% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4463% initialize the pixel array values. Initializing pixel array values is the
4464% application's responsibility.
4465%
4466% Performance is maximized if the selected region is part of one row, or
4467% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004468% pixels in-place (without a copy) if the image is in memory, or in a
4469% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004470% by the user.
4471%
4472% Pixels accessed via the returned pointer represent a simple array of type
4473% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
4474% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
4475% the black color component or the colormap indexes (of type IndexPacket)
4476% corresponding to the region. Once the PixelPacket (and/or IndexPacket)
4477% array has been updated, the changes must be saved back to the underlying
4478% image using SyncAuthenticPixels() or they may be lost.
4479%
4480% The format of the QueueAuthenticPixels() method is:
4481%
cristy5f959472010-05-27 22:19:46 +00004482% PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4483% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004484% ExceptionInfo *exception)
4485%
4486% A description of each parameter follows:
4487%
4488% o image: the image.
4489%
4490% o x,y,columns,rows: These values define the perimeter of a region of
4491% pixels.
4492%
4493% o exception: return any errors or warnings in this structure.
4494%
4495*/
cristybb503372010-05-27 20:51:26 +00004496MagickExport 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 CacheInfo
4501 *cache_info;
4502
cristy2036f5c2010-09-19 21:18:17 +00004503 const int
4504 id = GetOpenMPThreadId();
4505
cristy3ed852e2009-09-05 21:47:34 +00004506 assert(image != (Image *) NULL);
4507 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004508 assert(image->cache != (Cache) NULL);
4509 cache_info=(CacheInfo *) image->cache;
4510 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004511 if (cache_info->methods.queue_authentic_pixels_handler !=
4512 (QueueAuthenticPixelsHandler) NULL)
4513 return(cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4514 rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00004515 assert(id < (int) cache_info->number_threads);
4516 return(QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4517 exception));
cristy3ed852e2009-09-05 21:47:34 +00004518}
4519
4520/*
4521%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4522% %
4523% %
4524% %
4525+ R e a d P i x e l C a c h e I n d e x e s %
4526% %
4527% %
4528% %
4529%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4530%
4531% ReadPixelCacheIndexes() reads colormap indexes from the specified region of
4532% the pixel cache.
4533%
4534% The format of the ReadPixelCacheIndexes() method is:
4535%
4536% MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4537% NexusInfo *nexus_info,ExceptionInfo *exception)
4538%
4539% A description of each parameter follows:
4540%
4541% o cache_info: the pixel cache.
4542%
4543% o nexus_info: the cache nexus to read the colormap indexes.
4544%
4545% o exception: return any errors or warnings in this structure.
4546%
4547*/
4548static MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4549 NexusInfo *nexus_info,ExceptionInfo *exception)
4550{
4551 MagickOffsetType
4552 count,
4553 offset;
4554
4555 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004556 extent,
4557 length;
cristy3ed852e2009-09-05 21:47:34 +00004558
4559 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004560 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004561
cristybb503372010-05-27 20:51:26 +00004562 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004563 y;
4564
cristybb503372010-05-27 20:51:26 +00004565 size_t
cristy3ed852e2009-09-05 21:47:34 +00004566 rows;
4567
cristy3ed852e2009-09-05 21:47:34 +00004568 if (cache_info->active_index_channel == MagickFalse)
4569 return(MagickFalse);
4570 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4571 return(MagickTrue);
4572 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4573 nexus_info->region.x;
4574 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
4575 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004576 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004577 q=nexus_info->indexes;
4578 switch (cache_info->type)
4579 {
4580 case MemoryCache:
4581 case MapCache:
4582 {
4583 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004584 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004585
4586 /*
4587 Read indexes from memory.
4588 */
cristydd341db2010-03-04 19:06:38 +00004589 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004590 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004591 {
cristy48078b12010-09-23 17:11:01 +00004592 length=extent;
cristydd341db2010-03-04 19:06:38 +00004593 rows=1UL;
4594 }
cristy3ed852e2009-09-05 21:47:34 +00004595 p=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00004596 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004597 {
cristy8f036fe2010-09-18 02:02:00 +00004598 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00004599 p+=cache_info->columns;
4600 q+=nexus_info->region.width;
4601 }
4602 break;
4603 }
4604 case DiskCache:
4605 {
4606 /*
4607 Read indexes from disk.
4608 */
4609 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4610 {
4611 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4612 cache_info->cache_filename);
4613 return(MagickFalse);
4614 }
cristydd341db2010-03-04 19:06:38 +00004615 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004616 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004617 {
cristy48078b12010-09-23 17:11:01 +00004618 length=extent;
cristydd341db2010-03-04 19:06:38 +00004619 rows=1UL;
4620 }
cristy48078b12010-09-23 17:11:01 +00004621 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004622 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004623 {
cristy48078b12010-09-23 17:11:01 +00004624 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristy3ed852e2009-09-05 21:47:34 +00004625 sizeof(PixelPacket)+offset*sizeof(*q),length,(unsigned char *) q);
4626 if ((MagickSizeType) count < length)
4627 break;
4628 offset+=cache_info->columns;
4629 q+=nexus_info->region.width;
4630 }
cristybb503372010-05-27 20:51:26 +00004631 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004632 {
4633 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4634 cache_info->cache_filename);
4635 return(MagickFalse);
4636 }
4637 break;
4638 }
4639 default:
4640 break;
4641 }
4642 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004643 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004644 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004645 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004646 nexus_info->region.width,(double) nexus_info->region.height,(double)
4647 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004648 return(MagickTrue);
4649}
4650
4651/*
4652%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4653% %
4654% %
4655% %
4656+ R e a d P i x e l C a c h e P i x e l s %
4657% %
4658% %
4659% %
4660%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4661%
4662% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4663% cache.
4664%
4665% The format of the ReadPixelCachePixels() method is:
4666%
4667% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4668% NexusInfo *nexus_info,ExceptionInfo *exception)
4669%
4670% A description of each parameter follows:
4671%
4672% o cache_info: the pixel cache.
4673%
4674% o nexus_info: the cache nexus to read the pixels.
4675%
4676% o exception: return any errors or warnings in this structure.
4677%
4678*/
4679static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4680 NexusInfo *nexus_info,ExceptionInfo *exception)
4681{
4682 MagickOffsetType
4683 count,
4684 offset;
4685
4686 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004687 extent,
4688 length;
cristy3ed852e2009-09-05 21:47:34 +00004689
cristy3ed852e2009-09-05 21:47:34 +00004690 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004691 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004692
cristye076a6e2010-08-15 19:59:43 +00004693 register ssize_t
4694 y;
4695
cristybb503372010-05-27 20:51:26 +00004696 size_t
cristy3ed852e2009-09-05 21:47:34 +00004697 rows;
4698
cristy3ed852e2009-09-05 21:47:34 +00004699 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4700 return(MagickTrue);
4701 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4702 nexus_info->region.x;
4703 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
4704 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004705 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004706 q=nexus_info->pixels;
4707 switch (cache_info->type)
4708 {
4709 case MemoryCache:
4710 case MapCache:
4711 {
4712 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004713 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004714
4715 /*
4716 Read pixels from memory.
4717 */
cristydd341db2010-03-04 19:06:38 +00004718 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004719 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004720 {
cristy48078b12010-09-23 17:11:01 +00004721 length=extent;
cristydd341db2010-03-04 19:06:38 +00004722 rows=1UL;
4723 }
cristy3ed852e2009-09-05 21:47:34 +00004724 p=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00004725 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004726 {
cristy8f036fe2010-09-18 02:02:00 +00004727 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00004728 p+=cache_info->columns;
4729 q+=nexus_info->region.width;
4730 }
4731 break;
4732 }
4733 case DiskCache:
4734 {
4735 /*
4736 Read pixels from disk.
4737 */
4738 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4739 {
4740 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4741 cache_info->cache_filename);
4742 return(MagickFalse);
4743 }
cristydd341db2010-03-04 19:06:38 +00004744 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004745 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004746 {
cristy48078b12010-09-23 17:11:01 +00004747 length=extent;
cristydd341db2010-03-04 19:06:38 +00004748 rows=1UL;
4749 }
cristybb503372010-05-27 20:51:26 +00004750 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004751 {
4752 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4753 sizeof(*q),length,(unsigned char *) q);
4754 if ((MagickSizeType) count < length)
4755 break;
4756 offset+=cache_info->columns;
4757 q+=nexus_info->region.width;
4758 }
cristybb503372010-05-27 20:51:26 +00004759 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004760 {
4761 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4762 cache_info->cache_filename);
4763 return(MagickFalse);
4764 }
4765 break;
4766 }
4767 default:
4768 break;
4769 }
4770 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004771 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004772 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004773 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004774 nexus_info->region.width,(double) nexus_info->region.height,(double)
4775 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004776 return(MagickTrue);
4777}
4778
4779/*
4780%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4781% %
4782% %
4783% %
4784+ R e f e r e n c e P i x e l C a c h e %
4785% %
4786% %
4787% %
4788%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4789%
4790% ReferencePixelCache() increments the reference count associated with the
4791% pixel cache returning a pointer to the cache.
4792%
4793% The format of the ReferencePixelCache method is:
4794%
4795% Cache ReferencePixelCache(Cache cache_info)
4796%
4797% A description of each parameter follows:
4798%
4799% o cache_info: the pixel cache.
4800%
4801*/
4802MagickExport Cache ReferencePixelCache(Cache cache)
4803{
4804 CacheInfo
4805 *cache_info;
4806
4807 assert(cache != (Cache *) NULL);
4808 cache_info=(CacheInfo *) cache;
4809 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004810 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004811 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004812 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004813 return(cache_info);
4814}
4815
4816/*
4817%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4818% %
4819% %
4820% %
4821+ S e t P i x e l C a c h e M e t h o d s %
4822% %
4823% %
4824% %
4825%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4826%
4827% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4828%
4829% The format of the SetPixelCacheMethods() method is:
4830%
4831% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4832%
4833% A description of each parameter follows:
4834%
4835% o cache: the pixel cache.
4836%
4837% o cache_methods: Specifies a pointer to a CacheMethods structure.
4838%
4839*/
4840MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4841{
4842 CacheInfo
4843 *cache_info;
4844
4845 GetOneAuthenticPixelFromHandler
4846 get_one_authentic_pixel_from_handler;
4847
4848 GetOneVirtualPixelFromHandler
4849 get_one_virtual_pixel_from_handler;
4850
4851 /*
4852 Set cache pixel methods.
4853 */
4854 assert(cache != (Cache) NULL);
4855 assert(cache_methods != (CacheMethods *) NULL);
4856 cache_info=(CacheInfo *) cache;
4857 assert(cache_info->signature == MagickSignature);
4858 if (cache_info->debug != MagickFalse)
4859 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4860 cache_info->filename);
4861 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4862 cache_info->methods.get_virtual_pixel_handler=
4863 cache_methods->get_virtual_pixel_handler;
4864 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4865 cache_info->methods.destroy_pixel_handler=
4866 cache_methods->destroy_pixel_handler;
4867 if (cache_methods->get_virtual_indexes_from_handler !=
4868 (GetVirtualIndexesFromHandler) NULL)
4869 cache_info->methods.get_virtual_indexes_from_handler=
4870 cache_methods->get_virtual_indexes_from_handler;
4871 if (cache_methods->get_authentic_pixels_handler !=
4872 (GetAuthenticPixelsHandler) NULL)
4873 cache_info->methods.get_authentic_pixels_handler=
4874 cache_methods->get_authentic_pixels_handler;
4875 if (cache_methods->queue_authentic_pixels_handler !=
4876 (QueueAuthenticPixelsHandler) NULL)
4877 cache_info->methods.queue_authentic_pixels_handler=
4878 cache_methods->queue_authentic_pixels_handler;
4879 if (cache_methods->sync_authentic_pixels_handler !=
4880 (SyncAuthenticPixelsHandler) NULL)
4881 cache_info->methods.sync_authentic_pixels_handler=
4882 cache_methods->sync_authentic_pixels_handler;
4883 if (cache_methods->get_authentic_pixels_from_handler !=
4884 (GetAuthenticPixelsFromHandler) NULL)
4885 cache_info->methods.get_authentic_pixels_from_handler=
4886 cache_methods->get_authentic_pixels_from_handler;
4887 if (cache_methods->get_authentic_indexes_from_handler !=
4888 (GetAuthenticIndexesFromHandler) NULL)
4889 cache_info->methods.get_authentic_indexes_from_handler=
4890 cache_methods->get_authentic_indexes_from_handler;
4891 get_one_virtual_pixel_from_handler=
4892 cache_info->methods.get_one_virtual_pixel_from_handler;
4893 if (get_one_virtual_pixel_from_handler !=
4894 (GetOneVirtualPixelFromHandler) NULL)
4895 cache_info->methods.get_one_virtual_pixel_from_handler=
4896 cache_methods->get_one_virtual_pixel_from_handler;
4897 get_one_authentic_pixel_from_handler=
4898 cache_methods->get_one_authentic_pixel_from_handler;
4899 if (get_one_authentic_pixel_from_handler !=
4900 (GetOneAuthenticPixelFromHandler) NULL)
4901 cache_info->methods.get_one_authentic_pixel_from_handler=
4902 cache_methods->get_one_authentic_pixel_from_handler;
4903}
4904
4905/*
4906%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4907% %
4908% %
4909% %
4910+ S e t P i x e l C a c h e N e x u s P i x e l s %
4911% %
4912% %
4913% %
4914%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4915%
4916% SetPixelCacheNexusPixels() defines the region of the cache for the
4917% specified cache nexus.
4918%
4919% The format of the SetPixelCacheNexusPixels() method is:
4920%
4921% PixelPacket SetPixelCacheNexusPixels(const Image *image,
4922% const RectangleInfo *region,NexusInfo *nexus_info,
4923% ExceptionInfo *exception)
4924%
4925% A description of each parameter follows:
4926%
4927% o image: the image.
4928%
4929% o region: A pointer to the RectangleInfo structure that defines the
4930% region of this particular cache nexus.
4931%
4932% o nexus_info: the cache nexus to set.
4933%
4934% o exception: return any errors or warnings in this structure.
4935%
4936*/
cristyabd6e372010-09-15 19:11:26 +00004937
4938static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4939 NexusInfo *nexus_info,ExceptionInfo *exception)
4940{
4941 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4942 return(MagickFalse);
4943 nexus_info->mapped=MagickFalse;
4944 nexus_info->cache=(PixelPacket *) AcquireMagickMemory((size_t)
4945 nexus_info->length);
4946 if (nexus_info->cache == (PixelPacket *) NULL)
4947 {
4948 nexus_info->mapped=MagickTrue;
4949 nexus_info->cache=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
4950 nexus_info->length);
4951 }
4952 if (nexus_info->cache == (PixelPacket *) NULL)
4953 {
4954 (void) ThrowMagickException(exception,GetMagickModule(),
4955 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4956 cache_info->filename);
4957 return(MagickFalse);
4958 }
4959 return(MagickTrue);
4960}
4961
cristy3ed852e2009-09-05 21:47:34 +00004962static PixelPacket *SetPixelCacheNexusPixels(const Image *image,
4963 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4964{
4965 CacheInfo
4966 *cache_info;
4967
4968 MagickBooleanType
4969 status;
4970
cristy3ed852e2009-09-05 21:47:34 +00004971 MagickSizeType
4972 length,
4973 number_pixels;
4974
cristy3ed852e2009-09-05 21:47:34 +00004975 cache_info=(CacheInfo *) image->cache;
4976 assert(cache_info->signature == MagickSignature);
4977 if (cache_info->type == UndefinedCache)
4978 return((PixelPacket *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00004979 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00004980 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
4981 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00004982 {
cristybb503372010-05-27 20:51:26 +00004983 ssize_t
cristybad067a2010-02-15 17:20:55 +00004984 x,
4985 y;
cristy3ed852e2009-09-05 21:47:34 +00004986
cristyeaedf062010-05-29 22:36:02 +00004987 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4988 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00004989 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4990 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00004991 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00004992 ((nexus_info->region.width == cache_info->columns) ||
4993 ((nexus_info->region.width % cache_info->columns) == 0)))))
4994 {
4995 MagickOffsetType
4996 offset;
4997
4998 /*
4999 Pixels are accessed directly from memory.
5000 */
5001 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5002 nexus_info->region.x;
5003 nexus_info->pixels=cache_info->pixels+offset;
5004 nexus_info->indexes=(IndexPacket *) NULL;
5005 if (cache_info->active_index_channel != MagickFalse)
5006 nexus_info->indexes=cache_info->indexes+offset;
5007 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00005008 }
5009 }
5010 /*
5011 Pixels are stored in a cache region until they are synced to the cache.
5012 */
5013 number_pixels=(MagickSizeType) nexus_info->region.width*
5014 nexus_info->region.height;
5015 length=number_pixels*sizeof(PixelPacket);
5016 if (cache_info->active_index_channel != MagickFalse)
5017 length+=number_pixels*sizeof(IndexPacket);
5018 if (nexus_info->cache == (PixelPacket *) NULL)
5019 {
5020 nexus_info->length=length;
5021 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5022 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005023 {
5024 nexus_info->length=0;
5025 return((PixelPacket *) NULL);
5026 }
cristy3ed852e2009-09-05 21:47:34 +00005027 }
5028 else
5029 if (nexus_info->length != length)
5030 {
5031 RelinquishCacheNexusPixels(nexus_info);
5032 nexus_info->length=length;
5033 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5034 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005035 {
5036 nexus_info->length=0;
5037 return((PixelPacket *) NULL);
5038 }
cristy3ed852e2009-09-05 21:47:34 +00005039 }
5040 nexus_info->pixels=nexus_info->cache;
5041 nexus_info->indexes=(IndexPacket *) NULL;
5042 if (cache_info->active_index_channel != MagickFalse)
5043 nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
5044 return(nexus_info->pixels);
5045}
5046
5047/*
5048%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5049% %
5050% %
5051% %
5052% 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 %
5053% %
5054% %
5055% %
5056%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5057%
5058% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5059% pixel cache and returns the previous setting. A virtual pixel is any pixel
5060% access that is outside the boundaries of the image cache.
5061%
5062% The format of the SetPixelCacheVirtualMethod() method is:
5063%
5064% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5065% const VirtualPixelMethod virtual_pixel_method)
5066%
5067% A description of each parameter follows:
5068%
5069% o image: the image.
5070%
5071% o virtual_pixel_method: choose the type of virtual pixel.
5072%
5073*/
5074MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5075 const VirtualPixelMethod virtual_pixel_method)
5076{
5077 CacheInfo
5078 *cache_info;
5079
5080 VirtualPixelMethod
5081 method;
5082
5083 assert(image != (Image *) NULL);
5084 assert(image->signature == MagickSignature);
5085 if (image->debug != MagickFalse)
5086 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5087 assert(image->cache != (Cache) NULL);
5088 cache_info=(CacheInfo *) image->cache;
5089 assert(cache_info->signature == MagickSignature);
5090 method=cache_info->virtual_pixel_method;
5091 cache_info->virtual_pixel_method=virtual_pixel_method;
5092 return(method);
5093}
5094
5095/*
5096%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5097% %
5098% %
5099% %
5100+ 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 %
5101% %
5102% %
5103% %
5104%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5105%
5106% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5107% in-memory or disk cache. The method returns MagickTrue if the pixel region
5108% is synced, otherwise MagickFalse.
5109%
5110% The format of the SyncAuthenticPixelCacheNexus() method is:
5111%
5112% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5113% NexusInfo *nexus_info,ExceptionInfo *exception)
5114%
5115% A description of each parameter follows:
5116%
5117% o image: the image.
5118%
5119% o nexus_info: the cache nexus to sync.
5120%
5121% o exception: return any errors or warnings in this structure.
5122%
5123*/
5124MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5125 NexusInfo *nexus_info,ExceptionInfo *exception)
5126{
5127 CacheInfo
5128 *cache_info;
5129
5130 MagickBooleanType
5131 status;
5132
5133 /*
5134 Transfer pixels to the cache.
5135 */
5136 assert(image != (Image *) NULL);
5137 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005138 if (image->cache == (Cache) NULL)
5139 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5140 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005141 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005142 if (cache_info->type == UndefinedCache)
5143 return(MagickFalse);
5144 if ((image->clip_mask != (Image *) NULL) &&
5145 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5146 return(MagickFalse);
5147 if ((image->mask != (Image *) NULL) &&
5148 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5149 return(MagickFalse);
5150 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5151 return(MagickTrue);
5152 assert(cache_info->signature == MagickSignature);
5153 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5154 if ((cache_info->active_index_channel != MagickFalse) &&
5155 (WritePixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse))
5156 return(MagickFalse);
5157 return(status);
5158}
5159
5160/*
5161%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5162% %
5163% %
5164% %
5165+ S y n c A u t h e n t i c P i x e l C a c h e %
5166% %
5167% %
5168% %
5169%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5170%
5171% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5172% or disk cache. The method returns MagickTrue if the pixel region is synced,
5173% otherwise MagickFalse.
5174%
5175% The format of the SyncAuthenticPixelsCache() method is:
5176%
5177% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5178% ExceptionInfo *exception)
5179%
5180% A description of each parameter follows:
5181%
5182% o image: the image.
5183%
5184% o exception: return any errors or warnings in this structure.
5185%
5186*/
5187static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5188 ExceptionInfo *exception)
5189{
5190 CacheInfo
5191 *cache_info;
5192
cristy5c9e6f22010-09-17 17:31:01 +00005193 const int
5194 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005195
cristye7cc7cf2010-09-21 13:26:47 +00005196 assert(image != (Image *) NULL);
5197 assert(image->signature == MagickSignature);
5198 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005199 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005200 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005201 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00005202 return(SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5203 exception));
cristy3ed852e2009-09-05 21:47:34 +00005204}
5205
5206/*
5207%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5208% %
5209% %
5210% %
5211% S y n c A u t h e n t i c P i x e l s %
5212% %
5213% %
5214% %
5215%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5216%
5217% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5218% The method returns MagickTrue if the pixel region is flushed, otherwise
5219% MagickFalse.
5220%
5221% The format of the SyncAuthenticPixels() method is:
5222%
5223% MagickBooleanType SyncAuthenticPixels(Image *image,
5224% ExceptionInfo *exception)
5225%
5226% A description of each parameter follows:
5227%
5228% o image: the image.
5229%
5230% o exception: return any errors or warnings in this structure.
5231%
5232*/
5233MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5234 ExceptionInfo *exception)
5235{
5236 CacheInfo
5237 *cache_info;
5238
cristy2036f5c2010-09-19 21:18:17 +00005239 const int
5240 id = GetOpenMPThreadId();
5241
cristy3ed852e2009-09-05 21:47:34 +00005242 assert(image != (Image *) NULL);
5243 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005244 assert(image->cache != (Cache) NULL);
5245 cache_info=(CacheInfo *) image->cache;
5246 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005247 if (cache_info->methods.sync_authentic_pixels_handler !=
5248 (SyncAuthenticPixelsHandler) NULL)
5249 return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
cristy2036f5c2010-09-19 21:18:17 +00005250 assert(id < (int) cache_info->number_threads);
5251 return(SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5252 exception));
cristy3ed852e2009-09-05 21:47:34 +00005253}
5254
5255/*
5256%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5257% %
5258% %
5259% %
5260+ W r i t e P i x e l C a c h e I n d e x e s %
5261% %
5262% %
5263% %
5264%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5265%
5266% WritePixelCacheIndexes() writes the colormap indexes to the specified
5267% region of the pixel cache.
5268%
5269% The format of the WritePixelCacheIndexes() method is:
5270%
5271% MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5272% NexusInfo *nexus_info,ExceptionInfo *exception)
5273%
5274% A description of each parameter follows:
5275%
5276% o cache_info: the pixel cache.
5277%
5278% o nexus_info: the cache nexus to write the colormap indexes.
5279%
5280% o exception: return any errors or warnings in this structure.
5281%
5282*/
5283static MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5284 NexusInfo *nexus_info,ExceptionInfo *exception)
5285{
5286 MagickOffsetType
5287 count,
5288 offset;
5289
5290 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005291 extent,
5292 length;
cristy3ed852e2009-09-05 21:47:34 +00005293
5294 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005295 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005296
cristybb503372010-05-27 20:51:26 +00005297 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005298 y;
5299
cristybb503372010-05-27 20:51:26 +00005300 size_t
cristy3ed852e2009-09-05 21:47:34 +00005301 rows;
5302
cristy3ed852e2009-09-05 21:47:34 +00005303 if (cache_info->active_index_channel == MagickFalse)
5304 return(MagickFalse);
5305 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5306 return(MagickTrue);
5307 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5308 nexus_info->region.x;
5309 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
5310 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005311 extent=(MagickSizeType) length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005312 p=nexus_info->indexes;
5313 switch (cache_info->type)
5314 {
5315 case MemoryCache:
5316 case MapCache:
5317 {
5318 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005319 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005320
5321 /*
5322 Write indexes to memory.
5323 */
cristydd341db2010-03-04 19:06:38 +00005324 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005325 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005326 {
cristy48078b12010-09-23 17:11:01 +00005327 length=extent;
cristydd341db2010-03-04 19:06:38 +00005328 rows=1UL;
5329 }
cristy3ed852e2009-09-05 21:47:34 +00005330 q=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00005331 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005332 {
cristy8f036fe2010-09-18 02:02:00 +00005333 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00005334 p+=nexus_info->region.width;
5335 q+=cache_info->columns;
5336 }
5337 break;
5338 }
5339 case DiskCache:
5340 {
5341 /*
5342 Write indexes to disk.
5343 */
5344 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5345 {
5346 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5347 cache_info->cache_filename);
5348 return(MagickFalse);
5349 }
cristydd341db2010-03-04 19:06:38 +00005350 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005351 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005352 {
cristy48078b12010-09-23 17:11:01 +00005353 length=extent;
cristydd341db2010-03-04 19:06:38 +00005354 rows=1UL;
5355 }
cristy48078b12010-09-23 17:11:01 +00005356 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005357 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005358 {
cristy48078b12010-09-23 17:11:01 +00005359 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5360 sizeof(PixelPacket)+offset*sizeof(*p),length,(const unsigned char *)
5361 p);
cristy3ed852e2009-09-05 21:47:34 +00005362 if ((MagickSizeType) count < length)
5363 break;
5364 p+=nexus_info->region.width;
5365 offset+=cache_info->columns;
5366 }
cristybb503372010-05-27 20:51:26 +00005367 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005368 {
5369 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5370 cache_info->cache_filename);
5371 return(MagickFalse);
5372 }
5373 break;
5374 }
5375 default:
5376 break;
5377 }
5378 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005379 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005380 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005381 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005382 nexus_info->region.width,(double) nexus_info->region.height,(double)
5383 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005384 return(MagickTrue);
5385}
5386
5387/*
5388%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5389% %
5390% %
5391% %
5392+ W r i t e C a c h e P i x e l s %
5393% %
5394% %
5395% %
5396%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5397%
5398% WritePixelCachePixels() writes image pixels to the specified region of the
5399% pixel cache.
5400%
5401% The format of the WritePixelCachePixels() method is:
5402%
5403% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5404% NexusInfo *nexus_info,ExceptionInfo *exception)
5405%
5406% A description of each parameter follows:
5407%
5408% o cache_info: the pixel cache.
5409%
5410% o nexus_info: the cache nexus to write the pixels.
5411%
5412% o exception: return any errors or warnings in this structure.
5413%
5414*/
5415static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5416 NexusInfo *nexus_info,ExceptionInfo *exception)
5417{
5418 MagickOffsetType
5419 count,
5420 offset;
5421
5422 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005423 extent,
5424 length;
cristy3ed852e2009-09-05 21:47:34 +00005425
cristy3ed852e2009-09-05 21:47:34 +00005426 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005427 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005428
cristybb503372010-05-27 20:51:26 +00005429 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005430 y;
5431
cristybb503372010-05-27 20:51:26 +00005432 size_t
cristy3ed852e2009-09-05 21:47:34 +00005433 rows;
5434
cristy3ed852e2009-09-05 21:47:34 +00005435 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5436 return(MagickTrue);
5437 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5438 nexus_info->region.x;
5439 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
5440 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005441 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005442 p=nexus_info->pixels;
5443 switch (cache_info->type)
5444 {
5445 case MemoryCache:
5446 case MapCache:
5447 {
5448 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005449 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005450
5451 /*
5452 Write pixels to memory.
5453 */
cristydd341db2010-03-04 19:06:38 +00005454 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005455 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005456 {
cristy48078b12010-09-23 17:11:01 +00005457 length=extent;
cristydd341db2010-03-04 19:06:38 +00005458 rows=1UL;
5459 }
cristy3ed852e2009-09-05 21:47:34 +00005460 q=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00005461 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005462 {
cristy8f036fe2010-09-18 02:02:00 +00005463 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00005464 p+=nexus_info->region.width;
5465 q+=cache_info->columns;
5466 }
5467 break;
5468 }
5469 case DiskCache:
5470 {
5471 /*
5472 Write pixels to disk.
5473 */
5474 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5475 {
5476 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5477 cache_info->cache_filename);
5478 return(MagickFalse);
5479 }
cristydd341db2010-03-04 19:06:38 +00005480 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005481 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005482 {
cristy48078b12010-09-23 17:11:01 +00005483 length=extent;
cristydd341db2010-03-04 19:06:38 +00005484 rows=1UL;
5485 }
cristybb503372010-05-27 20:51:26 +00005486 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005487 {
5488 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5489 sizeof(*p),length,(const unsigned char *) p);
5490 if ((MagickSizeType) count < length)
5491 break;
5492 p+=nexus_info->region.width;
5493 offset+=cache_info->columns;
5494 }
cristybb503372010-05-27 20:51:26 +00005495 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005496 {
5497 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5498 cache_info->cache_filename);
5499 return(MagickFalse);
5500 }
5501 break;
5502 }
5503 default:
5504 break;
5505 }
5506 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005507 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005508 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005509 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005510 nexus_info->region.width,(double) nexus_info->region.height,(double)
5511 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005512 return(MagickTrue);
5513}