blob: 29c8cf5dc1a62b6ed9617b461841495b5b1ad1b9 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% CCCC AAA CCCC H H EEEEE %
7% C A A C H H E %
8% C AAAAA C HHHHH EEE %
9% C A A C H H E %
10% CCCC A A CCCC H H EEEEE %
11% %
12% %
13% MagickCore Pixel Cache Methods %
14% %
15% Software Design %
16% John Cristy %
17% July 1999 %
18% %
19% %
cristy16af1cb2009-12-11 21:38:29 +000020% Copyright 1999-2010 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
26% http://www.imagemagick.org/script/license.php %
27% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37%
38*/
39
40/*
41 Include declarations.
42*/
43#include "magick/studio.h"
44#include "magick/blob.h"
45#include "magick/blob-private.h"
46#include "magick/cache.h"
47#include "magick/cache-private.h"
48#include "magick/color-private.h"
49#include "magick/composite-private.h"
50#include "magick/exception.h"
51#include "magick/exception-private.h"
cristy365e58f2010-02-15 02:00:01 +000052#include "magick/geometry.h"
cristy3ed852e2009-09-05 21:47:34 +000053#include "magick/list.h"
54#include "magick/log.h"
55#include "magick/magick.h"
56#include "magick/memory_.h"
cristy4789f0d2010-01-10 00:01:06 +000057#include "magick/pixel.h"
cristy3ed852e2009-09-05 21:47:34 +000058#include "magick/pixel-private.h"
cristya21afde2010-07-02 00:45:40 +000059#include "magick/policy.h"
cristy3ed852e2009-09-05 21:47:34 +000060#include "magick/quantum.h"
61#include "magick/random_.h"
62#include "magick/resource_.h"
63#include "magick/semaphore.h"
64#include "magick/splay-tree.h"
65#include "magick/string_.h"
cristya21afde2010-07-02 00:45:40 +000066#include "magick/string-private.h"
cristy3ed852e2009-09-05 21:47:34 +000067#include "magick/thread-private.h"
68#include "magick/utility.h"
69#if defined(MAGICKCORE_ZLIB_DELEGATE)
70#include "zlib.h"
71#endif
72
73/*
cristy30097232010-07-01 02:16:30 +000074 Define declarations.
75*/
76#define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
77
78/*
cristy3ed852e2009-09-05 21:47:34 +000079 Typedef declarations.
80*/
81typedef struct _MagickModulo
82{
cristybb503372010-05-27 20:51:26 +000083 ssize_t
cristy3ed852e2009-09-05 21:47:34 +000084 quotient,
85 remainder;
86} MagickModulo;
87
88struct _NexusInfo
89{
90 MagickBooleanType
91 mapped;
92
93 RectangleInfo
94 region;
95
96 MagickSizeType
97 length;
98
99 PixelPacket
100 *cache,
101 *pixels;
102
103 IndexPacket
104 *indexes;
105
cristybb503372010-05-27 20:51:26 +0000106 size_t
cristy3ed852e2009-09-05 21:47:34 +0000107 signature;
108};
109
110/*
111 Forward declarations.
112*/
113#if defined(__cplusplus) || defined(c_plusplus)
114extern "C" {
115#endif
116
117static const IndexPacket
118 *GetVirtualIndexesFromCache(const Image *);
119
120static const PixelPacket
cristybb503372010-05-27 20:51:26 +0000121 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
cristye7cc7cf2010-09-21 13:26:47 +0000122 const ssize_t,const size_t,const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000123 *GetVirtualPixelsCache(const Image *);
124
125static MagickBooleanType
cristye7cc7cf2010-09-21 13:26:47 +0000126 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,
127 PixelPacket *,ExceptionInfo *),
128 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
129 const ssize_t,const ssize_t,PixelPacket *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000130 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
131 ReadPixelCacheIndexes(CacheInfo *,NexusInfo *,ExceptionInfo *),
132 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
133 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
134 WritePixelCacheIndexes(CacheInfo *,NexusInfo *,ExceptionInfo *),
135 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
136
137static PixelPacket
cristye7cc7cf2010-09-21 13:26:47 +0000138 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
139 const size_t,ExceptionInfo *),
cristybb503372010-05-27 20:51:26 +0000140 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
141 const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000142 *SetPixelCacheNexusPixels(const Image *,const RectangleInfo *,NexusInfo *,
cristya4af2e32010-03-08 00:51:56 +0000143 ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +0000144
145#if defined(__cplusplus) || defined(c_plusplus)
146}
147#endif
148
149/*
150 Global declarations.
151*/
152static volatile MagickBooleanType
153 instantiate_cache = MagickFalse;
154
155static SemaphoreInfo
156 *cache_semaphore = (SemaphoreInfo *) NULL;
157
158static SplayTreeInfo
159 *cache_resources = (SplayTreeInfo *) NULL;
cristy3ed852e2009-09-05 21:47:34 +0000160
161/*
162%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
163% %
164% %
165% %
166+ A c q u i r e P i x e l C a c h e %
167% %
168% %
169% %
170%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
171%
172% AcquirePixelCache() acquires a pixel cache.
173%
174% The format of the AcquirePixelCache() method is:
175%
cristybb503372010-05-27 20:51:26 +0000176% Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000177%
178% A description of each parameter follows:
179%
180% o number_threads: the number of nexus threads.
181%
182*/
cristybb503372010-05-27 20:51:26 +0000183MagickExport Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000184{
185 CacheInfo
186 *cache_info;
187
cristy73bd4a52010-10-05 11:24:23 +0000188 cache_info=(CacheInfo *) AcquireMagickMemory(sizeof(*cache_info));
cristy3ed852e2009-09-05 21:47:34 +0000189 if (cache_info == (CacheInfo *) NULL)
190 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
191 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
192 cache_info->type=UndefinedCache;
cristy87528ea2009-09-10 14:53:56 +0000193 cache_info->mode=IOMode;
cristy3ed852e2009-09-05 21:47:34 +0000194 cache_info->colorspace=RGBColorspace;
195 cache_info->file=(-1);
196 cache_info->id=GetMagickThreadId();
197 cache_info->number_threads=number_threads;
198 if (number_threads == 0)
199 cache_info->number_threads=GetOpenMPMaximumThreads();
200 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
201 if (cache_info->nexus_info == (NexusInfo **) NULL)
202 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristy3ed852e2009-09-05 21:47:34 +0000203 cache_info->semaphore=AllocateSemaphoreInfo();
cristy93505cf2010-08-10 21:37:49 +0000204 cache_info->reference_count=1;
cristy3ed852e2009-09-05 21:47:34 +0000205 cache_info->disk_semaphore=AllocateSemaphoreInfo();
206 cache_info->debug=IsEventLogging();
207 cache_info->signature=MagickSignature;
208 if ((cache_resources == (SplayTreeInfo *) NULL) &&
209 (instantiate_cache == MagickFalse))
210 {
cristy4e1dff62009-10-25 20:36:03 +0000211 if (cache_semaphore == (SemaphoreInfo *) NULL)
212 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000213 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000214 if ((cache_resources == (SplayTreeInfo *) NULL) &&
215 (instantiate_cache == MagickFalse))
216 {
217 cache_resources=NewSplayTree((int (*)(const void *,const void *))
218 NULL,(void *(*)(void *)) NULL,(void *(*)(void *)) NULL);
219 instantiate_cache=MagickTrue;
220 }
cristyf84a1932010-01-03 18:00:18 +0000221 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000222 }
223 (void) AddValueToSplayTree(cache_resources,cache_info,cache_info);
224 return((Cache ) cache_info);
225}
226
227/*
228%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
229% %
230% %
231% %
232% A c q u i r e P i x e l C a c h e N e x u s %
233% %
234% %
235% %
236%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
237%
238% AcquirePixelCacheNexus() allocates the NexusInfo structure.
239%
240% The format of the AcquirePixelCacheNexus method is:
241%
cristybb503372010-05-27 20:51:26 +0000242% NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000243%
244% A description of each parameter follows:
245%
246% o number_threads: the number of nexus threads.
247%
248*/
cristy2cd7a752010-08-23 00:48:54 +0000249MagickExport NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000250{
cristy3ed852e2009-09-05 21:47:34 +0000251 NexusInfo
252 **nexus_info;
253
cristye076a6e2010-08-15 19:59:43 +0000254 register ssize_t
255 i;
256
cristyb41ee102010-10-04 16:46:15 +0000257 nexus_info=(NexusInfo **) AcquireQuantumMemory(number_threads,
cristy3ed852e2009-09-05 21:47:34 +0000258 sizeof(*nexus_info));
259 if (nexus_info == (NexusInfo **) NULL)
260 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristybb503372010-05-27 20:51:26 +0000261 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000262 {
cristy6a924af2010-09-23 14:02:54 +0000263 nexus_info[i]=(NexusInfo *) AcquireAlignedMemory(1,sizeof(**nexus_info));
cristy3ed852e2009-09-05 21:47:34 +0000264 if (nexus_info[i] == (NexusInfo *) NULL)
265 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
266 (void) ResetMagickMemory(nexus_info[i],0,sizeof(*nexus_info[i]));
267 nexus_info[i]->signature=MagickSignature;
268 }
269 return(nexus_info);
270}
271
272/*
273%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
274% %
275% %
276% %
cristyd43a46b2010-01-21 02:13:41 +0000277+ A c q u i r e P i x e l C a c h e P i x e l s %
278% %
279% %
280% %
281%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
282%
283% AcquirePixelCachePixels() returns the pixels associated with the specified
284% image.
285%
286% The format of the AcquirePixelCachePixels() method is:
287%
288% const void *AcquirePixelCachePixels(const Image *image,
289% MagickSizeType *length,ExceptionInfo *exception)
290%
291% A description of each parameter follows:
292%
293% o image: the image.
294%
295% o length: the pixel cache length.
296%
297% o exception: return any errors or warnings in this structure.
298%
299*/
300MagickExport const void *AcquirePixelCachePixels(const Image *image,
301 MagickSizeType *length,ExceptionInfo *exception)
302{
303 CacheInfo
304 *cache_info;
305
306 assert(image != (const Image *) NULL);
307 assert(image->signature == MagickSignature);
cristyd43a46b2010-01-21 02:13:41 +0000308 assert(exception != (ExceptionInfo *) NULL);
309 assert(exception->signature == MagickSignature);
310 assert(image->cache != (Cache) NULL);
311 cache_info=(CacheInfo *) image->cache;
312 assert(cache_info->signature == MagickSignature);
313 *length=0;
314 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
315 return((const void *) NULL);
316 *length=cache_info->length;
317 return((const void *) cache_info->pixels);
318}
319
320/*
321%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
322% %
323% %
324% %
cristyf34a1452009-10-24 22:29:27 +0000325+ C a c h e C o m p o n e n t G e n e s i s %
326% %
327% %
328% %
329%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
330%
331% CacheComponentGenesis() instantiates the cache component.
332%
333% The format of the CacheComponentGenesis method is:
334%
335% MagickBooleanType CacheComponentGenesis(void)
336%
337*/
338MagickExport MagickBooleanType CacheComponentGenesis(void)
339{
cristy165b6092009-10-26 13:52:10 +0000340 AcquireSemaphoreInfo(&cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000341 return(MagickTrue);
342}
343
344/*
345%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
346% %
347% %
348% %
349+ C a c h e C o m p o n e n t T e r m i n u s %
350% %
351% %
352% %
353%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
354%
355% CacheComponentTerminus() destroys the cache component.
356%
357% The format of the CacheComponentTerminus() method is:
358%
359% CacheComponentTerminus(void)
360%
361*/
362MagickExport void CacheComponentTerminus(void)
363{
cristy18b17442009-10-25 18:36:48 +0000364 if (cache_semaphore == (SemaphoreInfo *) NULL)
365 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000366 LockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000367 if (cache_resources != (SplayTreeInfo *) NULL)
368 cache_resources=DestroySplayTree(cache_resources);
369 instantiate_cache=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +0000370 UnlockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000371 DestroySemaphoreInfo(&cache_semaphore);
372}
373
374/*
375%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
376% %
377% %
378% %
cristy3ed852e2009-09-05 21:47:34 +0000379+ C l i p P i x e l C a c h e N e x u s %
380% %
381% %
382% %
383%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
384%
385% ClipPixelCacheNexus() clips the cache nexus as defined by the image clip
386% mask. The method returns MagickTrue if the pixel region is clipped,
387% otherwise MagickFalse.
388%
389% The format of the ClipPixelCacheNexus() method is:
390%
391% MagickBooleanType ClipPixelCacheNexus(Image *image,NexusInfo *nexus_info,
392% ExceptionInfo *exception)
393%
394% A description of each parameter follows:
395%
396% o image: the image.
397%
398% o nexus_info: the cache nexus to clip.
399%
400% o exception: return any errors or warnings in this structure.
401%
402*/
403static MagickBooleanType ClipPixelCacheNexus(Image *image,
404 NexusInfo *nexus_info,ExceptionInfo *exception)
405{
406 CacheInfo
407 *cache_info;
408
409 MagickSizeType
410 number_pixels;
411
412 NexusInfo
413 **clip_nexus,
414 **image_nexus;
415
416 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000417 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +0000418
419 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +0000420 *restrict nexus_indexes,
421 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +0000422
cristy3ed852e2009-09-05 21:47:34 +0000423 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000424 *restrict p,
425 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000426
cristye076a6e2010-08-15 19:59:43 +0000427 register ssize_t
428 i;
429
cristy3ed852e2009-09-05 21:47:34 +0000430 /*
431 Apply clip mask.
432 */
433 if (image->debug != MagickFalse)
434 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
435 if (image->clip_mask == (Image *) NULL)
436 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +0000437 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +0000438 if (cache_info == (Cache) NULL)
439 return(MagickFalse);
440 image_nexus=AcquirePixelCacheNexus(1);
441 clip_nexus=AcquirePixelCacheNexus(1);
442 if ((image_nexus == (NexusInfo **) NULL) ||
443 (clip_nexus == (NexusInfo **) NULL))
444 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
445 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,nexus_info->region.y,
446 nexus_info->region.width,nexus_info->region.height,image_nexus[0],
447 exception);
cristy2036f5c2010-09-19 21:18:17 +0000448 indexes=GetPixelCacheNexusIndexes(cache_info,image_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +0000449 q=nexus_info->pixels;
450 nexus_indexes=nexus_info->indexes;
451 r=GetVirtualPixelsFromNexus(image->clip_mask,MaskVirtualPixelMethod,
452 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
453 nexus_info->region.height,clip_nexus[0],exception);
454 number_pixels=(MagickSizeType) nexus_info->region.width*
455 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +0000456 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000457 {
458 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
459 break;
460 if (PixelIntensityToQuantum(r) > ((Quantum) QuantumRange/2))
461 {
cristyce70c172010-01-07 17:15:30 +0000462 SetRedPixelComponent(q,GetRedPixelComponent(p));
463 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
464 SetBluePixelComponent(q,GetBluePixelComponent(p));
465 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
cristy3ed852e2009-09-05 21:47:34 +0000466 if (cache_info->active_index_channel != MagickFalse)
467 nexus_indexes[i]=indexes[i];
468 }
469 p++;
470 q++;
471 r++;
472 }
473 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
474 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +0000475 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +0000476 return(MagickFalse);
477 return(MagickTrue);
478}
479
480/*
481%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
482% %
483% %
484% %
485+ C l o n e P i x e l C a c h e %
486% %
487% %
488% %
489%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
490%
491% ClonePixelCache() clones a pixel cache.
492%
493% The format of the ClonePixelCache() method is:
494%
495% Cache ClonePixelCache(const Cache cache)
496%
497% A description of each parameter follows:
498%
499% o cache: the pixel cache.
500%
501*/
502MagickExport Cache ClonePixelCache(const Cache cache)
503{
504 CacheInfo
505 *clone_info;
506
507 const CacheInfo
508 *cache_info;
509
510 assert(cache != (const Cache) NULL);
511 cache_info=(const CacheInfo *) cache;
512 assert(cache_info->signature == MagickSignature);
513 if (cache_info->debug != MagickFalse)
514 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
515 cache_info->filename);
516 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
517 if (clone_info == (Cache) NULL)
518 return((Cache) NULL);
519 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
520 return((Cache ) clone_info);
521}
522
523/*
524%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
525% %
526% %
527% %
cristy60c44a82009-10-07 00:58:49 +0000528+ C l o n e P i x e l C a c h e P i x e l s %
cristy3ed852e2009-09-05 21:47:34 +0000529% %
530% %
531% %
532%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
533% ClonePixelCachePixels() clones the source pixel cache to the destination
534% cache.
535%
536% The format of the ClonePixelCachePixels() method is:
537%
538% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
539% CacheInfo *source_info,ExceptionInfo *exception)
540%
541% A description of each parameter follows:
542%
543% o cache_info: the pixel cache.
544%
545% o source_info: the source pixel cache.
546%
547% o exception: return any errors or warnings in this structure.
548%
549*/
550
551static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
552{
553 int
554 status;
555
cristy5ee247a2010-02-12 15:42:34 +0000556 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000557 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000558 if (cache_info->file != -1)
559 status=close(cache_info->file);
cristy3ed852e2009-09-05 21:47:34 +0000560 cache_info->file=(-1);
561 RelinquishMagickResource(FileResource,1);
cristyf84a1932010-01-03 18:00:18 +0000562 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000563 return(status == -1 ? MagickFalse : MagickTrue);
564}
565
566static void LimitPixelCacheDescriptors(void)
567{
568 register CacheInfo
569 *p,
570 *q;
571
572 /*
573 Limit # of open file descriptors.
574 */
575 if (GetMagickResource(FileResource) < GetMagickResourceLimit(FileResource))
576 return;
cristyf84a1932010-01-03 18:00:18 +0000577 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000578 if (cache_resources == (SplayTreeInfo *) NULL)
579 {
cristyf84a1932010-01-03 18:00:18 +0000580 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000581 return;
582 }
583 ResetSplayTreeIterator(cache_resources);
584 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
585 while (p != (CacheInfo *) NULL)
586 {
587 if ((p->type == DiskCache) && (p->file != -1))
cristy508d9312010-02-10 21:10:30 +0000588 break;
cristy3ed852e2009-09-05 21:47:34 +0000589 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
590 }
591 for (q=p; p != (CacheInfo *) NULL; )
592 {
593 if ((p->type == DiskCache) && (p->file != -1) &&
594 (p->timestamp < q->timestamp))
cristy508d9312010-02-10 21:10:30 +0000595 q=p;
cristy3ed852e2009-09-05 21:47:34 +0000596 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
597 }
598 if (q != (CacheInfo *) NULL)
cristy9e116922010-02-12 20:58:13 +0000599 {
600 /*
601 Close least recently used cache.
602 */
603 (void) close(q->file);
604 q->file=(-1);
605 }
cristyf84a1932010-01-03 18:00:18 +0000606 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000607}
608
609static inline MagickSizeType MagickMax(const MagickSizeType x,
610 const MagickSizeType y)
611{
612 if (x > y)
613 return(x);
614 return(y);
615}
616
617static inline MagickSizeType MagickMin(const MagickSizeType x,
618 const MagickSizeType y)
619{
620 if (x < y)
621 return(x);
622 return(y);
623}
624
625static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
626 const MapMode mode)
627{
628 int
629 file;
630
631 /*
632 Open pixel cache on disk.
633 */
cristyf84a1932010-01-03 18:00:18 +0000634 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000635 if (cache_info->file != -1)
636 {
cristyf84a1932010-01-03 18:00:18 +0000637 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000638 return(MagickTrue); /* cache already open */
639 }
640 LimitPixelCacheDescriptors();
641 if (*cache_info->cache_filename == '\0')
642 file=AcquireUniqueFileResource(cache_info->cache_filename);
643 else
644 switch (mode)
645 {
646 case ReadMode:
647 {
648 file=open(cache_info->cache_filename,O_RDONLY | O_BINARY);
649 break;
650 }
651 case WriteMode:
652 {
653 file=open(cache_info->cache_filename,O_WRONLY | O_CREAT | O_BINARY |
654 O_EXCL,S_MODE);
655 if (file == -1)
656 file=open(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
657 break;
658 }
659 case IOMode:
660 default:
661 {
662 file=open(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
663 O_EXCL,S_MODE);
664 if (file == -1)
665 file=open(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
666 break;
667 }
668 }
669 if (file == -1)
670 {
cristyf84a1932010-01-03 18:00:18 +0000671 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000672 return(MagickFalse);
673 }
674 (void) AcquireMagickResource(FileResource,1);
675 cache_info->file=file;
676 cache_info->timestamp=time(0);
cristyf84a1932010-01-03 18:00:18 +0000677 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000678 return(MagickTrue);
679}
680
681static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
682 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000683 unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000684{
685 register MagickOffsetType
686 i;
687
688 ssize_t
689 count;
690
cristy08a88202010-03-04 19:18:05 +0000691 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000692#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000693 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000694 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
695 {
cristyf84a1932010-01-03 18:00:18 +0000696 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000697 return((MagickOffsetType) -1);
698 }
699#endif
700 count=0;
701 for (i=0; i < (MagickOffsetType) length; i+=count)
702 {
703#if !defined(MAGICKCORE_HAVE_PREAD)
704 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
705 (MagickSizeType) SSIZE_MAX));
706#else
707 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
708 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
709#endif
710 if (count > 0)
711 continue;
712 count=0;
713 if (errno != EINTR)
714 {
715 i=(-1);
716 break;
717 }
718 }
719#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000720 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000721#endif
722 return(i);
723}
724
725static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
726 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000727 const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000728{
729 register MagickOffsetType
730 i;
731
732 ssize_t
733 count;
734
cristy08a88202010-03-04 19:18:05 +0000735 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000736#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000737 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000738 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
739 {
cristyf84a1932010-01-03 18:00:18 +0000740 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000741 return((MagickOffsetType) -1);
742 }
743#endif
744 count=0;
745 for (i=0; i < (MagickOffsetType) length; i+=count)
746 {
747#if !defined(MAGICKCORE_HAVE_PWRITE)
748 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
749 (MagickSizeType) SSIZE_MAX));
750#else
751 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
752 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
753#endif
754 if (count > 0)
755 continue;
756 count=0;
757 if (errno != EINTR)
758 {
759 i=(-1);
760 break;
761 }
762 }
763#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000764 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000765#endif
766 return(i);
767}
768
769static MagickBooleanType CloneDiskToDiskPixelCache(CacheInfo *clone_info,
770 CacheInfo *cache_info,ExceptionInfo *exception)
771{
772 MagickOffsetType
773 count,
774 offset,
775 source_offset;
776
777 MagickSizeType
778 length;
779
cristy3ed852e2009-09-05 21:47:34 +0000780 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000781 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +0000782
cristye076a6e2010-08-15 19:59:43 +0000783 register ssize_t
784 y;
785
cristybb503372010-05-27 20:51:26 +0000786 size_t
cristy3ed852e2009-09-05 21:47:34 +0000787 columns,
788 rows;
789
790 if (cache_info->debug != MagickFalse)
791 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
792 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
793 {
794 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
795 clone_info->cache_filename);
796 return(MagickFalse);
797 }
798 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
799 {
800 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
801 cache_info->cache_filename);
802 return(MagickFalse);
803 }
cristybb503372010-05-27 20:51:26 +0000804 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
805 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +0000806 if ((clone_info->active_index_channel != MagickFalse) &&
807 (cache_info->active_index_channel != MagickFalse))
808 {
809 register IndexPacket
810 *indexes;
811
812 /*
813 Clone cache indexes.
814 */
815 length=MagickMax(clone_info->columns,cache_info->columns)*
816 sizeof(*indexes);
817 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
818 if (indexes == (IndexPacket *) NULL)
819 {
820 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
821 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
822 return(MagickFalse);
823 }
824 (void) ResetMagickMemory(indexes,0,(size_t) length);
825 length=columns*sizeof(*indexes);
826 source_offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
827 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
828 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
829 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +0000830 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000831 {
832 source_offset-=cache_info->columns*sizeof(*indexes);
833 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
834 length,(unsigned char *) indexes);
835 if ((MagickSizeType) count != length)
836 break;
837 offset-=clone_info->columns*sizeof(*indexes);
838 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
839 (unsigned char *) indexes);
840 if ((MagickSizeType) count != length)
841 break;
842 }
cristybb503372010-05-27 20:51:26 +0000843 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000844 {
845 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
846 ThrowFileException(exception,CacheError,"UnableToCloneCache",
847 cache_info->cache_filename);
848 return(MagickFalse);
849 }
850 if (clone_info->columns > cache_info->columns)
851 {
852 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
853 (void) ResetMagickMemory(indexes,0,(size_t) length);
854 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
855 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +0000856 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000857 {
858 offset-=clone_info->columns*sizeof(*indexes);
859 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
860 length,(unsigned char *) indexes);
861 if ((MagickSizeType) count != length)
862 break;
863 }
cristybb503372010-05-27 20:51:26 +0000864 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000865 {
866 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
867 ThrowFileException(exception,CacheError,"UnableToCloneCache",
868 cache_info->cache_filename);
869 return(MagickFalse);
870 }
871 }
872 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
873 }
874 /*
875 Clone cache pixels.
876 */
877 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
878 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
879 if (pixels == (PixelPacket *) NULL)
880 {
881 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
882 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
883 return(MagickFalse);
884 }
885 (void) ResetMagickMemory(pixels,0,(size_t) length);
886 length=columns*sizeof(*pixels);
887 source_offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
888 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +0000889 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000890 {
891 source_offset-=cache_info->columns*sizeof(*pixels);
892 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
893 length,(unsigned char *) pixels);
894 if ((MagickSizeType) count != length)
895 break;
896 offset-=clone_info->columns*sizeof(*pixels);
897 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
898 (unsigned char *) pixels);
899 if ((MagickSizeType) count != length)
900 break;
901 }
cristybb503372010-05-27 20:51:26 +0000902 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000903 {
904 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
905 ThrowFileException(exception,CacheError,"UnableToCloneCache",
906 cache_info->cache_filename);
907 return(MagickFalse);
908 }
909 if (clone_info->columns > cache_info->columns)
910 {
911 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
912 sizeof(*pixels);
913 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
914 (void) ResetMagickMemory(pixels,0,(size_t) length);
cristybb503372010-05-27 20:51:26 +0000915 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000916 {
917 offset-=clone_info->columns*sizeof(*pixels);
918 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
919 (unsigned char *) pixels);
920 if ((MagickSizeType) count != length)
921 break;
922 }
cristybb503372010-05-27 20:51:26 +0000923 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000924 {
925 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
926 ThrowFileException(exception,CacheError,"UnableToCloneCache",
927 cache_info->cache_filename);
928 return(MagickFalse);
929 }
930 }
931 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
932 return(MagickTrue);
933}
934
935static MagickBooleanType CloneDiskToMemoryPixelCache(CacheInfo *clone_info,
936 CacheInfo *cache_info,ExceptionInfo *exception)
937{
938 MagickOffsetType
939 count,
940 offset;
941
942 MagickSizeType
943 length;
944
cristy3ed852e2009-09-05 21:47:34 +0000945 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000946 *restrict pixels,
947 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000948
cristye076a6e2010-08-15 19:59:43 +0000949 register ssize_t
950 y;
951
cristybb503372010-05-27 20:51:26 +0000952 size_t
cristy3ed852e2009-09-05 21:47:34 +0000953 columns,
954 rows;
955
956 if (cache_info->debug != MagickFalse)
957 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
958 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
959 {
960 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
961 cache_info->cache_filename);
962 return(MagickFalse);
963 }
cristybb503372010-05-27 20:51:26 +0000964 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
965 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +0000966 if ((clone_info->active_index_channel != MagickFalse) &&
967 (cache_info->active_index_channel != MagickFalse))
968 {
969 register IndexPacket
970 *indexes,
971 *q;
972
973 /*
974 Clone cache indexes.
975 */
976 length=MagickMax(clone_info->columns,cache_info->columns)*
977 sizeof(*indexes);
978 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
979 if (indexes == (IndexPacket *) NULL)
980 {
981 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
982 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
983 return(MagickFalse);
984 }
985 (void) ResetMagickMemory(indexes,0,(size_t) length);
986 length=columns*sizeof(IndexPacket);
987 offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
988 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
989 q=clone_info->indexes+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +0000990 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000991 {
992 offset-=cache_info->columns*sizeof(IndexPacket);
993 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,
994 length,(unsigned char *) indexes);
995 if ((MagickSizeType) count != length)
996 break;
997 q-=clone_info->columns;
cristy8f036fe2010-09-18 02:02:00 +0000998 (void) memcpy(q,indexes,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +0000999 if ((MagickSizeType) count != length)
1000 break;
1001 }
cristybb503372010-05-27 20:51:26 +00001002 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001003 {
1004 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1005 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1006 cache_info->cache_filename);
1007 return(MagickFalse);
1008 }
1009 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1010 }
1011 /*
1012 Clone cache pixels.
1013 */
1014 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1015 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1016 if (pixels == (PixelPacket *) NULL)
1017 {
1018 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1019 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1020 return(MagickFalse);
1021 }
1022 (void) ResetMagickMemory(pixels,0,(size_t) length);
1023 length=columns*sizeof(*pixels);
1024 offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
1025 q=clone_info->pixels+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001026 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001027 {
1028 offset-=cache_info->columns*sizeof(*pixels);
1029 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,length,
1030 (unsigned char *) pixels);
1031 if ((MagickSizeType) count != length)
1032 break;
1033 q-=clone_info->columns;
cristy8f036fe2010-09-18 02:02:00 +00001034 (void) memcpy(q,pixels,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00001035 }
cristybb503372010-05-27 20:51:26 +00001036 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001037 {
1038 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1039 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1040 cache_info->cache_filename);
1041 return(MagickFalse);
1042 }
1043 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1044 return(MagickTrue);
1045}
1046
1047static MagickBooleanType CloneMemoryToDiskPixelCache(CacheInfo *clone_info,
1048 CacheInfo *cache_info,ExceptionInfo *exception)
1049{
1050 MagickOffsetType
1051 count,
1052 offset;
1053
1054 MagickSizeType
1055 length;
1056
cristy3ed852e2009-09-05 21:47:34 +00001057 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001058 *restrict p,
1059 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +00001060
cristye076a6e2010-08-15 19:59:43 +00001061 register ssize_t
1062 y;
1063
cristybb503372010-05-27 20:51:26 +00001064 size_t
cristy3ed852e2009-09-05 21:47:34 +00001065 columns,
1066 rows;
1067
1068 if (cache_info->debug != MagickFalse)
1069 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
1070 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
1071 {
1072 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1073 clone_info->cache_filename);
1074 return(MagickFalse);
1075 }
cristybb503372010-05-27 20:51:26 +00001076 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1077 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001078 if ((clone_info->active_index_channel != MagickFalse) &&
1079 (cache_info->active_index_channel != MagickFalse))
1080 {
1081 register IndexPacket
1082 *p,
1083 *indexes;
1084
1085 /*
1086 Clone cache indexes.
1087 */
1088 length=MagickMax(clone_info->columns,cache_info->columns)*
1089 sizeof(*indexes);
1090 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
1091 if (indexes == (IndexPacket *) NULL)
1092 {
1093 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1094 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1095 return(MagickFalse);
1096 }
1097 (void) ResetMagickMemory(indexes,0,(size_t) length);
1098 length=columns*sizeof(*indexes);
1099 p=cache_info->indexes+cache_info->columns*rows;
1100 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1101 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +00001102 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001103 {
1104 p-=cache_info->columns;
cristy8f036fe2010-09-18 02:02:00 +00001105 (void) memcpy(indexes,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00001106 offset-=clone_info->columns*sizeof(*indexes);
1107 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1108 (unsigned char *) indexes);
1109 if ((MagickSizeType) count != length)
1110 break;
1111 }
cristybb503372010-05-27 20:51:26 +00001112 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001113 {
1114 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1115 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1116 cache_info->cache_filename);
1117 return(MagickFalse);
1118 }
1119 if (clone_info->columns > cache_info->columns)
1120 {
1121 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
1122 (void) ResetMagickMemory(indexes,0,(size_t) length);
1123 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1124 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +00001125 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001126 {
1127 offset-=clone_info->columns*sizeof(*indexes);
1128 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
1129 length,(unsigned char *) indexes);
1130 if ((MagickSizeType) count != length)
1131 break;
1132 }
cristybb503372010-05-27 20:51:26 +00001133 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001134 {
1135 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1136 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1137 cache_info->cache_filename);
1138 return(MagickFalse);
1139 }
1140 }
1141 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1142 }
1143 /*
1144 Clone cache pixels.
1145 */
1146 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1147 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1148 if (pixels == (PixelPacket *) NULL)
1149 {
1150 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1151 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1152 return(MagickFalse);
1153 }
1154 (void) ResetMagickMemory(pixels,0,(size_t) length);
1155 length=columns*sizeof(*pixels);
1156 p=cache_info->pixels+cache_info->columns*rows;
1157 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +00001158 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001159 {
1160 p-=cache_info->columns;
cristy8f036fe2010-09-18 02:02:00 +00001161 (void) memcpy(pixels,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00001162 offset-=clone_info->columns*sizeof(*pixels);
1163 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1164 (unsigned char *) pixels);
1165 if ((MagickSizeType) count != length)
1166 break;
1167 }
cristybb503372010-05-27 20:51:26 +00001168 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001169 {
1170 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1171 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1172 cache_info->cache_filename);
1173 return(MagickFalse);
1174 }
1175 if (clone_info->columns > cache_info->columns)
1176 {
1177 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
1178 sizeof(*pixels);
1179 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1180 (void) ResetMagickMemory(pixels,0,(size_t) length);
cristybb503372010-05-27 20:51:26 +00001181 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001182 {
1183 offset-=clone_info->columns*sizeof(*pixels);
1184 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1185 (unsigned char *) pixels);
1186 if ((MagickSizeType) count != length)
1187 break;
1188 }
cristybb503372010-05-27 20:51:26 +00001189 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001190 {
1191 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1192 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1193 cache_info->cache_filename);
1194 return(MagickFalse);
1195 }
1196 }
1197 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1198 return(MagickTrue);
1199}
1200
1201static MagickBooleanType CloneMemoryToMemoryPixelCache(CacheInfo *clone_info,
1202 CacheInfo *cache_info,ExceptionInfo *magick_unused(exception))
1203{
cristy3ed852e2009-09-05 21:47:34 +00001204 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001205 *restrict pixels,
1206 *restrict source_pixels;
cristy3ed852e2009-09-05 21:47:34 +00001207
cristye076a6e2010-08-15 19:59:43 +00001208 register ssize_t
1209 y;
cristy3ed852e2009-09-05 21:47:34 +00001210
cristybb503372010-05-27 20:51:26 +00001211 size_t
cristy3ed852e2009-09-05 21:47:34 +00001212 columns,
cristye076a6e2010-08-15 19:59:43 +00001213 length,
cristy3ed852e2009-09-05 21:47:34 +00001214 rows;
1215
1216 if (cache_info->debug != MagickFalse)
1217 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
cristybb503372010-05-27 20:51:26 +00001218 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1219 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001220 if ((clone_info->active_index_channel != MagickFalse) &&
1221 (cache_info->active_index_channel != MagickFalse))
1222 {
1223 register IndexPacket
1224 *indexes,
1225 *source_indexes;
1226
1227 /*
1228 Clone cache indexes.
1229 */
1230 length=columns*sizeof(*indexes);
1231 if (clone_info->columns == cache_info->columns)
cristy8f036fe2010-09-18 02:02:00 +00001232 (void) memcpy(clone_info->indexes,cache_info->indexes,length*rows);
cristy3ed852e2009-09-05 21:47:34 +00001233 else
1234 {
1235 source_indexes=cache_info->indexes+cache_info->columns*rows;
1236 indexes=clone_info->indexes+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001237 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001238 {
1239 source_indexes-=cache_info->columns;
1240 indexes-=clone_info->columns;
cristy8f036fe2010-09-18 02:02:00 +00001241 (void) memcpy(indexes,source_indexes,length);
cristy3ed852e2009-09-05 21:47:34 +00001242 }
1243 if (clone_info->columns > cache_info->columns)
1244 {
1245 length=(clone_info->columns-cache_info->columns)*
1246 sizeof(*indexes);
1247 indexes=clone_info->indexes+clone_info->columns*rows+
1248 cache_info->columns;
cristybb503372010-05-27 20:51:26 +00001249 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001250 {
1251 indexes-=clone_info->columns;
1252 (void) ResetMagickMemory(indexes,0,length);
1253 }
1254 }
1255 }
1256 }
1257 /*
1258 Clone cache pixels.
1259 */
1260 length=columns*sizeof(*pixels);
1261 if (clone_info->columns == cache_info->columns)
cristy8f036fe2010-09-18 02:02:00 +00001262 (void) memcpy(clone_info->pixels,cache_info->pixels,length*rows);
cristy3ed852e2009-09-05 21:47:34 +00001263 else
1264 {
1265 source_pixels=cache_info->pixels+cache_info->columns*rows;
1266 pixels=clone_info->pixels+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001267 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001268 {
1269 source_pixels-=cache_info->columns;
1270 pixels-=clone_info->columns;
cristy8f036fe2010-09-18 02:02:00 +00001271 (void) memcpy(pixels,source_pixels,length);
cristy3ed852e2009-09-05 21:47:34 +00001272 }
1273 if (clone_info->columns > cache_info->columns)
1274 {
1275 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1276 pixels=clone_info->pixels+clone_info->columns*rows+
1277 cache_info->columns;
cristybb503372010-05-27 20:51:26 +00001278 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001279 {
1280 pixels-=clone_info->columns;
1281 (void) ResetMagickMemory(pixels,0,length);
1282 }
1283 }
1284 }
1285 return(MagickTrue);
1286}
1287
1288static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1289 CacheInfo *cache_info,ExceptionInfo *exception)
1290{
cristy5a7fbfb2010-11-06 16:10:59 +00001291 if (cache_info->type == PingCache)
1292 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001293 if ((clone_info->type != DiskCache) && (cache_info->type != DiskCache))
1294 return(CloneMemoryToMemoryPixelCache(clone_info,cache_info,exception));
1295 if ((clone_info->type == DiskCache) && (cache_info->type == DiskCache))
1296 return(CloneDiskToDiskPixelCache(clone_info,cache_info,exception));
1297 if (cache_info->type == DiskCache)
1298 return(CloneDiskToMemoryPixelCache(clone_info,cache_info,exception));
1299 return(CloneMemoryToDiskPixelCache(clone_info,cache_info,exception));
1300}
1301
1302/*
1303%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1304% %
1305% %
1306% %
1307+ C l o n e P i x e l C a c h e M e t h o d s %
1308% %
1309% %
1310% %
1311%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1312%
1313% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1314% another.
1315%
1316% The format of the ClonePixelCacheMethods() method is:
1317%
1318% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1319%
1320% A description of each parameter follows:
1321%
1322% o clone: Specifies a pointer to a Cache structure.
1323%
1324% o cache: the pixel cache.
1325%
1326*/
1327MagickExport void ClonePixelCacheMethods(Cache clone,const Cache cache)
1328{
1329 CacheInfo
1330 *cache_info,
1331 *source_info;
1332
1333 assert(clone != (Cache) NULL);
1334 source_info=(CacheInfo *) clone;
1335 assert(source_info->signature == MagickSignature);
1336 if (source_info->debug != MagickFalse)
1337 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1338 source_info->filename);
1339 assert(cache != (Cache) NULL);
1340 cache_info=(CacheInfo *) cache;
1341 assert(cache_info->signature == MagickSignature);
1342 source_info->methods=cache_info->methods;
1343}
1344
1345/*
1346%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1347% %
1348% %
1349% %
1350+ D e s t r o y I m a g e P i x e l C a c h e %
1351% %
1352% %
1353% %
1354%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1355%
1356% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1357%
1358% The format of the DestroyImagePixelCache() method is:
1359%
1360% void DestroyImagePixelCache(Image *image)
1361%
1362% A description of each parameter follows:
1363%
1364% o image: the image.
1365%
1366*/
1367static void DestroyImagePixelCache(Image *image)
1368{
1369 assert(image != (Image *) NULL);
1370 assert(image->signature == MagickSignature);
1371 if (image->debug != MagickFalse)
1372 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1373 if (image->cache == (void *) NULL)
1374 return;
1375 image->cache=DestroyPixelCache(image->cache);
1376}
1377
1378/*
1379%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1380% %
1381% %
1382% %
1383+ D e s t r o y I m a g e P i x e l s %
1384% %
1385% %
1386% %
1387%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1388%
1389% DestroyImagePixels() deallocates memory associated with the pixel cache.
1390%
1391% The format of the DestroyImagePixels() method is:
1392%
1393% void DestroyImagePixels(Image *image)
1394%
1395% A description of each parameter follows:
1396%
1397% o image: the image.
1398%
1399*/
1400MagickExport void DestroyImagePixels(Image *image)
1401{
1402 CacheInfo
1403 *cache_info;
1404
1405 assert(image != (const Image *) NULL);
1406 assert(image->signature == MagickSignature);
1407 if (image->debug != MagickFalse)
1408 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1409 assert(image->cache != (Cache) NULL);
1410 cache_info=(CacheInfo *) image->cache;
1411 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001412 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1413 {
1414 cache_info->methods.destroy_pixel_handler(image);
1415 return;
1416 }
cristy2036f5c2010-09-19 21:18:17 +00001417 image->cache=DestroyPixelCache(image->cache);
cristy3ed852e2009-09-05 21:47:34 +00001418}
1419
1420/*
1421%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1422% %
1423% %
1424% %
1425+ D e s t r o y P i x e l C a c h e %
1426% %
1427% %
1428% %
1429%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1430%
1431% DestroyPixelCache() deallocates memory associated with the pixel cache.
1432%
1433% The format of the DestroyPixelCache() method is:
1434%
1435% Cache DestroyPixelCache(Cache cache)
1436%
1437% A description of each parameter follows:
1438%
1439% o cache: the pixel cache.
1440%
1441*/
1442
1443static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1444{
1445 switch (cache_info->type)
1446 {
1447 case MemoryCache:
1448 {
1449 if (cache_info->mapped == MagickFalse)
1450 cache_info->pixels=(PixelPacket *) RelinquishMagickMemory(
1451 cache_info->pixels);
1452 else
1453 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,
1454 (size_t) cache_info->length);
1455 RelinquishMagickResource(MemoryResource,cache_info->length);
1456 break;
1457 }
1458 case MapCache:
1459 {
1460 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,(size_t)
1461 cache_info->length);
1462 RelinquishMagickResource(MapResource,cache_info->length);
1463 }
1464 case DiskCache:
1465 {
1466 if (cache_info->file != -1)
1467 (void) ClosePixelCacheOnDisk(cache_info);
1468 RelinquishMagickResource(DiskResource,cache_info->length);
1469 break;
1470 }
1471 default:
1472 break;
1473 }
1474 cache_info->type=UndefinedCache;
1475 cache_info->mapped=MagickFalse;
1476 cache_info->indexes=(IndexPacket *) NULL;
1477}
1478
1479MagickExport Cache DestroyPixelCache(Cache cache)
1480{
1481 CacheInfo
1482 *cache_info;
1483
cristy3ed852e2009-09-05 21:47:34 +00001484 assert(cache != (Cache) NULL);
1485 cache_info=(CacheInfo *) cache;
1486 assert(cache_info->signature == MagickSignature);
1487 if (cache_info->debug != MagickFalse)
1488 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1489 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001490 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001491 cache_info->reference_count--;
1492 if (cache_info->reference_count != 0)
1493 {
cristyf84a1932010-01-03 18:00:18 +00001494 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001495 return((Cache) NULL);
1496 }
cristyf84a1932010-01-03 18:00:18 +00001497 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001498 if (cache_resources != (SplayTreeInfo *) NULL)
1499 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
cristy5b8de732009-09-10 23:50:40 +00001500 if (cache_info->debug != MagickFalse)
1501 {
1502 char
1503 message[MaxTextExtent];
1504
1505 (void) FormatMagickString(message,MaxTextExtent,"destroy %s",
1506 cache_info->filename);
1507 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1508 }
cristyc2e1bdd2009-09-10 23:43:34 +00001509 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1510 (cache_info->type != DiskCache)))
1511 RelinquishPixelCachePixels(cache_info);
1512 else
1513 {
1514 RelinquishPixelCachePixels(cache_info);
1515 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1516 }
cristy3ed852e2009-09-05 21:47:34 +00001517 *cache_info->cache_filename='\0';
1518 if (cache_info->nexus_info != (NexusInfo **) NULL)
1519 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1520 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001521 if (cache_info->random_info != (RandomInfo *) NULL)
1522 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001523 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1524 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1525 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1526 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001527 cache_info->signature=(~MagickSignature);
cristyb41ee102010-10-04 16:46:15 +00001528 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001529 cache=(Cache) NULL;
1530 return(cache);
1531}
1532
1533/*
1534%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1535% %
1536% %
1537% %
1538+ D e s t r o y P i x e l C a c h e N e x u s %
1539% %
1540% %
1541% %
1542%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1543%
1544% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1545%
1546% The format of the DestroyPixelCacheNexus() method is:
1547%
1548% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001549% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001550%
1551% A description of each parameter follows:
1552%
1553% o nexus_info: the nexus to destroy.
1554%
1555% o number_threads: the number of nexus threads.
1556%
1557*/
1558
1559static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1560{
1561 if (nexus_info->mapped == MagickFalse)
1562 (void) RelinquishMagickMemory(nexus_info->cache);
1563 else
1564 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1565 nexus_info->cache=(PixelPacket *) NULL;
1566 nexus_info->pixels=(PixelPacket *) NULL;
1567 nexus_info->indexes=(IndexPacket *) NULL;
1568 nexus_info->length=0;
1569 nexus_info->mapped=MagickFalse;
1570}
1571
1572MagickExport NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001573 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001574{
cristybb503372010-05-27 20:51:26 +00001575 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001576 i;
1577
1578 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001579 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001580 {
1581 if (nexus_info[i]->cache != (PixelPacket *) NULL)
1582 RelinquishCacheNexusPixels(nexus_info[i]);
1583 nexus_info[i]->signature=(~MagickSignature);
1584 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
1585 }
cristyb41ee102010-10-04 16:46:15 +00001586 nexus_info=(NexusInfo **) RelinquishMagickMemory(nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00001587 return(nexus_info);
1588}
1589
1590/*
1591%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1592% %
1593% %
1594% %
cristy3ed852e2009-09-05 21:47:34 +00001595+ 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 %
1596% %
1597% %
1598% %
1599%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1600%
1601% GetAuthenticIndexesFromCache() returns the indexes associated with the last
1602% call to QueueAuthenticPixelsCache() or GetAuthenticPixelsCache().
1603%
1604% The format of the GetAuthenticIndexesFromCache() method is:
1605%
1606% IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1607%
1608% A description of each parameter follows:
1609%
1610% o image: the image.
1611%
1612*/
1613static IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1614{
1615 CacheInfo
1616 *cache_info;
1617
cristy5c9e6f22010-09-17 17:31:01 +00001618 const int
1619 id = GetOpenMPThreadId();
1620
cristye7cc7cf2010-09-21 13:26:47 +00001621 assert(image != (const Image *) NULL);
1622 assert(image->signature == MagickSignature);
1623 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001624 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001625 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001626 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001627 return(GetPixelCacheNexusIndexes(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001628}
1629
1630/*
1631%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1632% %
1633% %
1634% %
1635% G e t A u t h e n t i c I n d e x Q u e u e %
1636% %
1637% %
1638% %
1639%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1640%
1641% GetAuthenticIndexQueue() returns the authentic black channel or the colormap
1642% indexes associated with the last call to QueueAuthenticPixels() or
1643% GetVirtualPixels(). NULL is returned if the black channel or colormap
1644% indexes are not available.
1645%
1646% The format of the GetAuthenticIndexQueue() method is:
1647%
1648% IndexPacket *GetAuthenticIndexQueue(const Image *image)
1649%
1650% A description of each parameter follows:
1651%
1652% o image: the image.
1653%
1654*/
1655MagickExport IndexPacket *GetAuthenticIndexQueue(const Image *image)
1656{
1657 CacheInfo
1658 *cache_info;
1659
cristy2036f5c2010-09-19 21:18:17 +00001660 const int
1661 id = GetOpenMPThreadId();
1662
cristy3ed852e2009-09-05 21:47:34 +00001663 assert(image != (const Image *) NULL);
1664 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001665 assert(image->cache != (Cache) NULL);
1666 cache_info=(CacheInfo *) image->cache;
1667 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001668 if (cache_info->methods.get_authentic_indexes_from_handler !=
cristy3ed852e2009-09-05 21:47:34 +00001669 (GetAuthenticIndexesFromHandler) NULL)
cristyd317f372010-09-18 01:42:20 +00001670 return(cache_info->methods.get_authentic_indexes_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001671 assert(id < (int) cache_info->number_threads);
1672 return(GetPixelCacheNexusIndexes(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001673}
1674
1675/*
1676%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1677% %
1678% %
1679% %
1680+ 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 %
1681% %
1682% %
1683% %
1684%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1685%
1686% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1687% disk pixel cache as defined by the geometry parameters. A pointer to the
1688% pixels is returned if the pixels are transferred, otherwise a NULL is
1689% returned.
1690%
1691% The format of the GetAuthenticPixelCacheNexus() method is:
1692%
cristybb503372010-05-27 20:51:26 +00001693% PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1694% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001695% NexusInfo *nexus_info,ExceptionInfo *exception)
1696%
1697% A description of each parameter follows:
1698%
1699% o image: the image.
1700%
1701% o x,y,columns,rows: These values define the perimeter of a region of
1702% pixels.
1703%
1704% o nexus_info: the cache nexus to return.
1705%
1706% o exception: return any errors or warnings in this structure.
1707%
1708*/
1709
1710static inline MagickBooleanType IsNexusInCore(const CacheInfo *cache_info,
1711 NexusInfo *nexus_info)
1712{
1713 MagickOffsetType
1714 offset;
1715
cristy73724512010-04-12 14:43:14 +00001716 if (cache_info->type == PingCache)
1717 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001718 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1719 nexus_info->region.x;
cristy096bf2c2010-09-22 11:55:02 +00001720 return(nexus_info->pixels == (cache_info->pixels+offset) ? MagickTrue :
1721 MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +00001722}
1723
cristye076a6e2010-08-15 19:59:43 +00001724MagickExport PixelPacket *GetAuthenticPixelCacheNexus(Image *image,
1725 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001726 NexusInfo *nexus_info,ExceptionInfo *exception)
1727{
1728 CacheInfo
1729 *cache_info;
1730
1731 PixelPacket
1732 *pixels;
1733
1734 /*
1735 Transfer pixels from the cache.
1736 */
1737 assert(image != (Image *) NULL);
1738 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001739 pixels=QueueAuthenticNexus(image,x,y,columns,rows,nexus_info,exception);
1740 if (pixels == (PixelPacket *) NULL)
1741 return((PixelPacket *) NULL);
1742 cache_info=(CacheInfo *) image->cache;
1743 assert(cache_info->signature == MagickSignature);
1744 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
1745 return(pixels);
1746 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1747 return((PixelPacket *) NULL);
1748 if (cache_info->active_index_channel != MagickFalse)
1749 if (ReadPixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse)
1750 return((PixelPacket *) NULL);
1751 return(pixels);
1752}
1753
1754/*
1755%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1756% %
1757% %
1758% %
1759+ 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 %
1760% %
1761% %
1762% %
1763%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1764%
1765% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1766% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1767%
1768% The format of the GetAuthenticPixelsFromCache() method is:
1769%
1770% PixelPacket *GetAuthenticPixelsFromCache(const Image image)
1771%
1772% A description of each parameter follows:
1773%
1774% o image: the image.
1775%
1776*/
1777static PixelPacket *GetAuthenticPixelsFromCache(const Image *image)
1778{
1779 CacheInfo
1780 *cache_info;
1781
cristy5c9e6f22010-09-17 17:31:01 +00001782 const int
1783 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001784
cristye7cc7cf2010-09-21 13:26:47 +00001785 assert(image != (const Image *) NULL);
1786 assert(image->signature == MagickSignature);
1787 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001788 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001789 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001790 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001791 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001792}
1793
1794/*
1795%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1796% %
1797% %
1798% %
1799% G e t A u t h e n t i c P i x e l Q u e u e %
1800% %
1801% %
1802% %
1803%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1804%
1805% GetAuthenticPixelQueue() returns the authentic pixels associated with the
1806% last call to QueueAuthenticPixels() or GetAuthenticPixels().
1807%
1808% The format of the GetAuthenticPixelQueue() method is:
1809%
1810% PixelPacket *GetAuthenticPixelQueue(const Image image)
1811%
1812% A description of each parameter follows:
1813%
1814% o image: the image.
1815%
1816*/
1817MagickExport PixelPacket *GetAuthenticPixelQueue(const Image *image)
1818{
1819 CacheInfo
1820 *cache_info;
1821
cristy2036f5c2010-09-19 21:18:17 +00001822 const int
1823 id = GetOpenMPThreadId();
1824
cristy3ed852e2009-09-05 21:47:34 +00001825 assert(image != (const Image *) NULL);
1826 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001827 assert(image->cache != (Cache) NULL);
1828 cache_info=(CacheInfo *) image->cache;
1829 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001830 if (cache_info->methods.get_authentic_pixels_from_handler !=
1831 (GetAuthenticPixelsFromHandler) NULL)
1832 return(cache_info->methods.get_authentic_pixels_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001833 assert(id < (int) cache_info->number_threads);
1834 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001835}
1836
1837/*
1838%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1839% %
1840% %
1841% %
1842% G e t A u t h e n t i c P i x e l s %
1843% %
1844% %
1845% %
1846%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1847%
1848% GetAuthenticPixels() obtains a pixel region for read/write access. If the
1849% region is successfully accessed, a pointer to a PixelPacket array
1850% representing the region is returned, otherwise NULL is returned.
1851%
1852% The returned pointer may point to a temporary working copy of the pixels
1853% or it may point to the original pixels in memory. Performance is maximized
1854% if the selected region is part of one row, or one or more full rows, since
1855% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001856% if the image is in memory, or in a memory-mapped file. The returned pointer
1857% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001858%
1859% Pixels accessed via the returned pointer represent a simple array of type
1860% PixelPacket. If the image type is CMYK or if the storage class is
1861% PseduoClass, call GetAuthenticIndexQueue() after invoking
1862% GetAuthenticPixels() to obtain the black color component or colormap indexes
1863% (of type IndexPacket) corresponding to the region. Once the PixelPacket
1864% (and/or IndexPacket) array has been updated, the changes must be saved back
1865% to the underlying image using SyncAuthenticPixels() or they may be lost.
1866%
1867% The format of the GetAuthenticPixels() method is:
1868%
cristy5f959472010-05-27 22:19:46 +00001869% PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1870% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001871% ExceptionInfo *exception)
1872%
1873% A description of each parameter follows:
1874%
1875% o image: the image.
1876%
1877% o x,y,columns,rows: These values define the perimeter of a region of
1878% pixels.
1879%
1880% o exception: return any errors or warnings in this structure.
1881%
1882*/
cristybb503372010-05-27 20:51:26 +00001883MagickExport PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1884 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001885 ExceptionInfo *exception)
1886{
1887 CacheInfo
1888 *cache_info;
1889
cristy2036f5c2010-09-19 21:18:17 +00001890 const int
1891 id = GetOpenMPThreadId();
1892
cristy3ed852e2009-09-05 21:47:34 +00001893 assert(image != (Image *) NULL);
1894 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001895 assert(image->cache != (Cache) NULL);
1896 cache_info=(CacheInfo *) image->cache;
1897 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001898 if (cache_info->methods.get_authentic_pixels_handler !=
1899 (GetAuthenticPixelsHandler) NULL)
1900 return(cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1901 rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00001902 assert(id < (int) cache_info->number_threads);
1903 return(GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1904 cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00001905}
1906
1907/*
1908%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1909% %
1910% %
1911% %
1912+ G e t A u t h e n t i c P i x e l s C a c h e %
1913% %
1914% %
1915% %
1916%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1917%
1918% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1919% as defined by the geometry parameters. A pointer to the pixels is returned
1920% if the pixels are transferred, otherwise a NULL is returned.
1921%
1922% The format of the GetAuthenticPixelsCache() method is:
1923%
cristybb503372010-05-27 20:51:26 +00001924% PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1925% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001926% ExceptionInfo *exception)
1927%
1928% A description of each parameter follows:
1929%
1930% o image: the image.
1931%
1932% o x,y,columns,rows: These values define the perimeter of a region of
1933% pixels.
1934%
1935% o exception: return any errors or warnings in this structure.
1936%
1937*/
cristybb503372010-05-27 20:51:26 +00001938static PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1939 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001940 ExceptionInfo *exception)
1941{
1942 CacheInfo
1943 *cache_info;
1944
cristy5c9e6f22010-09-17 17:31:01 +00001945 const int
1946 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001947
cristye7cc7cf2010-09-21 13:26:47 +00001948 assert(image != (const Image *) NULL);
1949 assert(image->signature == MagickSignature);
1950 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00001951 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001952 if (cache_info == (Cache) NULL)
1953 return((PixelPacket *) NULL);
cristye7cc7cf2010-09-21 13:26:47 +00001954 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001955 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001956 return(GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1957 cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00001958}
1959
1960/*
1961%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1962% %
1963% %
1964% %
1965+ G e t I m a g e E x t e n t %
1966% %
1967% %
1968% %
1969%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1970%
1971% GetImageExtent() returns the extent of the pixels associated with the
1972% last call to QueueAuthenticPixels() or GetAuthenticPixels().
1973%
1974% The format of the GetImageExtent() method is:
1975%
1976% MagickSizeType GetImageExtent(const Image *image)
1977%
1978% A description of each parameter follows:
1979%
1980% o image: the image.
1981%
1982*/
1983MagickExport MagickSizeType GetImageExtent(const Image *image)
1984{
1985 CacheInfo
1986 *cache_info;
1987
cristy5c9e6f22010-09-17 17:31:01 +00001988 const int
1989 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001990
cristy3ed852e2009-09-05 21:47:34 +00001991 assert(image != (Image *) NULL);
1992 assert(image->signature == MagickSignature);
1993 if (image->debug != MagickFalse)
1994 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1995 assert(image->cache != (Cache) NULL);
1996 cache_info=(CacheInfo *) image->cache;
1997 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001998 assert(id < (int) cache_info->number_threads);
cristy2036f5c2010-09-19 21:18:17 +00001999 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00002000}
2001
2002/*
2003%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2004% %
2005% %
2006% %
2007+ G e t I m a g e P i x e l C a c h e %
2008% %
2009% %
2010% %
2011%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2012%
2013% GetImagePixelCache() ensures that there is only a single reference to the
2014% pixel cache to be modified, updating the provided cache pointer to point to
2015% a clone of the original pixel cache if necessary.
2016%
2017% The format of the GetImagePixelCache method is:
2018%
2019% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2020% ExceptionInfo *exception)
2021%
2022% A description of each parameter follows:
2023%
2024% o image: the image.
2025%
2026% o clone: any value other than MagickFalse clones the cache pixels.
2027%
2028% o exception: return any errors or warnings in this structure.
2029%
2030*/
cristy3ed852e2009-09-05 21:47:34 +00002031static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
2032{
2033 CacheInfo
2034 *cache_info;
2035
2036 /*
2037 Does the image match the pixel cache morphology?
2038 */
2039 cache_info=(CacheInfo *) image->cache;
2040 if ((image->storage_class != cache_info->storage_class) ||
2041 (image->colorspace != cache_info->colorspace) ||
2042 (image->columns != cache_info->columns) ||
2043 (image->rows != cache_info->rows) ||
2044 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2045 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2046 return(MagickFalse);
2047 return(MagickTrue);
2048}
2049
cristy77ff0282010-09-13 00:51:10 +00002050static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2051 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002052{
2053 CacheInfo
2054 *cache_info;
2055
cristy3ed852e2009-09-05 21:47:34 +00002056 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00002057 destroy,
cristy3ed852e2009-09-05 21:47:34 +00002058 status;
2059
cristy50a10922010-02-15 18:35:25 +00002060 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00002061 cpu_throttle = 0,
2062 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00002063 time_limit = 0;
2064
cristy1ea34962010-07-01 19:49:21 +00002065 static time_t
cristya21afde2010-07-02 00:45:40 +00002066 cache_genesis = 0;
cristy1ea34962010-07-01 19:49:21 +00002067
cristyc4f9f132010-03-04 18:50:01 +00002068 status=MagickTrue;
2069 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00002070 if (cpu_throttle == 0)
2071 {
2072 char
2073 *limit;
2074
2075 /*
2076 Set CPU throttle in milleseconds.
2077 */
2078 cpu_throttle=MagickResourceInfinity;
2079 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2080 if (limit == (char *) NULL)
2081 limit=GetPolicyValue("throttle");
2082 if (limit != (char *) NULL)
2083 {
2084 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2085 limit=DestroyString(limit);
2086 }
2087 }
2088 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2089 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00002090 if (time_limit == 0)
2091 {
cristy6ebe97c2010-07-03 01:17:28 +00002092 /*
2093 Set the exire time in seconds.
2094 */
cristy1ea34962010-07-01 19:49:21 +00002095 time_limit=GetMagickResourceLimit(TimeResource);
cristya21afde2010-07-02 00:45:40 +00002096 cache_genesis=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00002097 }
2098 if ((time_limit != MagickResourceInfinity) &&
cristya21afde2010-07-02 00:45:40 +00002099 ((MagickSizeType) (time((time_t *) NULL)-cache_genesis) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00002100 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00002101 assert(image->cache != (Cache) NULL);
2102 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002103 destroy=MagickFalse;
cristyceb55ee2010-11-06 16:05:49 +00002104 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002105 {
cristyceb55ee2010-11-06 16:05:49 +00002106 LockSemaphoreInfo(cache_info->semaphore);
cristy4e6fa712010-11-06 16:06:12 +00002107 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002108 {
cristyceb55ee2010-11-06 16:05:49 +00002109 Image
2110 clone_image;
2111
2112 CacheInfo
2113 *clone_info;
2114
2115 /*
2116 Clone pixel cache.
2117 */
2118 clone_image=(*image);
2119 clone_image.semaphore=AllocateSemaphoreInfo();
2120 clone_image.reference_count=1;
2121 clone_image.cache=ClonePixelCache(cache_info);
2122 clone_info=(CacheInfo *) clone_image.cache;
2123 status=OpenPixelCache(&clone_image,IOMode,exception);
2124 if (status != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00002125 {
cristy5a7fbfb2010-11-06 16:10:59 +00002126 if (clone != MagickFalse)
cristy4e6fa712010-11-06 16:06:12 +00002127 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00002128 if (status != MagickFalse)
2129 {
cristyceb55ee2010-11-06 16:05:49 +00002130 destroy=MagickTrue;
2131 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00002132 }
2133 }
cristyceb55ee2010-11-06 16:05:49 +00002134 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002135 }
cristyceb55ee2010-11-06 16:05:49 +00002136 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002137 }
cristy4320e0e2009-09-10 15:00:08 +00002138 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002139 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002140 if (status != MagickFalse)
2141 {
2142 /*
2143 Ensure the image matches the pixel cache morphology.
2144 */
2145 image->taint=MagickTrue;
2146 image->type=UndefinedType;
cristydd438462010-05-06 13:44:04 +00002147 if (image->colorspace == GRAYColorspace)
2148 image->colorspace=RGBColorspace;
cristy3ed852e2009-09-05 21:47:34 +00002149 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2150 status=OpenPixelCache(image,IOMode,exception);
2151 }
cristyf84a1932010-01-03 18:00:18 +00002152 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002153 if (status == MagickFalse)
2154 return((Cache) NULL);
2155 return(image->cache);
2156}
2157
2158/*
2159%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2160% %
2161% %
2162% %
2163% G e t O n e A u t h e n t i c P i x e l %
2164% %
2165% %
2166% %
2167%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2168%
2169% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2170% location. The image background color is returned if an error occurs.
2171%
2172% The format of the GetOneAuthenticPixel() method is:
2173%
cristybb503372010-05-27 20:51:26 +00002174% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2175% const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002176%
2177% A description of each parameter follows:
2178%
2179% o image: the image.
2180%
2181% o x,y: These values define the location of the pixel to return.
2182%
2183% o pixel: return a pixel at the specified (x,y) location.
2184%
2185% o exception: return any errors or warnings in this structure.
2186%
2187*/
cristyacbbb7c2010-06-30 18:56:48 +00002188MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2189 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002190{
2191 CacheInfo
2192 *cache_info;
2193
cristy2036f5c2010-09-19 21:18:17 +00002194 PixelPacket
2195 *pixels;
2196
cristy3ed852e2009-09-05 21:47:34 +00002197 assert(image != (Image *) NULL);
2198 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002199 assert(image->cache != (Cache) NULL);
2200 cache_info=(CacheInfo *) image->cache;
2201 assert(cache_info->signature == MagickSignature);
2202 *pixel=image->background_color;
cristyd317f372010-09-18 01:42:20 +00002203 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2204 (GetOneAuthenticPixelFromHandler) NULL)
2205 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2206 pixel,exception));
cristy2036f5c2010-09-19 21:18:17 +00002207 *pixel=image->background_color;
2208 pixels=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2209 if (pixels == (PixelPacket *) NULL)
2210 return(MagickFalse);
2211 *pixel=(*pixels);
2212 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002213}
2214
2215/*
2216%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2217% %
2218% %
2219% %
2220+ 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 %
2221% %
2222% %
2223% %
2224%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2225%
2226% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2227% location. The image background color is returned if an error occurs.
2228%
2229% The format of the GetOneAuthenticPixelFromCache() method is:
2230%
2231% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy5f959472010-05-27 22:19:46 +00002232% const ssize_t x,const ssize_t y,PixelPacket *pixel,
2233% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002234%
2235% A description of each parameter follows:
2236%
2237% o image: the image.
2238%
2239% o x,y: These values define the location of the pixel to return.
2240%
2241% o pixel: return a pixel at the specified (x,y) location.
2242%
2243% o exception: return any errors or warnings in this structure.
2244%
2245*/
2246static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristybb503372010-05-27 20:51:26 +00002247 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002248{
cristy098f78c2010-09-23 17:28:44 +00002249 CacheInfo
2250 *cache_info;
2251
2252 const int
2253 id = GetOpenMPThreadId();
2254
cristy3ed852e2009-09-05 21:47:34 +00002255 PixelPacket
2256 *pixels;
2257
cristy0158a4b2010-09-20 13:59:45 +00002258 assert(image != (const Image *) NULL);
2259 assert(image->signature == MagickSignature);
2260 assert(image->cache != (Cache) NULL);
cristy098f78c2010-09-23 17:28:44 +00002261 cache_info=(CacheInfo *) image->cache;
2262 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002263 *pixel=image->background_color;
cristy098f78c2010-09-23 17:28:44 +00002264 assert(id < (int) cache_info->number_threads);
2265 pixels=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,
2266 cache_info->nexus_info[id],exception);
cristy3ed852e2009-09-05 21:47:34 +00002267 if (pixels == (PixelPacket *) NULL)
2268 return(MagickFalse);
2269 *pixel=(*pixels);
2270 return(MagickTrue);
2271}
2272
2273/*
2274%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2275% %
2276% %
2277% %
2278% G e t O n e V i r t u a l M a g i c k P i x e l %
2279% %
2280% %
2281% %
2282%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2283%
2284% GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2285% location. The image background color is returned if an error occurs. If
2286% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2287%
2288% The format of the GetOneVirtualMagickPixel() method is:
2289%
2290% MagickBooleanType GetOneVirtualMagickPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002291% const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
cristy3ed852e2009-09-05 21:47:34 +00002292% ExceptionInfo exception)
2293%
2294% A description of each parameter follows:
2295%
2296% o image: the image.
2297%
2298% o x,y: these values define the location of the pixel to return.
2299%
2300% o pixel: return a pixel at the specified (x,y) location.
2301%
2302% o exception: return any errors or warnings in this structure.
2303%
2304*/
2305MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
cristyacbbb7c2010-06-30 18:56:48 +00002306 const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
2307 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002308{
2309 CacheInfo
2310 *cache_info;
2311
cristy0158a4b2010-09-20 13:59:45 +00002312 const int
2313 id = GetOpenMPThreadId();
2314
cristy3ed852e2009-09-05 21:47:34 +00002315 register const IndexPacket
2316 *indexes;
2317
2318 register const PixelPacket
cristy0158a4b2010-09-20 13:59:45 +00002319 *pixels;
cristy3ed852e2009-09-05 21:47:34 +00002320
2321 assert(image != (const Image *) NULL);
2322 assert(image->signature == MagickSignature);
2323 assert(image->cache != (Cache) NULL);
2324 cache_info=(CacheInfo *) image->cache;
2325 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002326 assert(id < (int) cache_info->number_threads);
2327 pixels=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2328 1UL,1UL,cache_info->nexus_info[id],exception);
cristye7cc7cf2010-09-21 13:26:47 +00002329 GetMagickPixelPacket(image,pixel);
cristy0158a4b2010-09-20 13:59:45 +00002330 if (pixels == (const PixelPacket *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002331 return(MagickFalse);
cristy098f78c2010-09-23 17:28:44 +00002332 indexes=GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[id]);
cristy0158a4b2010-09-20 13:59:45 +00002333 SetMagickPixelPacket(image,pixels,indexes,pixel);
cristy3ed852e2009-09-05 21:47:34 +00002334 return(MagickTrue);
2335}
2336
2337/*
2338%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2339% %
2340% %
2341% %
2342% G e t O n e V i r t u a l M e t h o d P i x e l %
2343% %
2344% %
2345% %
2346%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2347%
2348% GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2349% location as defined by specified pixel method. The image background color
2350% is returned if an error occurs. If you plan to modify the pixel, use
2351% GetOneAuthenticPixel() instead.
2352%
2353% The format of the GetOneVirtualMethodPixel() method is:
2354%
2355% MagickBooleanType GetOneVirtualMethodPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002356% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2357% const ssize_t y,Pixelpacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002358%
2359% A description of each parameter follows:
2360%
2361% o image: the image.
2362%
2363% o virtual_pixel_method: the virtual pixel method.
2364%
2365% o x,y: These values define the location of the pixel to return.
2366%
2367% o pixel: return a pixel at the specified (x,y) location.
2368%
2369% o exception: return any errors or warnings in this structure.
2370%
2371*/
2372MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002373 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002374 PixelPacket *pixel,ExceptionInfo *exception)
2375{
cristy3ed852e2009-09-05 21:47:34 +00002376 CacheInfo
2377 *cache_info;
2378
cristy0158a4b2010-09-20 13:59:45 +00002379 const int
2380 id = GetOpenMPThreadId();
2381
cristy2036f5c2010-09-19 21:18:17 +00002382 const PixelPacket
2383 *pixels;
2384
cristy3ed852e2009-09-05 21:47:34 +00002385 assert(image != (const Image *) NULL);
2386 assert(image->signature == MagickSignature);
2387 assert(image->cache != (Cache) NULL);
2388 cache_info=(CacheInfo *) image->cache;
2389 assert(cache_info->signature == MagickSignature);
2390 *pixel=image->background_color;
cristyd317f372010-09-18 01:42:20 +00002391 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2392 (GetOneVirtualPixelFromHandler) NULL)
2393 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2394 virtual_pixel_method,x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002395 assert(id < (int) cache_info->number_threads);
2396 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2397 cache_info->nexus_info[id],exception);
cristy2036f5c2010-09-19 21:18:17 +00002398 if (pixels == (const PixelPacket *) NULL)
2399 return(MagickFalse);
2400 *pixel=(*pixels);
2401 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002402}
2403
2404/*
2405%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2406% %
2407% %
2408% %
2409% G e t O n e V i r t u a l P i x e l %
2410% %
2411% %
2412% %
2413%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2414%
2415% GetOneVirtualPixel() returns a single virtual pixel at the specified
2416% (x,y) location. The image background color is returned if an error occurs.
2417% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2418%
2419% The format of the GetOneVirtualPixel() method is:
2420%
cristybb503372010-05-27 20:51:26 +00002421% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2422% const ssize_t y,PixelPacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002423%
2424% A description of each parameter follows:
2425%
2426% o image: the image.
2427%
2428% o x,y: These values define the location of the pixel to return.
2429%
2430% o pixel: return a pixel at the specified (x,y) location.
2431%
2432% o exception: return any errors or warnings in this structure.
2433%
2434*/
2435MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002436 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002437{
cristy3ed852e2009-09-05 21:47:34 +00002438 CacheInfo
2439 *cache_info;
2440
cristy0158a4b2010-09-20 13:59:45 +00002441 const int
2442 id = GetOpenMPThreadId();
2443
cristy2036f5c2010-09-19 21:18:17 +00002444 const PixelPacket
2445 *pixels;
2446
cristy3ed852e2009-09-05 21:47:34 +00002447 assert(image != (const Image *) NULL);
2448 assert(image->signature == MagickSignature);
2449 assert(image->cache != (Cache) NULL);
2450 cache_info=(CacheInfo *) image->cache;
2451 assert(cache_info->signature == MagickSignature);
2452 *pixel=image->background_color;
cristyd317f372010-09-18 01:42:20 +00002453 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2454 (GetOneVirtualPixelFromHandler) NULL)
2455 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2456 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002457 assert(id < (int) cache_info->number_threads);
2458 pixels=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2459 1UL,1UL,cache_info->nexus_info[id],exception);
cristy2036f5c2010-09-19 21:18:17 +00002460 if (pixels == (const PixelPacket *) NULL)
2461 return(MagickFalse);
2462 *pixel=(*pixels);
2463 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002464}
2465
2466/*
2467%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2468% %
2469% %
2470% %
2471+ 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 %
2472% %
2473% %
2474% %
2475%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2476%
2477% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2478% specified (x,y) location. The image background color is returned if an
2479% error occurs.
2480%
2481% The format of the GetOneVirtualPixelFromCache() method is:
2482%
2483% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristybb503372010-05-27 20:51:26 +00002484% const VirtualPixelPacket method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002485% PixelPacket *pixel,ExceptionInfo *exception)
2486%
2487% A description of each parameter follows:
2488%
2489% o image: the image.
2490%
2491% o virtual_pixel_method: the virtual pixel method.
2492%
2493% o x,y: These values define the location of the pixel to return.
2494%
2495% o pixel: return a pixel at the specified (x,y) location.
2496%
2497% o exception: return any errors or warnings in this structure.
2498%
2499*/
2500static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002501 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002502 PixelPacket *pixel,ExceptionInfo *exception)
2503{
cristy0158a4b2010-09-20 13:59:45 +00002504 CacheInfo
2505 *cache_info;
2506
2507 const int
2508 id = GetOpenMPThreadId();
2509
cristy3ed852e2009-09-05 21:47:34 +00002510 const PixelPacket
2511 *pixels;
2512
cristye7cc7cf2010-09-21 13:26:47 +00002513 assert(image != (const Image *) NULL);
2514 assert(image->signature == MagickSignature);
2515 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002516 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002517 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002518 assert(id < (int) cache_info->number_threads);
cristye7cc7cf2010-09-21 13:26:47 +00002519 *pixel=image->background_color;
cristy0158a4b2010-09-20 13:59:45 +00002520 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2521 cache_info->nexus_info[id],exception);
cristy3ed852e2009-09-05 21:47:34 +00002522 if (pixels == (const PixelPacket *) NULL)
2523 return(MagickFalse);
2524 *pixel=(*pixels);
2525 return(MagickTrue);
2526}
2527
2528/*
2529%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2530% %
2531% %
2532% %
2533+ G e t P i x e l C a c h e C o l o r s p a c e %
2534% %
2535% %
2536% %
2537%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2538%
2539% GetPixelCacheColorspace() returns the class type of the pixel cache.
2540%
2541% The format of the GetPixelCacheColorspace() method is:
2542%
2543% Colorspace GetPixelCacheColorspace(Cache cache)
2544%
2545% A description of each parameter follows:
2546%
2547% o cache: the pixel cache.
2548%
2549*/
2550MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
2551{
2552 CacheInfo
2553 *cache_info;
2554
2555 assert(cache != (Cache) NULL);
2556 cache_info=(CacheInfo *) cache;
2557 assert(cache_info->signature == MagickSignature);
2558 if (cache_info->debug != MagickFalse)
2559 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2560 cache_info->filename);
2561 return(cache_info->colorspace);
2562}
2563
2564/*
2565%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2566% %
2567% %
2568% %
2569+ G e t P i x e l C a c h e M e t h o d s %
2570% %
2571% %
2572% %
2573%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2574%
2575% GetPixelCacheMethods() initializes the CacheMethods structure.
2576%
2577% The format of the GetPixelCacheMethods() method is:
2578%
2579% void GetPixelCacheMethods(CacheMethods *cache_methods)
2580%
2581% A description of each parameter follows:
2582%
2583% o cache_methods: Specifies a pointer to a CacheMethods structure.
2584%
2585*/
2586MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
2587{
2588 assert(cache_methods != (CacheMethods *) NULL);
2589 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2590 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2591 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2592 cache_methods->get_virtual_indexes_from_handler=GetVirtualIndexesFromCache;
2593 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2594 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2595 cache_methods->get_authentic_indexes_from_handler=
2596 GetAuthenticIndexesFromCache;
2597 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2598 cache_methods->get_one_authentic_pixel_from_handler=
2599 GetOneAuthenticPixelFromCache;
2600 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2601 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2602 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2603}
2604
2605/*
2606%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2607% %
2608% %
2609% %
2610+ G e t P i x e l C a c h e N e x u s E x t e n t %
2611% %
2612% %
2613% %
2614%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2615%
2616% GetPixelCacheNexusExtent() returns the extent of the pixels associated with
2617% the last call to SetPixelCacheNexusPixels() or GetPixelCacheNexusPixels().
2618%
2619% The format of the GetPixelCacheNexusExtent() method is:
2620%
2621% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2622% NexusInfo *nexus_info)
2623%
2624% A description of each parameter follows:
2625%
2626% o nexus_info: the nexus info.
2627%
2628*/
2629MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2630 NexusInfo *nexus_info)
2631{
2632 CacheInfo
2633 *cache_info;
2634
2635 MagickSizeType
2636 extent;
2637
cristye7cc7cf2010-09-21 13:26:47 +00002638 assert(cache != (const Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002639 cache_info=(CacheInfo *) cache;
2640 assert(cache_info->signature == MagickSignature);
2641 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2642 if (extent == 0)
2643 return((MagickSizeType) cache_info->columns*cache_info->rows);
2644 return(extent);
2645}
2646
2647/*
2648%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2649% %
2650% %
2651% %
2652+ 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 %
2653% %
2654% %
2655% %
2656%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2657%
2658% GetPixelCacheNexusIndexes() returns the indexes associated with the
2659% specified cache nexus.
2660%
2661% The format of the GetPixelCacheNexusIndexes() method is:
2662%
2663% IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2664% NexusInfo *nexus_info)
2665%
2666% A description of each parameter follows:
2667%
2668% o cache: the pixel cache.
2669%
2670% o nexus_info: the cache nexus to return the colormap indexes.
2671%
2672*/
2673MagickExport IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2674 NexusInfo *nexus_info)
2675{
2676 CacheInfo
2677 *cache_info;
2678
cristye7cc7cf2010-09-21 13:26:47 +00002679 assert(cache != (const Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002680 cache_info=(CacheInfo *) cache;
2681 assert(cache_info->signature == MagickSignature);
2682 if (cache_info->storage_class == UndefinedClass)
2683 return((IndexPacket *) NULL);
2684 return(nexus_info->indexes);
2685}
2686
2687/*
2688%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2689% %
2690% %
2691% %
2692+ G e t P i x e l C a c h e N e x u s P i x e l s %
2693% %
2694% %
2695% %
2696%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2697%
2698% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2699% cache nexus.
2700%
2701% The format of the GetPixelCacheNexusPixels() method is:
2702%
2703% PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2704% NexusInfo *nexus_info)
2705%
2706% A description of each parameter follows:
2707%
2708% o cache: the pixel cache.
2709%
2710% o nexus_info: the cache nexus to return the pixels.
2711%
2712*/
2713MagickExport PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2714 NexusInfo *nexus_info)
2715{
2716 CacheInfo
2717 *cache_info;
2718
cristye7cc7cf2010-09-21 13:26:47 +00002719 assert(cache != (const Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002720 cache_info=(CacheInfo *) cache;
2721 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002722 if (cache_info->storage_class == UndefinedClass)
2723 return((PixelPacket *) NULL);
2724 return(nexus_info->pixels);
2725}
2726
2727/*
2728%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2729% %
2730% %
2731% %
cristy056ba772010-01-02 23:33:54 +00002732+ G e t P i x e l C a c h e P i x e l s %
2733% %
2734% %
2735% %
2736%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2737%
2738% GetPixelCachePixels() returns the pixels associated with the specified image.
2739%
2740% The format of the GetPixelCachePixels() method is:
2741%
cristyf84a1932010-01-03 18:00:18 +00002742% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2743% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002744%
2745% A description of each parameter follows:
2746%
2747% o image: the image.
2748%
2749% o length: the pixel cache length.
2750%
cristyf84a1932010-01-03 18:00:18 +00002751% o exception: return any errors or warnings in this structure.
2752%
cristy056ba772010-01-02 23:33:54 +00002753*/
cristyf84a1932010-01-03 18:00:18 +00002754MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2755 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002756{
2757 CacheInfo
2758 *cache_info;
2759
2760 assert(image != (const Image *) NULL);
2761 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002762 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00002763 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002764 assert(cache_info->signature == MagickSignature);
2765 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002766 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002767 return((void *) NULL);
2768 *length=cache_info->length;
2769 return((void *) cache_info->pixels);
2770}
2771
2772/*
2773%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2774% %
2775% %
2776% %
cristyb32b90a2009-09-07 21:45:48 +00002777+ 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 +00002778% %
2779% %
2780% %
2781%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2782%
2783% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2784%
2785% The format of the GetPixelCacheStorageClass() method is:
2786%
2787% ClassType GetPixelCacheStorageClass(Cache cache)
2788%
2789% A description of each parameter follows:
2790%
2791% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2792%
2793% o cache: the pixel cache.
2794%
2795*/
2796MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
2797{
2798 CacheInfo
2799 *cache_info;
2800
2801 assert(cache != (Cache) NULL);
2802 cache_info=(CacheInfo *) cache;
2803 assert(cache_info->signature == MagickSignature);
2804 if (cache_info->debug != MagickFalse)
2805 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2806 cache_info->filename);
2807 return(cache_info->storage_class);
2808}
2809
2810/*
2811%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2812% %
2813% %
2814% %
cristyb32b90a2009-09-07 21:45:48 +00002815+ G e t P i x e l C a c h e T i l e S i z e %
2816% %
2817% %
2818% %
2819%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2820%
2821% GetPixelCacheTileSize() returns the pixel cache tile size.
2822%
2823% The format of the GetPixelCacheTileSize() method is:
2824%
cristybb503372010-05-27 20:51:26 +00002825% void GetPixelCacheTileSize(const Image *image,size_t *width,
2826% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002827%
2828% A description of each parameter follows:
2829%
2830% o image: the image.
2831%
2832% o width: the optimize cache tile width in pixels.
2833%
2834% o height: the optimize cache tile height in pixels.
2835%
2836*/
cristybb503372010-05-27 20:51:26 +00002837MagickExport void GetPixelCacheTileSize(const Image *image,size_t *width,
2838 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002839{
cristyb32b90a2009-09-07 21:45:48 +00002840 assert(image != (Image *) NULL);
2841 assert(image->signature == MagickSignature);
2842 if (image->debug != MagickFalse)
2843 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristyb32b90a2009-09-07 21:45:48 +00002844 *width=2048UL/sizeof(PixelPacket);
2845 if (GetPixelCacheType(image) == DiskCache)
cristydaa97692009-09-13 02:10:35 +00002846 *width=8192UL/sizeof(PixelPacket);
cristyb32b90a2009-09-07 21:45:48 +00002847 *height=(*width);
2848}
2849
2850/*
2851%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2852% %
2853% %
2854% %
2855+ G e t P i x e l C a c h e T y p e %
2856% %
2857% %
2858% %
2859%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2860%
2861% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2862%
2863% The format of the GetPixelCacheType() method is:
2864%
2865% CacheType GetPixelCacheType(const Image *image)
2866%
2867% A description of each parameter follows:
2868%
2869% o image: the image.
2870%
2871*/
2872MagickExport CacheType GetPixelCacheType(const Image *image)
2873{
2874 CacheInfo
2875 *cache_info;
2876
2877 assert(image != (Image *) NULL);
2878 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002879 assert(image->cache != (Cache) NULL);
2880 cache_info=(CacheInfo *) image->cache;
2881 assert(cache_info->signature == MagickSignature);
2882 return(cache_info->type);
2883}
2884
2885/*
2886%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2887% %
2888% %
2889% %
cristy3ed852e2009-09-05 21:47:34 +00002890+ 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 %
2891% %
2892% %
2893% %
2894%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2895%
2896% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2897% pixel cache. A virtual pixel is any pixel access that is outside the
2898% boundaries of the image cache.
2899%
2900% The format of the GetPixelCacheVirtualMethod() method is:
2901%
2902% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2903%
2904% A description of each parameter follows:
2905%
2906% o image: the image.
2907%
2908*/
2909MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2910{
2911 CacheInfo
2912 *cache_info;
2913
2914 assert(image != (Image *) NULL);
2915 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002916 assert(image->cache != (Cache) NULL);
2917 cache_info=(CacheInfo *) image->cache;
2918 assert(cache_info->signature == MagickSignature);
2919 return(cache_info->virtual_pixel_method);
2920}
2921
2922/*
2923%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2924% %
2925% %
2926% %
2927+ 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 %
2928% %
2929% %
2930% %
2931%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2932%
2933% GetVirtualIndexesFromCache() returns the indexes associated with the last
2934% call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2935%
2936% The format of the GetVirtualIndexesFromCache() method is:
2937%
2938% IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2939%
2940% A description of each parameter follows:
2941%
2942% o image: the image.
2943%
2944*/
2945static const IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2946{
2947 CacheInfo
2948 *cache_info;
2949
cristy5c9e6f22010-09-17 17:31:01 +00002950 const int
2951 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002952
cristye7cc7cf2010-09-21 13:26:47 +00002953 assert(image != (const Image *) NULL);
2954 assert(image->signature == MagickSignature);
2955 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002956 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002957 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002958 assert(id < (int) cache_info->number_threads);
cristye7cc7cf2010-09-21 13:26:47 +00002959 return(GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00002960}
2961
2962/*
2963%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2964% %
2965% %
2966% %
2967+ 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 %
2968% %
2969% %
2970% %
2971%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2972%
2973% GetVirtualIndexesFromNexus() returns the indexes associated with the
2974% specified cache nexus.
2975%
2976% The format of the GetVirtualIndexesFromNexus() method is:
2977%
2978% const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2979% NexusInfo *nexus_info)
2980%
2981% A description of each parameter follows:
2982%
2983% o cache: the pixel cache.
2984%
2985% o nexus_info: the cache nexus to return the colormap indexes.
2986%
2987*/
2988MagickExport const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2989 NexusInfo *nexus_info)
2990{
2991 CacheInfo
2992 *cache_info;
2993
cristye7cc7cf2010-09-21 13:26:47 +00002994 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002995 cache_info=(CacheInfo *) cache;
2996 assert(cache_info->signature == MagickSignature);
2997 if (cache_info->storage_class == UndefinedClass)
2998 return((IndexPacket *) NULL);
2999 return(nexus_info->indexes);
3000}
3001
3002/*
3003%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3004% %
3005% %
3006% %
3007% G e t V i r t u a l I n d e x Q u e u e %
3008% %
3009% %
3010% %
3011%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3012%
3013% GetVirtualIndexQueue() returns the virtual black channel or the
3014% colormap indexes associated with the last call to QueueAuthenticPixels() or
3015% GetVirtualPixels(). NULL is returned if the black channel or colormap
3016% indexes are not available.
3017%
3018% The format of the GetVirtualIndexQueue() method is:
3019%
3020% const IndexPacket *GetVirtualIndexQueue(const Image *image)
3021%
3022% A description of each parameter follows:
3023%
3024% o image: the image.
3025%
3026*/
3027MagickExport const IndexPacket *GetVirtualIndexQueue(const Image *image)
3028{
3029 CacheInfo
3030 *cache_info;
3031
cristy2036f5c2010-09-19 21:18:17 +00003032 const int
3033 id = GetOpenMPThreadId();
3034
cristy3ed852e2009-09-05 21:47:34 +00003035 assert(image != (const Image *) NULL);
3036 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003037 assert(image->cache != (Cache) NULL);
3038 cache_info=(CacheInfo *) image->cache;
3039 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003040 if (cache_info->methods.get_virtual_indexes_from_handler !=
3041 (GetVirtualIndexesFromHandler) NULL)
3042 return(cache_info->methods.get_virtual_indexes_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003043 assert(id < (int) cache_info->number_threads);
3044 return(GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003045}
3046
3047/*
3048%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3049% %
3050% %
3051% %
3052+ 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 %
3053% %
3054% %
3055% %
3056%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3057%
3058% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3059% pixel cache as defined by the geometry parameters. A pointer to the pixels
3060% is returned if the pixels are transferred, otherwise a NULL is returned.
3061%
3062% The format of the GetVirtualPixelsFromNexus() method is:
3063%
3064% PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003065% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00003066% const size_t columns,const size_t rows,NexusInfo *nexus_info,
3067% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003068%
3069% A description of each parameter follows:
3070%
3071% o image: the image.
3072%
3073% o virtual_pixel_method: the virtual pixel method.
3074%
3075% o x,y,columns,rows: These values define the perimeter of a region of
3076% pixels.
3077%
3078% o nexus_info: the cache nexus to acquire.
3079%
3080% o exception: return any errors or warnings in this structure.
3081%
3082*/
3083
cristybb503372010-05-27 20:51:26 +00003084static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003085 DitherMatrix[64] =
3086 {
3087 0, 48, 12, 60, 3, 51, 15, 63,
3088 32, 16, 44, 28, 35, 19, 47, 31,
3089 8, 56, 4, 52, 11, 59, 7, 55,
3090 40, 24, 36, 20, 43, 27, 39, 23,
3091 2, 50, 14, 62, 1, 49, 13, 61,
3092 34, 18, 46, 30, 33, 17, 45, 29,
3093 10, 58, 6, 54, 9, 57, 5, 53,
3094 42, 26, 38, 22, 41, 25, 37, 21
3095 };
3096
cristybb503372010-05-27 20:51:26 +00003097static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003098{
cristybb503372010-05-27 20:51:26 +00003099 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003100 index;
3101
3102 index=x+DitherMatrix[x & 0x07]-32L;
3103 if (index < 0L)
3104 return(0L);
cristybb503372010-05-27 20:51:26 +00003105 if (index >= (ssize_t) columns)
3106 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00003107 return(index);
3108}
3109
cristybb503372010-05-27 20:51:26 +00003110static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003111{
cristybb503372010-05-27 20:51:26 +00003112 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003113 index;
3114
3115 index=y+DitherMatrix[y & 0x07]-32L;
3116 if (index < 0L)
3117 return(0L);
cristybb503372010-05-27 20:51:26 +00003118 if (index >= (ssize_t) rows)
3119 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00003120 return(index);
3121}
3122
cristybb503372010-05-27 20:51:26 +00003123static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003124{
3125 if (x < 0L)
3126 return(0L);
cristybb503372010-05-27 20:51:26 +00003127 if (x >= (ssize_t) columns)
3128 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003129 return(x);
3130}
3131
cristybb503372010-05-27 20:51:26 +00003132static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003133{
3134 if (y < 0L)
3135 return(0L);
cristybb503372010-05-27 20:51:26 +00003136 if (y >= (ssize_t) rows)
3137 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003138 return(y);
3139}
3140
cristybb503372010-05-27 20:51:26 +00003141static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003142{
cristybb503372010-05-27 20:51:26 +00003143 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003144}
3145
cristybb503372010-05-27 20:51:26 +00003146static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003147{
cristybb503372010-05-27 20:51:26 +00003148 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003149}
3150
3151/*
3152 VirtualPixelModulo() computes the remainder of dividing offset by extent. It
3153 returns not only the quotient (tile the offset falls in) but also the positive
3154 remainer within that tile such that 0 <= remainder < extent. This method is
3155 essentially a ldiv() using a floored modulo division rather than the normal
3156 default truncated modulo division.
3157*/
cristybb503372010-05-27 20:51:26 +00003158static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3159 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003160{
3161 MagickModulo
3162 modulo;
3163
cristybb503372010-05-27 20:51:26 +00003164 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003165 if (offset < 0L)
3166 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003167 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003168 return(modulo);
3169}
3170
3171MagickExport const PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003172 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3173 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003174 ExceptionInfo *exception)
3175{
3176 CacheInfo
3177 *cache_info;
3178
cristyc3ec0d42010-04-07 01:18:08 +00003179 IndexPacket
3180 virtual_index;
3181
cristy3ed852e2009-09-05 21:47:34 +00003182 MagickOffsetType
3183 offset;
3184
3185 MagickSizeType
3186 length,
3187 number_pixels;
3188
3189 NexusInfo
3190 **virtual_nexus;
3191
3192 PixelPacket
3193 *pixels,
3194 virtual_pixel;
3195
3196 RectangleInfo
3197 region;
3198
3199 register const IndexPacket
cristyc3ec0d42010-04-07 01:18:08 +00003200 *restrict virtual_indexes;
cristy3ed852e2009-09-05 21:47:34 +00003201
3202 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003203 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003204
3205 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003206 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003207
cristye076a6e2010-08-15 19:59:43 +00003208 register PixelPacket
3209 *restrict q;
3210
cristybb503372010-05-27 20:51:26 +00003211 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003212 u,
3213 v;
3214
cristy3ed852e2009-09-05 21:47:34 +00003215 /*
3216 Acquire pixels.
3217 */
cristye7cc7cf2010-09-21 13:26:47 +00003218 assert(image != (const Image *) NULL);
3219 assert(image->signature == MagickSignature);
3220 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003221 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003222 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003223 if (cache_info->type == UndefinedCache)
cristy3ed852e2009-09-05 21:47:34 +00003224 return((const PixelPacket *) NULL);
3225 region.x=x;
3226 region.y=y;
3227 region.width=columns;
3228 region.height=rows;
3229 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
3230 if (pixels == (PixelPacket *) NULL)
3231 return((const PixelPacket *) NULL);
cristydf415c82010-03-11 16:47:50 +00003232 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3233 nexus_info->region.x;
3234 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3235 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003236 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3237 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003238 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3239 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003240 {
3241 MagickBooleanType
3242 status;
3243
3244 /*
3245 Pixel request is inside cache extents.
3246 */
3247 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
3248 return(pixels);
3249 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3250 if (status == MagickFalse)
3251 return((const PixelPacket *) NULL);
3252 if ((cache_info->storage_class == PseudoClass) ||
3253 (cache_info->colorspace == CMYKColorspace))
3254 {
3255 status=ReadPixelCacheIndexes(cache_info,nexus_info,exception);
3256 if (status == MagickFalse)
3257 return((const PixelPacket *) NULL);
3258 }
3259 return(pixels);
3260 }
3261 /*
3262 Pixel request is outside cache extents.
3263 */
3264 q=pixels;
3265 indexes=GetPixelCacheNexusIndexes(cache_info,nexus_info);
3266 virtual_nexus=AcquirePixelCacheNexus(1);
3267 if (virtual_nexus == (NexusInfo **) NULL)
3268 {
3269 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3270 "UnableToGetCacheNexus","`%s'",image->filename);
3271 return((const PixelPacket *) NULL);
3272 }
3273 switch (virtual_pixel_method)
3274 {
3275 case BlackVirtualPixelMethod:
3276 {
cristy4789f0d2010-01-10 00:01:06 +00003277 SetRedPixelComponent(&virtual_pixel,0);
3278 SetGreenPixelComponent(&virtual_pixel,0);
3279 SetBluePixelComponent(&virtual_pixel,0);
3280 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003281 break;
3282 }
3283 case GrayVirtualPixelMethod:
3284 {
cristy4789f0d2010-01-10 00:01:06 +00003285 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3286 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3287 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3288 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003289 break;
3290 }
3291 case TransparentVirtualPixelMethod:
3292 {
cristy4789f0d2010-01-10 00:01:06 +00003293 SetRedPixelComponent(&virtual_pixel,0);
3294 SetGreenPixelComponent(&virtual_pixel,0);
3295 SetBluePixelComponent(&virtual_pixel,0);
3296 SetOpacityPixelComponent(&virtual_pixel,TransparentOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003297 break;
3298 }
3299 case MaskVirtualPixelMethod:
3300 case WhiteVirtualPixelMethod:
3301 {
cristy4789f0d2010-01-10 00:01:06 +00003302 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3303 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3304 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3305 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003306 break;
3307 }
3308 default:
3309 {
3310 virtual_pixel=image->background_color;
3311 break;
3312 }
3313 }
cristyc3ec0d42010-04-07 01:18:08 +00003314 virtual_index=0;
cristybb503372010-05-27 20:51:26 +00003315 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003316 {
cristybb503372010-05-27 20:51:26 +00003317 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003318 {
3319 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003320 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003321 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3322 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003323 {
3324 MagickModulo
3325 x_modulo,
3326 y_modulo;
3327
3328 /*
3329 Transfer a single pixel.
3330 */
3331 length=(MagickSizeType) 1;
3332 switch (virtual_pixel_method)
3333 {
3334 case BackgroundVirtualPixelMethod:
3335 case ConstantVirtualPixelMethod:
3336 case BlackVirtualPixelMethod:
3337 case GrayVirtualPixelMethod:
3338 case TransparentVirtualPixelMethod:
3339 case MaskVirtualPixelMethod:
3340 case WhiteVirtualPixelMethod:
3341 {
3342 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003343 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003344 break;
3345 }
3346 case EdgeVirtualPixelMethod:
3347 default:
3348 {
3349 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003350 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003351 1UL,1UL,*virtual_nexus,exception);
cristyc3ec0d42010-04-07 01:18:08 +00003352 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003353 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003354 break;
3355 }
3356 case RandomVirtualPixelMethod:
3357 {
3358 if (cache_info->random_info == (RandomInfo *) NULL)
3359 cache_info->random_info=AcquireRandomInfo();
3360 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003361 RandomX(cache_info->random_info,cache_info->columns),
3362 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003363 *virtual_nexus,exception);
cristyc3ec0d42010-04-07 01:18:08 +00003364 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003365 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003366 break;
3367 }
3368 case DitherVirtualPixelMethod:
3369 {
3370 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003371 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003372 1UL,1UL,*virtual_nexus,exception);
cristyc3ec0d42010-04-07 01:18:08 +00003373 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003374 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003375 break;
3376 }
3377 case TileVirtualPixelMethod:
3378 {
3379 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3380 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3381 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003382 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003383 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003384 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003385 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003386 break;
3387 }
3388 case MirrorVirtualPixelMethod:
3389 {
3390 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3391 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003392 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003393 x_modulo.remainder-1L;
3394 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3395 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003396 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003397 y_modulo.remainder-1L;
3398 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003399 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003400 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003401 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003402 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003403 break;
3404 }
3405 case CheckerTileVirtualPixelMethod:
3406 {
3407 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3408 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3409 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3410 {
3411 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003412 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003413 break;
3414 }
3415 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003416 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003417 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003418 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003419 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003420 break;
3421 }
3422 case HorizontalTileVirtualPixelMethod:
3423 {
cristybb503372010-05-27 20:51:26 +00003424 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003425 {
3426 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003427 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003428 break;
3429 }
3430 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3431 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3432 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003433 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003434 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003435 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003436 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003437 break;
3438 }
3439 case VerticalTileVirtualPixelMethod:
3440 {
cristybb503372010-05-27 20:51:26 +00003441 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
cristy3ed852e2009-09-05 21:47:34 +00003442 {
3443 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003444 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003445 break;
3446 }
3447 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3448 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3449 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003450 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003451 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003452 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003453 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003454 break;
3455 }
3456 case HorizontalTileEdgeVirtualPixelMethod:
3457 {
3458 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3459 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003460 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003461 *virtual_nexus,exception);
cristyc3ec0d42010-04-07 01:18:08 +00003462 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003463 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003464 break;
3465 }
3466 case VerticalTileEdgeVirtualPixelMethod:
3467 {
3468 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3469 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003470 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003471 *virtual_nexus,exception);
cristyc3ec0d42010-04-07 01:18:08 +00003472 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003473 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003474 break;
3475 }
3476 }
3477 if (p == (const PixelPacket *) NULL)
3478 break;
3479 *q++=(*p);
cristyc3ec0d42010-04-07 01:18:08 +00003480 if ((indexes != (IndexPacket *) NULL) &&
3481 (virtual_indexes != (const IndexPacket *) NULL))
3482 *indexes++=(*virtual_indexes);
cristy3ed852e2009-09-05 21:47:34 +00003483 continue;
3484 }
3485 /*
3486 Transfer a run of pixels.
3487 */
3488 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,
cristy0a36c742010-10-03 02:10:53 +00003489 (size_t) length,1UL,*virtual_nexus,exception);
cristy3ed852e2009-09-05 21:47:34 +00003490 if (p == (const PixelPacket *) NULL)
3491 break;
cristy0a36c742010-10-03 02:10:53 +00003492 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,*virtual_nexus);
cristy8f036fe2010-09-18 02:02:00 +00003493 (void) memcpy(q,p,(size_t) length*sizeof(*p));
cristy3ed852e2009-09-05 21:47:34 +00003494 q+=length;
cristyc3ec0d42010-04-07 01:18:08 +00003495 if ((indexes != (IndexPacket *) NULL) &&
3496 (virtual_indexes != (const IndexPacket *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003497 {
cristy8f036fe2010-09-18 02:02:00 +00003498 (void) memcpy(indexes,virtual_indexes,(size_t) length*
cristyc3ec0d42010-04-07 01:18:08 +00003499 sizeof(*virtual_indexes));
3500 indexes+=length;
cristy3ed852e2009-09-05 21:47:34 +00003501 }
3502 }
3503 }
3504 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3505 return(pixels);
3506}
3507
3508/*
3509%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3510% %
3511% %
3512% %
3513+ G e t V i r t u a l P i x e l C a c h e %
3514% %
3515% %
3516% %
3517%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3518%
3519% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3520% cache as defined by the geometry parameters. A pointer to the pixels
3521% is returned if the pixels are transferred, otherwise a NULL is returned.
3522%
3523% The format of the GetVirtualPixelCache() method is:
3524%
3525% const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003526% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3527% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003528% ExceptionInfo *exception)
3529%
3530% A description of each parameter follows:
3531%
3532% o image: the image.
3533%
3534% o virtual_pixel_method: the virtual pixel method.
3535%
3536% o x,y,columns,rows: These values define the perimeter of a region of
3537% pixels.
3538%
3539% o exception: return any errors or warnings in this structure.
3540%
3541*/
3542static const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003543 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3544 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003545{
3546 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003547 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003548
cristy5c9e6f22010-09-17 17:31:01 +00003549 const int
3550 id = GetOpenMPThreadId();
3551
cristye7cc7cf2010-09-21 13:26:47 +00003552 assert(image != (const Image *) NULL);
3553 assert(image->signature == MagickSignature);
3554 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003555 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003556 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003557 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003558 return(GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3559 cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00003560}
3561
3562/*
3563%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3564% %
3565% %
3566% %
3567% G e t V i r t u a l P i x e l Q u e u e %
3568% %
3569% %
3570% %
3571%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3572%
3573% GetVirtualPixelQueue() returns the virtual pixels associated with the
3574% last call to QueueAuthenticPixels() or GetVirtualPixels().
3575%
3576% The format of the GetVirtualPixelQueue() method is:
3577%
3578% const PixelPacket *GetVirtualPixelQueue(const Image image)
3579%
3580% A description of each parameter follows:
3581%
3582% o image: the image.
3583%
3584*/
3585MagickExport const PixelPacket *GetVirtualPixelQueue(const Image *image)
3586{
3587 CacheInfo
3588 *cache_info;
3589
cristy2036f5c2010-09-19 21:18:17 +00003590 const int
3591 id = GetOpenMPThreadId();
3592
cristy3ed852e2009-09-05 21:47:34 +00003593 assert(image != (const Image *) NULL);
3594 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003595 assert(image->cache != (Cache) NULL);
3596 cache_info=(CacheInfo *) image->cache;
3597 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003598 if (cache_info->methods.get_virtual_pixels_handler !=
3599 (GetVirtualPixelsHandler) NULL)
3600 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003601 assert(id < (int) cache_info->number_threads);
3602 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003603}
3604
3605/*
3606%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3607% %
3608% %
3609% %
3610% G e t V i r t u a l P i x e l s %
3611% %
3612% %
3613% %
3614%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3615%
3616% GetVirtualPixels() returns an immutable pixel region. If the
3617% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003618% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003619% copy of the pixels or it may point to the original pixels in memory.
3620% Performance is maximized if the selected region is part of one row, or one
3621% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003622% (without a copy) if the image is in memory, or in a memory-mapped file. The
3623% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003624%
3625% Pixels accessed via the returned pointer represent a simple array of type
3626% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
3627% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to access
3628% the black color component or to obtain the colormap indexes (of type
3629% IndexPacket) corresponding to the region.
3630%
3631% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3632%
3633% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3634% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3635% GetCacheViewAuthenticPixels() instead.
3636%
3637% The format of the GetVirtualPixels() method is:
3638%
cristybb503372010-05-27 20:51:26 +00003639% const PixelPacket *GetVirtualPixels(const Image *image,const ssize_t x,
3640% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003641% ExceptionInfo *exception)
3642%
3643% A description of each parameter follows:
3644%
3645% o image: the image.
3646%
3647% o x,y,columns,rows: These values define the perimeter of a region of
3648% pixels.
3649%
3650% o exception: return any errors or warnings in this structure.
3651%
3652*/
3653MagickExport const PixelPacket *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003654 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3655 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003656{
3657 CacheInfo
3658 *cache_info;
3659
cristy2036f5c2010-09-19 21:18:17 +00003660 const int
3661 id = GetOpenMPThreadId();
3662
cristy3ed852e2009-09-05 21:47:34 +00003663 assert(image != (const Image *) NULL);
3664 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003665 assert(image->cache != (Cache) NULL);
3666 cache_info=(CacheInfo *) image->cache;
3667 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003668 if (cache_info->methods.get_virtual_pixel_handler !=
3669 (GetVirtualPixelHandler) NULL)
3670 return(cache_info->methods.get_virtual_pixel_handler(image,
3671 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003672 assert(id < (int) cache_info->number_threads);
3673 return(GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3674 columns,rows,cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00003675}
3676
3677/*
3678%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3679% %
3680% %
3681% %
3682+ 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 %
3683% %
3684% %
3685% %
3686%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3687%
3688% GetVirtualPixelsCache() returns the pixels associated with the last call
3689% to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3690%
3691% The format of the GetVirtualPixelsCache() method is:
3692%
3693% PixelPacket *GetVirtualPixelsCache(const Image *image)
3694%
3695% A description of each parameter follows:
3696%
3697% o image: the image.
3698%
3699*/
3700static const PixelPacket *GetVirtualPixelsCache(const Image *image)
3701{
3702 CacheInfo
3703 *cache_info;
3704
cristy5c9e6f22010-09-17 17:31:01 +00003705 const int
3706 id = GetOpenMPThreadId();
3707
cristye7cc7cf2010-09-21 13:26:47 +00003708 assert(image != (const Image *) NULL);
3709 assert(image->signature == MagickSignature);
3710 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003711 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003712 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003713 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003714 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003715}
3716
3717/*
3718%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3719% %
3720% %
3721% %
3722+ G e t V i r t u a l P i x e l s N e x u s %
3723% %
3724% %
3725% %
3726%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3727%
3728% GetVirtualPixelsNexus() returns the pixels associated with the specified
3729% cache nexus.
3730%
3731% The format of the GetVirtualPixelsNexus() method is:
3732%
3733% const IndexPacket *GetVirtualPixelsNexus(const Cache cache,
3734% NexusInfo *nexus_info)
3735%
3736% A description of each parameter follows:
3737%
3738% o cache: the pixel cache.
3739%
3740% o nexus_info: the cache nexus to return the colormap pixels.
3741%
3742*/
3743MagickExport const PixelPacket *GetVirtualPixelsNexus(const Cache cache,
3744 NexusInfo *nexus_info)
3745{
3746 CacheInfo
3747 *cache_info;
3748
cristye7cc7cf2010-09-21 13:26:47 +00003749 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003750 cache_info=(CacheInfo *) cache;
3751 assert(cache_info->signature == MagickSignature);
3752 if (cache_info->storage_class == UndefinedClass)
3753 return((PixelPacket *) NULL);
3754 return((const PixelPacket *) nexus_info->pixels);
3755}
3756
3757/*
3758%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3759% %
3760% %
3761% %
3762+ M a s k P i x e l C a c h e N e x u s %
3763% %
3764% %
3765% %
3766%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3767%
3768% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3769% The method returns MagickTrue if the pixel region is masked, otherwise
3770% MagickFalse.
3771%
3772% The format of the MaskPixelCacheNexus() method is:
3773%
3774% MagickBooleanType MaskPixelCacheNexus(Image *image,
3775% NexusInfo *nexus_info,ExceptionInfo *exception)
3776%
3777% A description of each parameter follows:
3778%
3779% o image: the image.
3780%
3781% o nexus_info: the cache nexus to clip.
3782%
3783% o exception: return any errors or warnings in this structure.
3784%
3785*/
3786
3787static inline void MagickPixelCompositeMask(const MagickPixelPacket *p,
3788 const MagickRealType alpha,const MagickPixelPacket *q,
3789 const MagickRealType beta,MagickPixelPacket *composite)
3790{
3791 MagickRealType
3792 gamma;
3793
3794 if (alpha == TransparentOpacity)
3795 {
3796 *composite=(*q);
3797 return;
3798 }
3799 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3800 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3801 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3802 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3803 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3804 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3805 composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
3806}
3807
3808static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3809 ExceptionInfo *exception)
3810{
3811 CacheInfo
3812 *cache_info;
3813
3814 MagickPixelPacket
3815 alpha,
3816 beta;
3817
3818 MagickSizeType
3819 number_pixels;
3820
3821 NexusInfo
3822 **clip_nexus,
3823 **image_nexus;
3824
3825 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003826 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003827
3828 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003829 *restrict nexus_indexes,
3830 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003831
cristy3ed852e2009-09-05 21:47:34 +00003832 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003833 *restrict p,
3834 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003835
cristye076a6e2010-08-15 19:59:43 +00003836 register ssize_t
3837 i;
3838
cristy3ed852e2009-09-05 21:47:34 +00003839 /*
3840 Apply clip mask.
3841 */
3842 if (image->debug != MagickFalse)
3843 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3844 if (image->mask == (Image *) NULL)
3845 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +00003846 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00003847 if (cache_info == (Cache) NULL)
3848 return(MagickFalse);
3849 image_nexus=AcquirePixelCacheNexus(1);
3850 clip_nexus=AcquirePixelCacheNexus(1);
3851 if ((image_nexus == (NexusInfo **) NULL) ||
3852 (clip_nexus == (NexusInfo **) NULL))
3853 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy09449f72010-01-23 03:08:36 +00003854 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,
3855 nexus_info->region.y,nexus_info->region.width,nexus_info->region.height,
3856 image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003857 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
3858 q=nexus_info->pixels;
3859 nexus_indexes=nexus_info->indexes;
3860 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3861 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3862 nexus_info->region.height,clip_nexus[0],&image->exception);
3863 GetMagickPixelPacket(image,&alpha);
3864 GetMagickPixelPacket(image,&beta);
3865 number_pixels=(MagickSizeType) nexus_info->region.width*
3866 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +00003867 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +00003868 {
3869 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
3870 break;
3871 SetMagickPixelPacket(image,p,indexes+i,&alpha);
3872 SetMagickPixelPacket(image,q,nexus_indexes+i,&beta);
3873 MagickPixelCompositeMask(&beta,(MagickRealType) PixelIntensityToQuantum(r),
3874 &alpha,alpha.opacity,&beta);
cristyce70c172010-01-07 17:15:30 +00003875 q->red=ClampToQuantum(beta.red);
3876 q->green=ClampToQuantum(beta.green);
3877 q->blue=ClampToQuantum(beta.blue);
3878 q->opacity=ClampToQuantum(beta.opacity);
cristy3ed852e2009-09-05 21:47:34 +00003879 if (cache_info->active_index_channel != MagickFalse)
3880 nexus_indexes[i]=indexes[i];
3881 p++;
3882 q++;
3883 r++;
3884 }
3885 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3886 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +00003887 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003888 return(MagickFalse);
3889 return(MagickTrue);
3890}
3891
3892/*
3893%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3894% %
3895% %
3896% %
3897+ O p e n P i x e l C a c h e %
3898% %
3899% %
3900% %
3901%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3902%
3903% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3904% dimensions, allocating space for the image pixels and optionally the
3905% colormap indexes, and memory mapping the cache if it is disk based. The
3906% cache nexus array is initialized as well.
3907%
3908% The format of the OpenPixelCache() method is:
3909%
3910% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3911% ExceptionInfo *exception)
3912%
3913% A description of each parameter follows:
3914%
3915% o image: the image.
3916%
3917% o mode: ReadMode, WriteMode, or IOMode.
3918%
3919% o exception: return any errors or warnings in this structure.
3920%
3921*/
3922
cristyd43a46b2010-01-21 02:13:41 +00003923static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003924{
3925 cache_info->mapped=MagickFalse;
3926 cache_info->pixels=(PixelPacket *) AcquireMagickMemory((size_t)
3927 cache_info->length);
3928 if (cache_info->pixels == (PixelPacket *) NULL)
3929 {
3930 cache_info->mapped=MagickTrue;
3931 cache_info->pixels=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
3932 cache_info->length);
3933 }
3934}
3935
3936static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3937{
3938 CacheInfo
3939 *cache_info;
3940
3941 MagickOffsetType
3942 count,
3943 extent,
3944 offset;
3945
3946 cache_info=(CacheInfo *) image->cache;
3947 if (image->debug != MagickFalse)
3948 {
3949 char
3950 format[MaxTextExtent],
3951 message[MaxTextExtent];
3952
cristyb9080c92009-12-01 20:13:26 +00003953 (void) FormatMagickSize(length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00003954 (void) FormatMagickString(message,MaxTextExtent,
cristy2ce15c92010-03-12 14:03:41 +00003955 "extend %s (%s[%d], disk, %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003956 cache_info->cache_filename,cache_info->file,format);
3957 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3958 }
3959 if (length != (MagickSizeType) ((MagickOffsetType) length))
3960 return(MagickFalse);
3961 extent=(MagickOffsetType) MagickSeek(cache_info->file,0,SEEK_END);
3962 if (extent < 0)
3963 return(MagickFalse);
3964 if ((MagickSizeType) extent >= length)
3965 return(MagickTrue);
3966 offset=(MagickOffsetType) length-1;
3967 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3968 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3969}
3970
3971static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3972 ExceptionInfo *exception)
3973{
3974 char
3975 format[MaxTextExtent],
3976 message[MaxTextExtent];
3977
3978 CacheInfo
3979 *cache_info,
3980 source_info;
3981
3982 MagickSizeType
3983 length,
3984 number_pixels;
3985
3986 MagickStatusType
3987 status;
3988
3989 size_t
cristye076a6e2010-08-15 19:59:43 +00003990 columns,
cristy3ed852e2009-09-05 21:47:34 +00003991 packet_size;
3992
cristye7cc7cf2010-09-21 13:26:47 +00003993 assert(image != (const Image *) NULL);
3994 assert(image->signature == MagickSignature);
3995 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003996 if (image->debug != MagickFalse)
3997 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3998 if ((image->columns == 0) || (image->rows == 0))
3999 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
4000 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004001 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004002 source_info=(*cache_info);
4003 source_info.file=(-1);
cristye8c25f92010-06-03 00:53:06 +00004004 (void) FormatMagickString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
4005 image->filename,(double) GetImageIndexInList(image));
cristy87528ea2009-09-10 14:53:56 +00004006 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +00004007 cache_info->rows=image->rows;
4008 cache_info->columns=image->columns;
4009 cache_info->active_index_channel=((image->storage_class == PseudoClass) ||
4010 (image->colorspace == CMYKColorspace)) ? MagickTrue : MagickFalse;
cristy73724512010-04-12 14:43:14 +00004011 if (image->ping != MagickFalse)
4012 {
4013 cache_info->storage_class=image->storage_class;
4014 cache_info->colorspace=image->colorspace;
4015 cache_info->type=PingCache;
4016 cache_info->pixels=(PixelPacket *) NULL;
4017 cache_info->indexes=(IndexPacket *) NULL;
4018 cache_info->length=0;
4019 return(MagickTrue);
4020 }
cristy3ed852e2009-09-05 21:47:34 +00004021 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4022 packet_size=sizeof(PixelPacket);
4023 if (cache_info->active_index_channel != MagickFalse)
4024 packet_size+=sizeof(IndexPacket);
4025 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00004026 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00004027 if (cache_info->columns != columns)
4028 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4029 image->filename);
4030 cache_info->length=length;
4031 status=AcquireMagickResource(AreaResource,cache_info->length);
4032 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4033 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4034 {
4035 status=AcquireMagickResource(MemoryResource,cache_info->length);
4036 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4037 (cache_info->type == MemoryCache))
4038 {
cristyd43a46b2010-01-21 02:13:41 +00004039 AllocatePixelCachePixels(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004040 if (cache_info->pixels == (PixelPacket *) NULL)
4041 cache_info->pixels=source_info.pixels;
4042 else
4043 {
4044 /*
4045 Create memory pixel cache.
4046 */
4047 if (image->debug != MagickFalse)
4048 {
cristy97e7a572009-12-05 15:07:53 +00004049 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004050 format);
cristy3ed852e2009-09-05 21:47:34 +00004051 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004052 "open %s (%s memory, %.20gx%.20g %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00004053 cache_info->mapped != MagickFalse ? "anonymous" : "heap",
cristye8c25f92010-06-03 00:53:06 +00004054 (double) cache_info->columns,(double) cache_info->rows,
4055 format);
cristy3ed852e2009-09-05 21:47:34 +00004056 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4057 message);
4058 }
4059 cache_info->storage_class=image->storage_class;
4060 cache_info->colorspace=image->colorspace;
4061 cache_info->type=MemoryCache;
4062 cache_info->indexes=(IndexPacket *) NULL;
4063 if (cache_info->active_index_channel != MagickFalse)
4064 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4065 number_pixels);
4066 if (source_info.storage_class != UndefinedClass)
4067 {
4068 status|=ClonePixelCachePixels(cache_info,&source_info,
4069 exception);
4070 RelinquishPixelCachePixels(&source_info);
4071 }
4072 return(MagickTrue);
4073 }
4074 }
4075 RelinquishMagickResource(MemoryResource,cache_info->length);
4076 }
4077 /*
4078 Create pixel cache on disk.
4079 */
4080 status=AcquireMagickResource(DiskResource,cache_info->length);
4081 if (status == MagickFalse)
4082 {
4083 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4084 "CacheResourcesExhausted","`%s'",image->filename);
4085 return(MagickFalse);
4086 }
4087 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4088 {
4089 RelinquishMagickResource(DiskResource,cache_info->length);
4090 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4091 image->filename);
4092 return(MagickFalse);
4093 }
4094 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4095 cache_info->length);
4096 if (status == MagickFalse)
4097 {
4098 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4099 image->filename);
4100 return(MagickFalse);
4101 }
4102 cache_info->storage_class=image->storage_class;
4103 cache_info->colorspace=image->colorspace;
4104 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4105 status=AcquireMagickResource(AreaResource,cache_info->length);
4106 if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4107 cache_info->type=DiskCache;
4108 else
4109 {
4110 status=AcquireMagickResource(MapResource,cache_info->length);
4111 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4112 (cache_info->type != MemoryCache))
4113 cache_info->type=DiskCache;
4114 else
4115 {
4116 cache_info->pixels=(PixelPacket *) MapBlob(cache_info->file,mode,
4117 cache_info->offset,(size_t) cache_info->length);
4118 if (cache_info->pixels == (PixelPacket *) NULL)
4119 {
4120 cache_info->pixels=source_info.pixels;
4121 cache_info->type=DiskCache;
4122 }
4123 else
4124 {
4125 /*
4126 Create file-backed memory-mapped pixel cache.
4127 */
4128 (void) ClosePixelCacheOnDisk(cache_info);
4129 cache_info->type=MapCache;
4130 cache_info->mapped=MagickTrue;
4131 cache_info->indexes=(IndexPacket *) NULL;
4132 if (cache_info->active_index_channel != MagickFalse)
4133 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4134 number_pixels);
4135 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4136 {
4137 status=ClonePixelCachePixels(cache_info,&source_info,
4138 exception);
4139 RelinquishPixelCachePixels(&source_info);
4140 }
4141 if (image->debug != MagickFalse)
4142 {
cristy97e7a572009-12-05 15:07:53 +00004143 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004144 format);
cristy3ed852e2009-09-05 21:47:34 +00004145 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004146 "open %s (%s[%d], memory-mapped, %.20gx%.20g %sB)",
cristy3ed852e2009-09-05 21:47:34 +00004147 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004148 cache_info->file,(double) cache_info->columns,(double)
4149 cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004150 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4151 message);
4152 }
4153 return(MagickTrue);
4154 }
4155 }
4156 RelinquishMagickResource(MapResource,cache_info->length);
4157 }
4158 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4159 {
4160 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4161 RelinquishPixelCachePixels(&source_info);
4162 }
4163 if (image->debug != MagickFalse)
4164 {
cristyb9080c92009-12-01 20:13:26 +00004165 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00004166 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004167 "open %s (%s[%d], disk, %.20gx%.20g %sB)",cache_info->filename,
4168 cache_info->cache_filename,cache_info->file,(double)
4169 cache_info->columns,(double) cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004170 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4171 }
4172 return(MagickTrue);
4173}
4174
4175/*
4176%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4177% %
4178% %
4179% %
4180+ P e r s i s t P i x e l C a c h e %
4181% %
4182% %
4183% %
4184%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4185%
4186% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4187% persistent pixel cache is one that resides on disk and is not destroyed
4188% when the program exits.
4189%
4190% The format of the PersistPixelCache() method is:
4191%
4192% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4193% const MagickBooleanType attach,MagickOffsetType *offset,
4194% ExceptionInfo *exception)
4195%
4196% A description of each parameter follows:
4197%
4198% o image: the image.
4199%
4200% o filename: the persistent pixel cache filename.
4201%
cristy01b7eb02009-09-10 23:10:14 +00004202% o attach: A value other than zero initializes the persistent pixel
4203% cache.
4204%
cristy3ed852e2009-09-05 21:47:34 +00004205% o initialize: A value other than zero initializes the persistent pixel
4206% cache.
4207%
4208% o offset: the offset in the persistent cache to store pixels.
4209%
4210% o exception: return any errors or warnings in this structure.
4211%
4212*/
4213MagickExport MagickBooleanType PersistPixelCache(Image *image,
4214 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4215 ExceptionInfo *exception)
4216{
4217 CacheInfo
4218 *cache_info,
4219 *clone_info;
4220
4221 Image
4222 clone_image;
4223
cristy3ed852e2009-09-05 21:47:34 +00004224 MagickBooleanType
4225 status;
4226
cristye076a6e2010-08-15 19:59:43 +00004227 ssize_t
4228 page_size;
4229
cristy3ed852e2009-09-05 21:47:34 +00004230 assert(image != (Image *) NULL);
4231 assert(image->signature == MagickSignature);
4232 if (image->debug != MagickFalse)
4233 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4234 assert(image->cache != (void *) NULL);
4235 assert(filename != (const char *) NULL);
4236 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004237 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004238 cache_info=(CacheInfo *) image->cache;
4239 assert(cache_info->signature == MagickSignature);
4240 if (attach != MagickFalse)
4241 {
4242 /*
cristy01b7eb02009-09-10 23:10:14 +00004243 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004244 */
4245 if (image->debug != MagickFalse)
4246 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004247 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004248 (void) CopyMagickString(cache_info->cache_filename,filename,
4249 MaxTextExtent);
4250 cache_info->type=DiskCache;
4251 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004252 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004253 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004254 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004255 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004256 }
cristy01b7eb02009-09-10 23:10:14 +00004257 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4258 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004259 {
cristyf84a1932010-01-03 18:00:18 +00004260 LockSemaphoreInfo(cache_info->semaphore);
cristy09449f72010-01-23 03:08:36 +00004261 if ((cache_info->mode != ReadMode) &&
4262 (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004263 (cache_info->reference_count == 1))
4264 {
4265 int
4266 status;
4267
4268 /*
cristy01b7eb02009-09-10 23:10:14 +00004269 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004270 */
4271 status=rename(cache_info->cache_filename,filename);
4272 if (status == 0)
4273 {
4274 (void) CopyMagickString(cache_info->cache_filename,filename,
4275 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004276 *offset+=cache_info->length+page_size-(cache_info->length %
4277 page_size);
cristyf84a1932010-01-03 18:00:18 +00004278 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004279 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004280 if (image->debug != MagickFalse)
4281 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4282 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004283 return(MagickTrue);
4284 }
4285 }
cristyf84a1932010-01-03 18:00:18 +00004286 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004287 }
4288 /*
cristy01b7eb02009-09-10 23:10:14 +00004289 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004290 */
4291 clone_image=(*image);
4292 clone_info=(CacheInfo *) clone_image.cache;
4293 image->cache=ClonePixelCache(cache_info);
4294 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4295 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4296 cache_info->type=DiskCache;
4297 cache_info->offset=(*offset);
4298 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004299 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004300 if (status != MagickFalse)
cristycfae90a2010-10-04 14:43:33 +00004301 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
cristy688f07b2009-09-27 15:19:13 +00004302 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004303 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4304 return(status);
4305}
4306
4307/*
4308%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4309% %
4310% %
4311% %
4312+ Q u e u e A u t h e n t i c N e x u s %
4313% %
4314% %
4315% %
4316%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4317%
4318% QueueAuthenticNexus() allocates an region to store image pixels as defined
4319% by the region rectangle and returns a pointer to the region. This region is
4320% subsequently transferred from the pixel cache with
4321% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4322% pixels are transferred, otherwise a NULL is returned.
4323%
4324% The format of the QueueAuthenticNexus() method is:
4325%
cristy5f959472010-05-27 22:19:46 +00004326% PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
4327% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004328% NexusInfo *nexus_info,ExceptionInfo *exception)
4329%
4330% A description of each parameter follows:
4331%
4332% o image: the image.
4333%
4334% o x,y,columns,rows: These values define the perimeter of a region of
4335% pixels.
4336%
4337% o nexus_info: the cache nexus to set.
4338%
4339% o exception: return any errors or warnings in this structure.
4340%
4341*/
cristybb503372010-05-27 20:51:26 +00004342MagickExport PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy30097232010-07-01 02:16:30 +00004343 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
4344 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004345{
4346 CacheInfo
4347 *cache_info;
4348
4349 MagickOffsetType
4350 offset;
4351
4352 MagickSizeType
4353 number_pixels;
4354
4355 RectangleInfo
4356 region;
4357
4358 /*
4359 Validate pixel cache geometry.
4360 */
cristye7cc7cf2010-09-21 13:26:47 +00004361 assert(image != (const Image *) NULL);
4362 assert(image->signature == MagickSignature);
4363 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004364 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
cristye7cc7cf2010-09-21 13:26:47 +00004365 assert(cache_info->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00004366 if (cache_info == (Cache) NULL)
4367 return((PixelPacket *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004368 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4369 {
4370 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4371 "NoPixelsDefinedInCache","`%s'",image->filename);
4372 return((PixelPacket *) NULL);
4373 }
cristybb503372010-05-27 20:51:26 +00004374 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4375 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004376 {
4377 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4378 "PixelsAreNotAuthentic","`%s'",image->filename);
4379 return((PixelPacket *) NULL);
4380 }
4381 offset=(MagickOffsetType) y*cache_info->columns+x;
4382 if (offset < 0)
4383 return((PixelPacket *) NULL);
4384 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4385 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4386 if ((MagickSizeType) offset >= number_pixels)
4387 return((PixelPacket *) NULL);
4388 /*
4389 Return pixel cache.
4390 */
4391 region.x=x;
4392 region.y=y;
4393 region.width=columns;
4394 region.height=rows;
4395 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4396}
4397
4398/*
4399%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4400% %
4401% %
4402% %
4403+ 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 %
4404% %
4405% %
4406% %
4407%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4408%
4409% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4410% defined by the region rectangle and returns a pointer to the region. This
4411% region is subsequently transferred from the pixel cache with
4412% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4413% pixels are transferred, otherwise a NULL is returned.
4414%
4415% The format of the QueueAuthenticPixelsCache() method is:
4416%
cristybb503372010-05-27 20:51:26 +00004417% PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4418% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004419% ExceptionInfo *exception)
4420%
4421% A description of each parameter follows:
4422%
4423% o image: the image.
4424%
4425% o x,y,columns,rows: These values define the perimeter of a region of
4426% pixels.
4427%
4428% o exception: return any errors or warnings in this structure.
4429%
4430*/
cristybb503372010-05-27 20:51:26 +00004431static PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4432 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004433 ExceptionInfo *exception)
4434{
4435 CacheInfo
4436 *cache_info;
4437
cristy5c9e6f22010-09-17 17:31:01 +00004438 const int
4439 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004440
cristye7cc7cf2010-09-21 13:26:47 +00004441 assert(image != (const Image *) NULL);
4442 assert(image->signature == MagickSignature);
4443 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004444 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004445 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004446 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00004447 return(QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4448 exception));
cristy3ed852e2009-09-05 21:47:34 +00004449}
4450
4451/*
4452%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4453% %
4454% %
4455% %
4456% Q u e u e A u t h e n t i c P i x e l s %
4457% %
4458% %
4459% %
4460%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4461%
4462% QueueAuthenticPixels() queues a mutable pixel region. If the region is
4463% successfully intialized a pointer to a PixelPacket array representing the
4464% region is returned, otherwise NULL is returned. The returned pointer may
4465% point to a temporary working buffer for the pixels or it may point to the
4466% final location of the pixels in memory.
4467%
4468% Write-only access means that any existing pixel values corresponding to
4469% the region are ignored. This is useful if the initial image is being
4470% created from scratch, or if the existing pixel values are to be
4471% completely replaced without need to refer to their pre-existing values.
4472% The application is free to read and write the pixel buffer returned by
4473% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4474% initialize the pixel array values. Initializing pixel array values is the
4475% application's responsibility.
4476%
4477% Performance is maximized if the selected region is part of one row, or
4478% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004479% pixels in-place (without a copy) if the image is in memory, or in a
4480% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004481% by the user.
4482%
4483% Pixels accessed via the returned pointer represent a simple array of type
4484% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
4485% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
4486% the black color component or the colormap indexes (of type IndexPacket)
4487% corresponding to the region. Once the PixelPacket (and/or IndexPacket)
4488% array has been updated, the changes must be saved back to the underlying
4489% image using SyncAuthenticPixels() or they may be lost.
4490%
4491% The format of the QueueAuthenticPixels() method is:
4492%
cristy5f959472010-05-27 22:19:46 +00004493% PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4494% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004495% ExceptionInfo *exception)
4496%
4497% A description of each parameter follows:
4498%
4499% o image: the image.
4500%
4501% o x,y,columns,rows: These values define the perimeter of a region of
4502% pixels.
4503%
4504% o exception: return any errors or warnings in this structure.
4505%
4506*/
cristybb503372010-05-27 20:51:26 +00004507MagickExport PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4508 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004509 ExceptionInfo *exception)
4510{
4511 CacheInfo
4512 *cache_info;
4513
cristy2036f5c2010-09-19 21:18:17 +00004514 const int
4515 id = GetOpenMPThreadId();
4516
cristy3ed852e2009-09-05 21:47:34 +00004517 assert(image != (Image *) NULL);
4518 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004519 assert(image->cache != (Cache) NULL);
4520 cache_info=(CacheInfo *) image->cache;
4521 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004522 if (cache_info->methods.queue_authentic_pixels_handler !=
4523 (QueueAuthenticPixelsHandler) NULL)
4524 return(cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4525 rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00004526 assert(id < (int) cache_info->number_threads);
4527 return(QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4528 exception));
cristy3ed852e2009-09-05 21:47:34 +00004529}
4530
4531/*
4532%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4533% %
4534% %
4535% %
4536+ R e a d P i x e l C a c h e I n d e x e s %
4537% %
4538% %
4539% %
4540%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4541%
4542% ReadPixelCacheIndexes() reads colormap indexes from the specified region of
4543% the pixel cache.
4544%
4545% The format of the ReadPixelCacheIndexes() method is:
4546%
4547% MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4548% NexusInfo *nexus_info,ExceptionInfo *exception)
4549%
4550% A description of each parameter follows:
4551%
4552% o cache_info: the pixel cache.
4553%
4554% o nexus_info: the cache nexus to read the colormap indexes.
4555%
4556% o exception: return any errors or warnings in this structure.
4557%
4558*/
4559static MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4560 NexusInfo *nexus_info,ExceptionInfo *exception)
4561{
4562 MagickOffsetType
4563 count,
4564 offset;
4565
4566 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004567 extent,
4568 length;
cristy3ed852e2009-09-05 21:47:34 +00004569
4570 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004571 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004572
cristybb503372010-05-27 20:51:26 +00004573 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004574 y;
4575
cristybb503372010-05-27 20:51:26 +00004576 size_t
cristy3ed852e2009-09-05 21:47:34 +00004577 rows;
4578
cristy3ed852e2009-09-05 21:47:34 +00004579 if (cache_info->active_index_channel == MagickFalse)
4580 return(MagickFalse);
4581 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4582 return(MagickTrue);
4583 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4584 nexus_info->region.x;
4585 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
4586 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004587 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004588 q=nexus_info->indexes;
4589 switch (cache_info->type)
4590 {
4591 case MemoryCache:
4592 case MapCache:
4593 {
4594 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004595 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004596
4597 /*
4598 Read indexes from memory.
4599 */
cristydd341db2010-03-04 19:06:38 +00004600 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004601 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004602 {
cristy48078b12010-09-23 17:11:01 +00004603 length=extent;
cristydd341db2010-03-04 19:06:38 +00004604 rows=1UL;
4605 }
cristy3ed852e2009-09-05 21:47:34 +00004606 p=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00004607 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004608 {
cristy8f036fe2010-09-18 02:02:00 +00004609 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00004610 p+=cache_info->columns;
4611 q+=nexus_info->region.width;
4612 }
4613 break;
4614 }
4615 case DiskCache:
4616 {
4617 /*
4618 Read indexes from disk.
4619 */
4620 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4621 {
4622 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4623 cache_info->cache_filename);
4624 return(MagickFalse);
4625 }
cristydd341db2010-03-04 19:06:38 +00004626 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004627 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004628 {
cristy48078b12010-09-23 17:11:01 +00004629 length=extent;
cristydd341db2010-03-04 19:06:38 +00004630 rows=1UL;
4631 }
cristy48078b12010-09-23 17:11:01 +00004632 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004633 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004634 {
cristy48078b12010-09-23 17:11:01 +00004635 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristy3ed852e2009-09-05 21:47:34 +00004636 sizeof(PixelPacket)+offset*sizeof(*q),length,(unsigned char *) q);
4637 if ((MagickSizeType) count < length)
4638 break;
4639 offset+=cache_info->columns;
4640 q+=nexus_info->region.width;
4641 }
cristybb503372010-05-27 20:51:26 +00004642 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004643 {
4644 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4645 cache_info->cache_filename);
4646 return(MagickFalse);
4647 }
4648 break;
4649 }
4650 default:
4651 break;
4652 }
4653 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004654 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004655 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004656 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004657 nexus_info->region.width,(double) nexus_info->region.height,(double)
4658 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004659 return(MagickTrue);
4660}
4661
4662/*
4663%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4664% %
4665% %
4666% %
4667+ R e a d P i x e l C a c h e P i x e l s %
4668% %
4669% %
4670% %
4671%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4672%
4673% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4674% cache.
4675%
4676% The format of the ReadPixelCachePixels() method is:
4677%
4678% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4679% NexusInfo *nexus_info,ExceptionInfo *exception)
4680%
4681% A description of each parameter follows:
4682%
4683% o cache_info: the pixel cache.
4684%
4685% o nexus_info: the cache nexus to read the pixels.
4686%
4687% o exception: return any errors or warnings in this structure.
4688%
4689*/
4690static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4691 NexusInfo *nexus_info,ExceptionInfo *exception)
4692{
4693 MagickOffsetType
4694 count,
4695 offset;
4696
4697 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004698 extent,
4699 length;
cristy3ed852e2009-09-05 21:47:34 +00004700
cristy3ed852e2009-09-05 21:47:34 +00004701 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004702 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004703
cristye076a6e2010-08-15 19:59:43 +00004704 register ssize_t
4705 y;
4706
cristybb503372010-05-27 20:51:26 +00004707 size_t
cristy3ed852e2009-09-05 21:47:34 +00004708 rows;
4709
cristy3ed852e2009-09-05 21:47:34 +00004710 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4711 return(MagickTrue);
4712 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4713 nexus_info->region.x;
4714 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
4715 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004716 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004717 q=nexus_info->pixels;
4718 switch (cache_info->type)
4719 {
4720 case MemoryCache:
4721 case MapCache:
4722 {
4723 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004724 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004725
4726 /*
4727 Read pixels from memory.
4728 */
cristydd341db2010-03-04 19:06:38 +00004729 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004730 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004731 {
cristy48078b12010-09-23 17:11:01 +00004732 length=extent;
cristydd341db2010-03-04 19:06:38 +00004733 rows=1UL;
4734 }
cristy3ed852e2009-09-05 21:47:34 +00004735 p=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00004736 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004737 {
cristy8f036fe2010-09-18 02:02:00 +00004738 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00004739 p+=cache_info->columns;
4740 q+=nexus_info->region.width;
4741 }
4742 break;
4743 }
4744 case DiskCache:
4745 {
4746 /*
4747 Read pixels from disk.
4748 */
4749 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4750 {
4751 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4752 cache_info->cache_filename);
4753 return(MagickFalse);
4754 }
cristydd341db2010-03-04 19:06:38 +00004755 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004756 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004757 {
cristy48078b12010-09-23 17:11:01 +00004758 length=extent;
cristydd341db2010-03-04 19:06:38 +00004759 rows=1UL;
4760 }
cristybb503372010-05-27 20:51:26 +00004761 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004762 {
4763 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4764 sizeof(*q),length,(unsigned char *) q);
4765 if ((MagickSizeType) count < length)
4766 break;
4767 offset+=cache_info->columns;
4768 q+=nexus_info->region.width;
4769 }
cristybb503372010-05-27 20:51:26 +00004770 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004771 {
4772 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4773 cache_info->cache_filename);
4774 return(MagickFalse);
4775 }
4776 break;
4777 }
4778 default:
4779 break;
4780 }
4781 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004782 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004783 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004784 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004785 nexus_info->region.width,(double) nexus_info->region.height,(double)
4786 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004787 return(MagickTrue);
4788}
4789
4790/*
4791%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4792% %
4793% %
4794% %
4795+ R e f e r e n c e P i x e l C a c h e %
4796% %
4797% %
4798% %
4799%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4800%
4801% ReferencePixelCache() increments the reference count associated with the
4802% pixel cache returning a pointer to the cache.
4803%
4804% The format of the ReferencePixelCache method is:
4805%
4806% Cache ReferencePixelCache(Cache cache_info)
4807%
4808% A description of each parameter follows:
4809%
4810% o cache_info: the pixel cache.
4811%
4812*/
4813MagickExport Cache ReferencePixelCache(Cache cache)
4814{
4815 CacheInfo
4816 *cache_info;
4817
4818 assert(cache != (Cache *) NULL);
4819 cache_info=(CacheInfo *) cache;
4820 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004821 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004822 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004823 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004824 return(cache_info);
4825}
4826
4827/*
4828%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4829% %
4830% %
4831% %
4832+ S e t P i x e l C a c h e M e t h o d s %
4833% %
4834% %
4835% %
4836%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4837%
4838% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4839%
4840% The format of the SetPixelCacheMethods() method is:
4841%
4842% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4843%
4844% A description of each parameter follows:
4845%
4846% o cache: the pixel cache.
4847%
4848% o cache_methods: Specifies a pointer to a CacheMethods structure.
4849%
4850*/
4851MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4852{
4853 CacheInfo
4854 *cache_info;
4855
4856 GetOneAuthenticPixelFromHandler
4857 get_one_authentic_pixel_from_handler;
4858
4859 GetOneVirtualPixelFromHandler
4860 get_one_virtual_pixel_from_handler;
4861
4862 /*
4863 Set cache pixel methods.
4864 */
4865 assert(cache != (Cache) NULL);
4866 assert(cache_methods != (CacheMethods *) NULL);
4867 cache_info=(CacheInfo *) cache;
4868 assert(cache_info->signature == MagickSignature);
4869 if (cache_info->debug != MagickFalse)
4870 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4871 cache_info->filename);
4872 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4873 cache_info->methods.get_virtual_pixel_handler=
4874 cache_methods->get_virtual_pixel_handler;
4875 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4876 cache_info->methods.destroy_pixel_handler=
4877 cache_methods->destroy_pixel_handler;
4878 if (cache_methods->get_virtual_indexes_from_handler !=
4879 (GetVirtualIndexesFromHandler) NULL)
4880 cache_info->methods.get_virtual_indexes_from_handler=
4881 cache_methods->get_virtual_indexes_from_handler;
4882 if (cache_methods->get_authentic_pixels_handler !=
4883 (GetAuthenticPixelsHandler) NULL)
4884 cache_info->methods.get_authentic_pixels_handler=
4885 cache_methods->get_authentic_pixels_handler;
4886 if (cache_methods->queue_authentic_pixels_handler !=
4887 (QueueAuthenticPixelsHandler) NULL)
4888 cache_info->methods.queue_authentic_pixels_handler=
4889 cache_methods->queue_authentic_pixels_handler;
4890 if (cache_methods->sync_authentic_pixels_handler !=
4891 (SyncAuthenticPixelsHandler) NULL)
4892 cache_info->methods.sync_authentic_pixels_handler=
4893 cache_methods->sync_authentic_pixels_handler;
4894 if (cache_methods->get_authentic_pixels_from_handler !=
4895 (GetAuthenticPixelsFromHandler) NULL)
4896 cache_info->methods.get_authentic_pixels_from_handler=
4897 cache_methods->get_authentic_pixels_from_handler;
4898 if (cache_methods->get_authentic_indexes_from_handler !=
4899 (GetAuthenticIndexesFromHandler) NULL)
4900 cache_info->methods.get_authentic_indexes_from_handler=
4901 cache_methods->get_authentic_indexes_from_handler;
4902 get_one_virtual_pixel_from_handler=
4903 cache_info->methods.get_one_virtual_pixel_from_handler;
4904 if (get_one_virtual_pixel_from_handler !=
4905 (GetOneVirtualPixelFromHandler) NULL)
4906 cache_info->methods.get_one_virtual_pixel_from_handler=
4907 cache_methods->get_one_virtual_pixel_from_handler;
4908 get_one_authentic_pixel_from_handler=
4909 cache_methods->get_one_authentic_pixel_from_handler;
4910 if (get_one_authentic_pixel_from_handler !=
4911 (GetOneAuthenticPixelFromHandler) NULL)
4912 cache_info->methods.get_one_authentic_pixel_from_handler=
4913 cache_methods->get_one_authentic_pixel_from_handler;
4914}
4915
4916/*
4917%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4918% %
4919% %
4920% %
4921+ S e t P i x e l C a c h e N e x u s P i x e l s %
4922% %
4923% %
4924% %
4925%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4926%
4927% SetPixelCacheNexusPixels() defines the region of the cache for the
4928% specified cache nexus.
4929%
4930% The format of the SetPixelCacheNexusPixels() method is:
4931%
4932% PixelPacket SetPixelCacheNexusPixels(const Image *image,
4933% const RectangleInfo *region,NexusInfo *nexus_info,
4934% ExceptionInfo *exception)
4935%
4936% A description of each parameter follows:
4937%
4938% o image: the image.
4939%
4940% o region: A pointer to the RectangleInfo structure that defines the
4941% region of this particular cache nexus.
4942%
4943% o nexus_info: the cache nexus to set.
4944%
4945% o exception: return any errors or warnings in this structure.
4946%
4947*/
cristyabd6e372010-09-15 19:11:26 +00004948
4949static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4950 NexusInfo *nexus_info,ExceptionInfo *exception)
4951{
4952 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4953 return(MagickFalse);
4954 nexus_info->mapped=MagickFalse;
4955 nexus_info->cache=(PixelPacket *) AcquireMagickMemory((size_t)
4956 nexus_info->length);
4957 if (nexus_info->cache == (PixelPacket *) NULL)
4958 {
4959 nexus_info->mapped=MagickTrue;
4960 nexus_info->cache=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
4961 nexus_info->length);
4962 }
4963 if (nexus_info->cache == (PixelPacket *) NULL)
4964 {
4965 (void) ThrowMagickException(exception,GetMagickModule(),
4966 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4967 cache_info->filename);
4968 return(MagickFalse);
4969 }
4970 return(MagickTrue);
4971}
4972
cristy3ed852e2009-09-05 21:47:34 +00004973static PixelPacket *SetPixelCacheNexusPixels(const Image *image,
4974 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4975{
4976 CacheInfo
4977 *cache_info;
4978
4979 MagickBooleanType
4980 status;
4981
cristy3ed852e2009-09-05 21:47:34 +00004982 MagickSizeType
4983 length,
4984 number_pixels;
4985
cristy3ed852e2009-09-05 21:47:34 +00004986 cache_info=(CacheInfo *) image->cache;
4987 assert(cache_info->signature == MagickSignature);
4988 if (cache_info->type == UndefinedCache)
4989 return((PixelPacket *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00004990 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00004991 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
4992 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00004993 {
cristybb503372010-05-27 20:51:26 +00004994 ssize_t
cristybad067a2010-02-15 17:20:55 +00004995 x,
4996 y;
cristy3ed852e2009-09-05 21:47:34 +00004997
cristyeaedf062010-05-29 22:36:02 +00004998 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4999 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00005000 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5001 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00005002 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00005003 ((nexus_info->region.width == cache_info->columns) ||
5004 ((nexus_info->region.width % cache_info->columns) == 0)))))
5005 {
5006 MagickOffsetType
5007 offset;
5008
5009 /*
5010 Pixels are accessed directly from memory.
5011 */
5012 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5013 nexus_info->region.x;
5014 nexus_info->pixels=cache_info->pixels+offset;
5015 nexus_info->indexes=(IndexPacket *) NULL;
5016 if (cache_info->active_index_channel != MagickFalse)
5017 nexus_info->indexes=cache_info->indexes+offset;
5018 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00005019 }
5020 }
5021 /*
5022 Pixels are stored in a cache region until they are synced to the cache.
5023 */
5024 number_pixels=(MagickSizeType) nexus_info->region.width*
5025 nexus_info->region.height;
5026 length=number_pixels*sizeof(PixelPacket);
5027 if (cache_info->active_index_channel != MagickFalse)
5028 length+=number_pixels*sizeof(IndexPacket);
5029 if (nexus_info->cache == (PixelPacket *) NULL)
5030 {
5031 nexus_info->length=length;
5032 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5033 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005034 {
5035 nexus_info->length=0;
5036 return((PixelPacket *) NULL);
5037 }
cristy3ed852e2009-09-05 21:47:34 +00005038 }
5039 else
5040 if (nexus_info->length != length)
5041 {
5042 RelinquishCacheNexusPixels(nexus_info);
5043 nexus_info->length=length;
5044 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5045 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005046 {
5047 nexus_info->length=0;
5048 return((PixelPacket *) NULL);
5049 }
cristy3ed852e2009-09-05 21:47:34 +00005050 }
5051 nexus_info->pixels=nexus_info->cache;
5052 nexus_info->indexes=(IndexPacket *) NULL;
5053 if (cache_info->active_index_channel != MagickFalse)
5054 nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
5055 return(nexus_info->pixels);
5056}
5057
5058/*
5059%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5060% %
5061% %
5062% %
5063% 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 %
5064% %
5065% %
5066% %
5067%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5068%
5069% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5070% pixel cache and returns the previous setting. A virtual pixel is any pixel
5071% access that is outside the boundaries of the image cache.
5072%
5073% The format of the SetPixelCacheVirtualMethod() method is:
5074%
5075% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5076% const VirtualPixelMethod virtual_pixel_method)
5077%
5078% A description of each parameter follows:
5079%
5080% o image: the image.
5081%
5082% o virtual_pixel_method: choose the type of virtual pixel.
5083%
5084*/
5085MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5086 const VirtualPixelMethod virtual_pixel_method)
5087{
5088 CacheInfo
5089 *cache_info;
5090
5091 VirtualPixelMethod
5092 method;
5093
5094 assert(image != (Image *) NULL);
5095 assert(image->signature == MagickSignature);
5096 if (image->debug != MagickFalse)
5097 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5098 assert(image->cache != (Cache) NULL);
5099 cache_info=(CacheInfo *) image->cache;
5100 assert(cache_info->signature == MagickSignature);
5101 method=cache_info->virtual_pixel_method;
5102 cache_info->virtual_pixel_method=virtual_pixel_method;
5103 return(method);
5104}
5105
5106/*
5107%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5108% %
5109% %
5110% %
5111+ 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 %
5112% %
5113% %
5114% %
5115%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5116%
5117% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5118% in-memory or disk cache. The method returns MagickTrue if the pixel region
5119% is synced, otherwise MagickFalse.
5120%
5121% The format of the SyncAuthenticPixelCacheNexus() method is:
5122%
5123% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5124% NexusInfo *nexus_info,ExceptionInfo *exception)
5125%
5126% A description of each parameter follows:
5127%
5128% o image: the image.
5129%
5130% o nexus_info: the cache nexus to sync.
5131%
5132% o exception: return any errors or warnings in this structure.
5133%
5134*/
5135MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5136 NexusInfo *nexus_info,ExceptionInfo *exception)
5137{
5138 CacheInfo
5139 *cache_info;
5140
5141 MagickBooleanType
5142 status;
5143
5144 /*
5145 Transfer pixels to the cache.
5146 */
5147 assert(image != (Image *) NULL);
5148 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005149 if (image->cache == (Cache) NULL)
5150 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5151 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005152 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005153 if (cache_info->type == UndefinedCache)
5154 return(MagickFalse);
5155 if ((image->clip_mask != (Image *) NULL) &&
5156 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5157 return(MagickFalse);
5158 if ((image->mask != (Image *) NULL) &&
5159 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5160 return(MagickFalse);
5161 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5162 return(MagickTrue);
5163 assert(cache_info->signature == MagickSignature);
5164 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5165 if ((cache_info->active_index_channel != MagickFalse) &&
5166 (WritePixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse))
5167 return(MagickFalse);
5168 return(status);
5169}
5170
5171/*
5172%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5173% %
5174% %
5175% %
5176+ S y n c A u t h e n t i c P i x e l C a c h e %
5177% %
5178% %
5179% %
5180%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5181%
5182% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5183% or disk cache. The method returns MagickTrue if the pixel region is synced,
5184% otherwise MagickFalse.
5185%
5186% The format of the SyncAuthenticPixelsCache() method is:
5187%
5188% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5189% ExceptionInfo *exception)
5190%
5191% A description of each parameter follows:
5192%
5193% o image: the image.
5194%
5195% o exception: return any errors or warnings in this structure.
5196%
5197*/
5198static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5199 ExceptionInfo *exception)
5200{
5201 CacheInfo
5202 *cache_info;
5203
cristy5c9e6f22010-09-17 17:31:01 +00005204 const int
5205 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005206
cristye7cc7cf2010-09-21 13:26:47 +00005207 assert(image != (Image *) NULL);
5208 assert(image->signature == MagickSignature);
5209 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005210 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005211 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005212 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00005213 return(SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5214 exception));
cristy3ed852e2009-09-05 21:47:34 +00005215}
5216
5217/*
5218%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5219% %
5220% %
5221% %
5222% S y n c A u t h e n t i c P i x e l s %
5223% %
5224% %
5225% %
5226%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5227%
5228% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5229% The method returns MagickTrue if the pixel region is flushed, otherwise
5230% MagickFalse.
5231%
5232% The format of the SyncAuthenticPixels() method is:
5233%
5234% MagickBooleanType SyncAuthenticPixels(Image *image,
5235% ExceptionInfo *exception)
5236%
5237% A description of each parameter follows:
5238%
5239% o image: the image.
5240%
5241% o exception: return any errors or warnings in this structure.
5242%
5243*/
5244MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5245 ExceptionInfo *exception)
5246{
5247 CacheInfo
5248 *cache_info;
5249
cristy2036f5c2010-09-19 21:18:17 +00005250 const int
5251 id = GetOpenMPThreadId();
5252
cristy3ed852e2009-09-05 21:47:34 +00005253 assert(image != (Image *) NULL);
5254 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005255 assert(image->cache != (Cache) NULL);
5256 cache_info=(CacheInfo *) image->cache;
5257 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005258 if (cache_info->methods.sync_authentic_pixels_handler !=
5259 (SyncAuthenticPixelsHandler) NULL)
5260 return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
cristy2036f5c2010-09-19 21:18:17 +00005261 assert(id < (int) cache_info->number_threads);
5262 return(SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5263 exception));
cristy3ed852e2009-09-05 21:47:34 +00005264}
5265
5266/*
5267%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5268% %
5269% %
5270% %
5271+ W r i t e P i x e l C a c h e I n d e x e s %
5272% %
5273% %
5274% %
5275%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5276%
5277% WritePixelCacheIndexes() writes the colormap indexes to the specified
5278% region of the pixel cache.
5279%
5280% The format of the WritePixelCacheIndexes() method is:
5281%
5282% MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5283% NexusInfo *nexus_info,ExceptionInfo *exception)
5284%
5285% A description of each parameter follows:
5286%
5287% o cache_info: the pixel cache.
5288%
5289% o nexus_info: the cache nexus to write the colormap indexes.
5290%
5291% o exception: return any errors or warnings in this structure.
5292%
5293*/
5294static MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5295 NexusInfo *nexus_info,ExceptionInfo *exception)
5296{
5297 MagickOffsetType
5298 count,
5299 offset;
5300
5301 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005302 extent,
5303 length;
cristy3ed852e2009-09-05 21:47:34 +00005304
5305 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005306 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005307
cristybb503372010-05-27 20:51:26 +00005308 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005309 y;
5310
cristybb503372010-05-27 20:51:26 +00005311 size_t
cristy3ed852e2009-09-05 21:47:34 +00005312 rows;
5313
cristy3ed852e2009-09-05 21:47:34 +00005314 if (cache_info->active_index_channel == MagickFalse)
5315 return(MagickFalse);
5316 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5317 return(MagickTrue);
5318 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5319 nexus_info->region.x;
5320 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
5321 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005322 extent=(MagickSizeType) length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005323 p=nexus_info->indexes;
5324 switch (cache_info->type)
5325 {
5326 case MemoryCache:
5327 case MapCache:
5328 {
5329 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005330 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005331
5332 /*
5333 Write indexes to memory.
5334 */
cristydd341db2010-03-04 19:06:38 +00005335 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005336 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005337 {
cristy48078b12010-09-23 17:11:01 +00005338 length=extent;
cristydd341db2010-03-04 19:06:38 +00005339 rows=1UL;
5340 }
cristy3ed852e2009-09-05 21:47:34 +00005341 q=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00005342 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005343 {
cristy8f036fe2010-09-18 02:02:00 +00005344 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00005345 p+=nexus_info->region.width;
5346 q+=cache_info->columns;
5347 }
5348 break;
5349 }
5350 case DiskCache:
5351 {
5352 /*
5353 Write indexes to disk.
5354 */
5355 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5356 {
5357 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5358 cache_info->cache_filename);
5359 return(MagickFalse);
5360 }
cristydd341db2010-03-04 19:06:38 +00005361 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005362 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005363 {
cristy48078b12010-09-23 17:11:01 +00005364 length=extent;
cristydd341db2010-03-04 19:06:38 +00005365 rows=1UL;
5366 }
cristy48078b12010-09-23 17:11:01 +00005367 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005368 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005369 {
cristy48078b12010-09-23 17:11:01 +00005370 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5371 sizeof(PixelPacket)+offset*sizeof(*p),length,(const unsigned char *)
5372 p);
cristy3ed852e2009-09-05 21:47:34 +00005373 if ((MagickSizeType) count < length)
5374 break;
5375 p+=nexus_info->region.width;
5376 offset+=cache_info->columns;
5377 }
cristybb503372010-05-27 20:51:26 +00005378 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005379 {
5380 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5381 cache_info->cache_filename);
5382 return(MagickFalse);
5383 }
5384 break;
5385 }
5386 default:
5387 break;
5388 }
5389 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005390 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005391 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005392 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005393 nexus_info->region.width,(double) nexus_info->region.height,(double)
5394 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005395 return(MagickTrue);
5396}
5397
5398/*
5399%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5400% %
5401% %
5402% %
5403+ W r i t e C a c h e P i x e l s %
5404% %
5405% %
5406% %
5407%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5408%
5409% WritePixelCachePixels() writes image pixels to the specified region of the
5410% pixel cache.
5411%
5412% The format of the WritePixelCachePixels() method is:
5413%
5414% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5415% NexusInfo *nexus_info,ExceptionInfo *exception)
5416%
5417% A description of each parameter follows:
5418%
5419% o cache_info: the pixel cache.
5420%
5421% o nexus_info: the cache nexus to write the pixels.
5422%
5423% o exception: return any errors or warnings in this structure.
5424%
5425*/
5426static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5427 NexusInfo *nexus_info,ExceptionInfo *exception)
5428{
5429 MagickOffsetType
5430 count,
5431 offset;
5432
5433 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005434 extent,
5435 length;
cristy3ed852e2009-09-05 21:47:34 +00005436
cristy3ed852e2009-09-05 21:47:34 +00005437 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005438 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005439
cristybb503372010-05-27 20:51:26 +00005440 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005441 y;
5442
cristybb503372010-05-27 20:51:26 +00005443 size_t
cristy3ed852e2009-09-05 21:47:34 +00005444 rows;
5445
cristy3ed852e2009-09-05 21:47:34 +00005446 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5447 return(MagickTrue);
5448 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5449 nexus_info->region.x;
5450 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
5451 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005452 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005453 p=nexus_info->pixels;
5454 switch (cache_info->type)
5455 {
5456 case MemoryCache:
5457 case MapCache:
5458 {
5459 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005460 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005461
5462 /*
5463 Write pixels to memory.
5464 */
cristydd341db2010-03-04 19:06:38 +00005465 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005466 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005467 {
cristy48078b12010-09-23 17:11:01 +00005468 length=extent;
cristydd341db2010-03-04 19:06:38 +00005469 rows=1UL;
5470 }
cristy3ed852e2009-09-05 21:47:34 +00005471 q=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00005472 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005473 {
cristy8f036fe2010-09-18 02:02:00 +00005474 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00005475 p+=nexus_info->region.width;
5476 q+=cache_info->columns;
5477 }
5478 break;
5479 }
5480 case DiskCache:
5481 {
5482 /*
5483 Write pixels to disk.
5484 */
5485 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5486 {
5487 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5488 cache_info->cache_filename);
5489 return(MagickFalse);
5490 }
cristydd341db2010-03-04 19:06:38 +00005491 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005492 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005493 {
cristy48078b12010-09-23 17:11:01 +00005494 length=extent;
cristydd341db2010-03-04 19:06:38 +00005495 rows=1UL;
5496 }
cristybb503372010-05-27 20:51:26 +00005497 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005498 {
5499 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5500 sizeof(*p),length,(const unsigned char *) p);
5501 if ((MagickSizeType) count < length)
5502 break;
5503 p+=nexus_info->region.width;
5504 offset+=cache_info->columns;
5505 }
cristybb503372010-05-27 20:51:26 +00005506 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005507 {
5508 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5509 cache_info->cache_filename);
5510 return(MagickFalse);
5511 }
5512 break;
5513 }
5514 default:
5515 break;
5516 }
5517 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005518 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005519 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005520 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005521 nexus_info->region.width,(double) nexus_info->region.height,(double)
5522 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005523 return(MagickTrue);
5524}