blob: 62667e778ee5f4510727299248025a789514e9be [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% CCCC AAA CCCC H H EEEEE %
7% C A A C H H E %
8% C AAAAA C HHHHH EEE %
9% C A A C H H E %
10% CCCC A A CCCC H H EEEEE %
11% %
12% %
13% MagickCore Pixel Cache Methods %
14% %
15% Software Design %
16% John Cristy %
17% July 1999 %
18% %
19% %
cristy16af1cb2009-12-11 21:38:29 +000020% Copyright 1999-2010 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
26% http://www.imagemagick.org/script/license.php %
27% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37%
38*/
39
40/*
41 Include declarations.
42*/
43#include "magick/studio.h"
44#include "magick/blob.h"
45#include "magick/blob-private.h"
46#include "magick/cache.h"
47#include "magick/cache-private.h"
48#include "magick/color-private.h"
49#include "magick/composite-private.h"
50#include "magick/exception.h"
51#include "magick/exception-private.h"
cristy365e58f2010-02-15 02:00:01 +000052#include "magick/geometry.h"
cristy3ed852e2009-09-05 21:47:34 +000053#include "magick/list.h"
54#include "magick/log.h"
55#include "magick/magick.h"
56#include "magick/memory_.h"
cristy4789f0d2010-01-10 00:01:06 +000057#include "magick/pixel.h"
cristy3ed852e2009-09-05 21:47:34 +000058#include "magick/pixel-private.h"
cristya21afde2010-07-02 00:45:40 +000059#include "magick/policy.h"
cristy3ed852e2009-09-05 21:47:34 +000060#include "magick/quantum.h"
61#include "magick/random_.h"
62#include "magick/resource_.h"
63#include "magick/semaphore.h"
64#include "magick/splay-tree.h"
65#include "magick/string_.h"
cristya21afde2010-07-02 00:45:40 +000066#include "magick/string-private.h"
cristy3ed852e2009-09-05 21:47:34 +000067#include "magick/thread-private.h"
68#include "magick/utility.h"
69#if defined(MAGICKCORE_ZLIB_DELEGATE)
70#include "zlib.h"
71#endif
72
73/*
cristy30097232010-07-01 02:16:30 +000074 Define declarations.
75*/
76#define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
77
78/*
cristy3ed852e2009-09-05 21:47:34 +000079 Typedef declarations.
80*/
81typedef struct _MagickModulo
82{
cristybb503372010-05-27 20:51:26 +000083 ssize_t
cristy3ed852e2009-09-05 21:47:34 +000084 quotient,
85 remainder;
86} MagickModulo;
87
88struct _NexusInfo
89{
90 MagickBooleanType
91 mapped;
92
93 RectangleInfo
94 region;
95
96 MagickSizeType
97 length;
98
99 PixelPacket
100 *cache,
101 *pixels;
102
103 IndexPacket
104 *indexes;
105
cristybb503372010-05-27 20:51:26 +0000106 size_t
cristy3ed852e2009-09-05 21:47:34 +0000107 signature;
108};
109
110/*
111 Forward declarations.
112*/
113#if defined(__cplusplus) || defined(c_plusplus)
114extern "C" {
115#endif
116
117static const IndexPacket
118 *GetVirtualIndexesFromCache(const Image *);
119
120static const PixelPacket
cristybb503372010-05-27 20:51:26 +0000121 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
cristye7cc7cf2010-09-21 13:26:47 +0000122 const ssize_t,const size_t,const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000123 *GetVirtualPixelsCache(const Image *);
124
125static MagickBooleanType
cristye7cc7cf2010-09-21 13:26:47 +0000126 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,
127 PixelPacket *,ExceptionInfo *),
128 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
129 const ssize_t,const ssize_t,PixelPacket *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000130 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
131 ReadPixelCacheIndexes(CacheInfo *,NexusInfo *,ExceptionInfo *),
132 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
133 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
134 WritePixelCacheIndexes(CacheInfo *,NexusInfo *,ExceptionInfo *),
135 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
136
137static PixelPacket
cristye7cc7cf2010-09-21 13:26:47 +0000138 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
139 const size_t,ExceptionInfo *),
cristybb503372010-05-27 20:51:26 +0000140 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
141 const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000142 *SetPixelCacheNexusPixels(const Image *,const RectangleInfo *,NexusInfo *,
cristya4af2e32010-03-08 00:51:56 +0000143 ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +0000144
145#if defined(__cplusplus) || defined(c_plusplus)
146}
147#endif
148
149/*
150 Global declarations.
151*/
152static volatile MagickBooleanType
153 instantiate_cache = MagickFalse;
154
155static SemaphoreInfo
156 *cache_semaphore = (SemaphoreInfo *) NULL;
157
158static SplayTreeInfo
159 *cache_resources = (SplayTreeInfo *) NULL;
cristy3ed852e2009-09-05 21:47:34 +0000160
161/*
162%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
163% %
164% %
165% %
166+ A c q u i r e P i x e l C a c h e %
167% %
168% %
169% %
170%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
171%
172% AcquirePixelCache() acquires a pixel cache.
173%
174% The format of the AcquirePixelCache() method is:
175%
cristybb503372010-05-27 20:51:26 +0000176% Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000177%
178% A description of each parameter follows:
179%
180% o number_threads: the number of nexus threads.
181%
182*/
cristybb503372010-05-27 20:51:26 +0000183MagickExport Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000184{
185 CacheInfo
186 *cache_info;
187
cristy73bd4a52010-10-05 11:24:23 +0000188 cache_info=(CacheInfo *) AcquireMagickMemory(sizeof(*cache_info));
cristy3ed852e2009-09-05 21:47:34 +0000189 if (cache_info == (CacheInfo *) NULL)
190 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
191 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
192 cache_info->type=UndefinedCache;
cristy87528ea2009-09-10 14:53:56 +0000193 cache_info->mode=IOMode;
cristy3ed852e2009-09-05 21:47:34 +0000194 cache_info->colorspace=RGBColorspace;
195 cache_info->file=(-1);
196 cache_info->id=GetMagickThreadId();
197 cache_info->number_threads=number_threads;
198 if (number_threads == 0)
199 cache_info->number_threads=GetOpenMPMaximumThreads();
200 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
201 if (cache_info->nexus_info == (NexusInfo **) NULL)
202 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristy3ed852e2009-09-05 21:47:34 +0000203 cache_info->semaphore=AllocateSemaphoreInfo();
cristy93505cf2010-08-10 21:37:49 +0000204 cache_info->reference_count=1;
cristy3ed852e2009-09-05 21:47:34 +0000205 cache_info->disk_semaphore=AllocateSemaphoreInfo();
206 cache_info->debug=IsEventLogging();
207 cache_info->signature=MagickSignature;
208 if ((cache_resources == (SplayTreeInfo *) NULL) &&
209 (instantiate_cache == MagickFalse))
210 {
cristy4e1dff62009-10-25 20:36:03 +0000211 if (cache_semaphore == (SemaphoreInfo *) NULL)
212 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000213 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000214 if ((cache_resources == (SplayTreeInfo *) NULL) &&
215 (instantiate_cache == MagickFalse))
216 {
217 cache_resources=NewSplayTree((int (*)(const void *,const void *))
218 NULL,(void *(*)(void *)) NULL,(void *(*)(void *)) NULL);
219 instantiate_cache=MagickTrue;
220 }
cristyf84a1932010-01-03 18:00:18 +0000221 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000222 }
223 (void) AddValueToSplayTree(cache_resources,cache_info,cache_info);
224 return((Cache ) cache_info);
225}
226
227/*
228%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
229% %
230% %
231% %
232% A c q u i r e P i x e l C a c h e N e x u s %
233% %
234% %
235% %
236%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
237%
238% AcquirePixelCacheNexus() allocates the NexusInfo structure.
239%
240% The format of the AcquirePixelCacheNexus method is:
241%
cristybb503372010-05-27 20:51:26 +0000242% NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000243%
244% A description of each parameter follows:
245%
246% o number_threads: the number of nexus threads.
247%
248*/
cristy2cd7a752010-08-23 00:48:54 +0000249MagickExport NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000250{
cristy3ed852e2009-09-05 21:47:34 +0000251 NexusInfo
252 **nexus_info;
253
cristye076a6e2010-08-15 19:59:43 +0000254 register ssize_t
255 i;
256
cristyb41ee102010-10-04 16:46:15 +0000257 nexus_info=(NexusInfo **) AcquireQuantumMemory(number_threads,
cristy3ed852e2009-09-05 21:47:34 +0000258 sizeof(*nexus_info));
259 if (nexus_info == (NexusInfo **) NULL)
260 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristybb503372010-05-27 20:51:26 +0000261 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000262 {
cristy6a924af2010-09-23 14:02:54 +0000263 nexus_info[i]=(NexusInfo *) AcquireAlignedMemory(1,sizeof(**nexus_info));
cristy3ed852e2009-09-05 21:47:34 +0000264 if (nexus_info[i] == (NexusInfo *) NULL)
265 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
266 (void) ResetMagickMemory(nexus_info[i],0,sizeof(*nexus_info[i]));
267 nexus_info[i]->signature=MagickSignature;
268 }
269 return(nexus_info);
270}
271
272/*
273%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
274% %
275% %
276% %
cristyd43a46b2010-01-21 02:13:41 +0000277+ A c q u i r e P i x e l C a c h e P i x e l s %
278% %
279% %
280% %
281%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
282%
283% AcquirePixelCachePixels() returns the pixels associated with the specified
284% image.
285%
286% The format of the AcquirePixelCachePixels() method is:
287%
288% const void *AcquirePixelCachePixels(const Image *image,
289% MagickSizeType *length,ExceptionInfo *exception)
290%
291% A description of each parameter follows:
292%
293% o image: the image.
294%
295% o length: the pixel cache length.
296%
297% o exception: return any errors or warnings in this structure.
298%
299*/
300MagickExport const void *AcquirePixelCachePixels(const Image *image,
301 MagickSizeType *length,ExceptionInfo *exception)
302{
303 CacheInfo
304 *cache_info;
305
306 assert(image != (const Image *) NULL);
307 assert(image->signature == MagickSignature);
cristyd43a46b2010-01-21 02:13:41 +0000308 assert(exception != (ExceptionInfo *) NULL);
309 assert(exception->signature == MagickSignature);
310 assert(image->cache != (Cache) NULL);
311 cache_info=(CacheInfo *) image->cache;
312 assert(cache_info->signature == MagickSignature);
313 *length=0;
314 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
315 return((const void *) NULL);
316 *length=cache_info->length;
317 return((const void *) cache_info->pixels);
318}
319
320/*
321%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
322% %
323% %
324% %
cristyf34a1452009-10-24 22:29:27 +0000325+ C a c h e C o m p o n e n t G e n e s i s %
326% %
327% %
328% %
329%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
330%
331% CacheComponentGenesis() instantiates the cache component.
332%
333% The format of the CacheComponentGenesis method is:
334%
335% MagickBooleanType CacheComponentGenesis(void)
336%
337*/
338MagickExport MagickBooleanType CacheComponentGenesis(void)
339{
cristy165b6092009-10-26 13:52:10 +0000340 AcquireSemaphoreInfo(&cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000341 return(MagickTrue);
342}
343
344/*
345%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
346% %
347% %
348% %
349+ C a c h e C o m p o n e n t T e r m i n u s %
350% %
351% %
352% %
353%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
354%
355% CacheComponentTerminus() destroys the cache component.
356%
357% The format of the CacheComponentTerminus() method is:
358%
359% CacheComponentTerminus(void)
360%
361*/
362MagickExport void CacheComponentTerminus(void)
363{
cristy18b17442009-10-25 18:36:48 +0000364 if (cache_semaphore == (SemaphoreInfo *) NULL)
365 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000366 LockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000367 if (cache_resources != (SplayTreeInfo *) NULL)
368 cache_resources=DestroySplayTree(cache_resources);
369 instantiate_cache=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +0000370 UnlockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000371 DestroySemaphoreInfo(&cache_semaphore);
372}
373
374/*
375%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
376% %
377% %
378% %
cristy3ed852e2009-09-05 21:47:34 +0000379+ C l i p P i x e l C a c h e N e x u s %
380% %
381% %
382% %
383%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
384%
385% ClipPixelCacheNexus() clips the cache nexus as defined by the image clip
386% mask. The method returns MagickTrue if the pixel region is clipped,
387% otherwise MagickFalse.
388%
389% The format of the ClipPixelCacheNexus() method is:
390%
391% MagickBooleanType ClipPixelCacheNexus(Image *image,NexusInfo *nexus_info,
392% ExceptionInfo *exception)
393%
394% A description of each parameter follows:
395%
396% o image: the image.
397%
398% o nexus_info: the cache nexus to clip.
399%
400% o exception: return any errors or warnings in this structure.
401%
402*/
403static MagickBooleanType ClipPixelCacheNexus(Image *image,
404 NexusInfo *nexus_info,ExceptionInfo *exception)
405{
406 CacheInfo
407 *cache_info;
408
409 MagickSizeType
410 number_pixels;
411
412 NexusInfo
413 **clip_nexus,
414 **image_nexus;
415
416 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000417 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +0000418
419 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +0000420 *restrict nexus_indexes,
421 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +0000422
cristy3ed852e2009-09-05 21:47:34 +0000423 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000424 *restrict p,
425 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000426
cristye076a6e2010-08-15 19:59:43 +0000427 register ssize_t
428 i;
429
cristy3ed852e2009-09-05 21:47:34 +0000430 /*
431 Apply clip mask.
432 */
433 if (image->debug != MagickFalse)
434 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
435 if (image->clip_mask == (Image *) NULL)
436 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +0000437 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +0000438 if (cache_info == (Cache) NULL)
439 return(MagickFalse);
440 image_nexus=AcquirePixelCacheNexus(1);
441 clip_nexus=AcquirePixelCacheNexus(1);
442 if ((image_nexus == (NexusInfo **) NULL) ||
443 (clip_nexus == (NexusInfo **) NULL))
444 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
445 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,nexus_info->region.y,
446 nexus_info->region.width,nexus_info->region.height,image_nexus[0],
447 exception);
cristy2036f5c2010-09-19 21:18:17 +0000448 indexes=GetPixelCacheNexusIndexes(cache_info,image_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +0000449 q=nexus_info->pixels;
450 nexus_indexes=nexus_info->indexes;
451 r=GetVirtualPixelsFromNexus(image->clip_mask,MaskVirtualPixelMethod,
452 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
453 nexus_info->region.height,clip_nexus[0],exception);
454 number_pixels=(MagickSizeType) nexus_info->region.width*
455 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +0000456 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000457 {
458 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
459 break;
460 if (PixelIntensityToQuantum(r) > ((Quantum) QuantumRange/2))
461 {
cristyce70c172010-01-07 17:15:30 +0000462 SetRedPixelComponent(q,GetRedPixelComponent(p));
463 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
464 SetBluePixelComponent(q,GetBluePixelComponent(p));
465 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
cristy3ed852e2009-09-05 21:47:34 +0000466 if (cache_info->active_index_channel != MagickFalse)
467 nexus_indexes[i]=indexes[i];
468 }
469 p++;
470 q++;
471 r++;
472 }
473 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
474 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +0000475 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +0000476 return(MagickFalse);
477 return(MagickTrue);
478}
479
480/*
481%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
482% %
483% %
484% %
485+ C l o n e P i x e l C a c h e %
486% %
487% %
488% %
489%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
490%
491% ClonePixelCache() clones a pixel cache.
492%
493% The format of the ClonePixelCache() method is:
494%
495% Cache ClonePixelCache(const Cache cache)
496%
497% A description of each parameter follows:
498%
499% o cache: the pixel cache.
500%
501*/
502MagickExport Cache ClonePixelCache(const Cache cache)
503{
504 CacheInfo
505 *clone_info;
506
507 const CacheInfo
508 *cache_info;
509
510 assert(cache != (const Cache) NULL);
511 cache_info=(const CacheInfo *) cache;
512 assert(cache_info->signature == MagickSignature);
513 if (cache_info->debug != MagickFalse)
514 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
515 cache_info->filename);
516 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
517 if (clone_info == (Cache) NULL)
518 return((Cache) NULL);
519 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
520 return((Cache ) clone_info);
521}
522
523/*
524%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
525% %
526% %
527% %
cristy60c44a82009-10-07 00:58:49 +0000528+ C l o n e P i x e l C a c h e P i x e l s %
cristy3ed852e2009-09-05 21:47:34 +0000529% %
530% %
531% %
532%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
533% ClonePixelCachePixels() clones the source pixel cache to the destination
534% cache.
535%
536% The format of the ClonePixelCachePixels() method is:
537%
538% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
539% CacheInfo *source_info,ExceptionInfo *exception)
540%
541% A description of each parameter follows:
542%
543% o cache_info: the pixel cache.
544%
545% o source_info: the source pixel cache.
546%
547% o exception: return any errors or warnings in this structure.
548%
549*/
550
551static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
552{
553 int
554 status;
555
cristy5ee247a2010-02-12 15:42:34 +0000556 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000557 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000558 if (cache_info->file != -1)
559 status=close(cache_info->file);
cristy3ed852e2009-09-05 21:47:34 +0000560 cache_info->file=(-1);
561 RelinquishMagickResource(FileResource,1);
cristyf84a1932010-01-03 18:00:18 +0000562 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000563 return(status == -1 ? MagickFalse : MagickTrue);
564}
565
566static void LimitPixelCacheDescriptors(void)
567{
568 register CacheInfo
569 *p,
570 *q;
571
572 /*
573 Limit # of open file descriptors.
574 */
575 if (GetMagickResource(FileResource) < GetMagickResourceLimit(FileResource))
576 return;
cristyf84a1932010-01-03 18:00:18 +0000577 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000578 if (cache_resources == (SplayTreeInfo *) NULL)
579 {
cristyf84a1932010-01-03 18:00:18 +0000580 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000581 return;
582 }
583 ResetSplayTreeIterator(cache_resources);
584 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
585 while (p != (CacheInfo *) NULL)
586 {
587 if ((p->type == DiskCache) && (p->file != -1))
cristy508d9312010-02-10 21:10:30 +0000588 break;
cristy3ed852e2009-09-05 21:47:34 +0000589 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
590 }
591 for (q=p; p != (CacheInfo *) NULL; )
592 {
593 if ((p->type == DiskCache) && (p->file != -1) &&
594 (p->timestamp < q->timestamp))
cristy508d9312010-02-10 21:10:30 +0000595 q=p;
cristy3ed852e2009-09-05 21:47:34 +0000596 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
597 }
598 if (q != (CacheInfo *) NULL)
cristy9e116922010-02-12 20:58:13 +0000599 {
600 /*
601 Close least recently used cache.
602 */
603 (void) close(q->file);
604 q->file=(-1);
605 }
cristyf84a1932010-01-03 18:00:18 +0000606 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000607}
608
609static inline MagickSizeType MagickMax(const MagickSizeType x,
610 const MagickSizeType y)
611{
612 if (x > y)
613 return(x);
614 return(y);
615}
616
617static inline MagickSizeType MagickMin(const MagickSizeType x,
618 const MagickSizeType y)
619{
620 if (x < y)
621 return(x);
622 return(y);
623}
624
625static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
626 const MapMode mode)
627{
628 int
629 file;
630
631 /*
632 Open pixel cache on disk.
633 */
cristyf84a1932010-01-03 18:00:18 +0000634 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000635 if (cache_info->file != -1)
636 {
cristyf84a1932010-01-03 18:00:18 +0000637 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000638 return(MagickTrue); /* cache already open */
639 }
640 LimitPixelCacheDescriptors();
641 if (*cache_info->cache_filename == '\0')
642 file=AcquireUniqueFileResource(cache_info->cache_filename);
643 else
644 switch (mode)
645 {
646 case ReadMode:
647 {
648 file=open(cache_info->cache_filename,O_RDONLY | O_BINARY);
649 break;
650 }
651 case WriteMode:
652 {
653 file=open(cache_info->cache_filename,O_WRONLY | O_CREAT | O_BINARY |
654 O_EXCL,S_MODE);
655 if (file == -1)
656 file=open(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
657 break;
658 }
659 case IOMode:
660 default:
661 {
662 file=open(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
663 O_EXCL,S_MODE);
664 if (file == -1)
665 file=open(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
666 break;
667 }
668 }
669 if (file == -1)
670 {
cristyf84a1932010-01-03 18:00:18 +0000671 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000672 return(MagickFalse);
673 }
674 (void) AcquireMagickResource(FileResource,1);
675 cache_info->file=file;
676 cache_info->timestamp=time(0);
cristyf84a1932010-01-03 18:00:18 +0000677 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000678 return(MagickTrue);
679}
680
681static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
682 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000683 unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000684{
685 register MagickOffsetType
686 i;
687
688 ssize_t
689 count;
690
cristy08a88202010-03-04 19:18:05 +0000691 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000692#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000693 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000694 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
695 {
cristyf84a1932010-01-03 18:00:18 +0000696 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000697 return((MagickOffsetType) -1);
698 }
699#endif
700 count=0;
701 for (i=0; i < (MagickOffsetType) length; i+=count)
702 {
703#if !defined(MAGICKCORE_HAVE_PREAD)
704 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
705 (MagickSizeType) SSIZE_MAX));
706#else
707 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
708 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
709#endif
710 if (count > 0)
711 continue;
712 count=0;
713 if (errno != EINTR)
714 {
715 i=(-1);
716 break;
717 }
718 }
719#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000720 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000721#endif
722 return(i);
723}
724
725static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
726 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000727 const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000728{
729 register MagickOffsetType
730 i;
731
732 ssize_t
733 count;
734
cristy08a88202010-03-04 19:18:05 +0000735 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000736#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000737 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000738 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
739 {
cristyf84a1932010-01-03 18:00:18 +0000740 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000741 return((MagickOffsetType) -1);
742 }
743#endif
744 count=0;
745 for (i=0; i < (MagickOffsetType) length; i+=count)
746 {
747#if !defined(MAGICKCORE_HAVE_PWRITE)
748 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
749 (MagickSizeType) SSIZE_MAX));
750#else
751 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
752 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
753#endif
754 if (count > 0)
755 continue;
756 count=0;
757 if (errno != EINTR)
758 {
759 i=(-1);
760 break;
761 }
762 }
763#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000764 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000765#endif
766 return(i);
767}
768
769static MagickBooleanType CloneDiskToDiskPixelCache(CacheInfo *clone_info,
770 CacheInfo *cache_info,ExceptionInfo *exception)
771{
772 MagickOffsetType
773 count,
774 offset,
775 source_offset;
776
777 MagickSizeType
778 length;
779
cristy3ed852e2009-09-05 21:47:34 +0000780 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000781 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +0000782
cristye076a6e2010-08-15 19:59:43 +0000783 register ssize_t
784 y;
785
cristybb503372010-05-27 20:51:26 +0000786 size_t
cristy3ed852e2009-09-05 21:47:34 +0000787 columns,
788 rows;
789
790 if (cache_info->debug != MagickFalse)
791 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
792 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
793 {
794 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
795 clone_info->cache_filename);
796 return(MagickFalse);
797 }
798 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
799 {
800 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
801 cache_info->cache_filename);
802 return(MagickFalse);
803 }
cristybb503372010-05-27 20:51:26 +0000804 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
805 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +0000806 if ((clone_info->active_index_channel != MagickFalse) &&
807 (cache_info->active_index_channel != MagickFalse))
808 {
809 register IndexPacket
810 *indexes;
811
812 /*
813 Clone cache indexes.
814 */
815 length=MagickMax(clone_info->columns,cache_info->columns)*
816 sizeof(*indexes);
817 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
818 if (indexes == (IndexPacket *) NULL)
819 {
820 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
821 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
822 return(MagickFalse);
823 }
824 (void) ResetMagickMemory(indexes,0,(size_t) length);
825 length=columns*sizeof(*indexes);
826 source_offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
827 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
828 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
829 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +0000830 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000831 {
832 source_offset-=cache_info->columns*sizeof(*indexes);
833 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
834 length,(unsigned char *) indexes);
835 if ((MagickSizeType) count != length)
836 break;
837 offset-=clone_info->columns*sizeof(*indexes);
838 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
839 (unsigned char *) indexes);
840 if ((MagickSizeType) count != length)
841 break;
842 }
cristybb503372010-05-27 20:51:26 +0000843 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000844 {
845 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
846 ThrowFileException(exception,CacheError,"UnableToCloneCache",
847 cache_info->cache_filename);
848 return(MagickFalse);
849 }
850 if (clone_info->columns > cache_info->columns)
851 {
852 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
853 (void) ResetMagickMemory(indexes,0,(size_t) length);
854 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
855 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +0000856 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000857 {
858 offset-=clone_info->columns*sizeof(*indexes);
859 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
860 length,(unsigned char *) indexes);
861 if ((MagickSizeType) count != length)
862 break;
863 }
cristybb503372010-05-27 20:51:26 +0000864 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000865 {
866 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
867 ThrowFileException(exception,CacheError,"UnableToCloneCache",
868 cache_info->cache_filename);
869 return(MagickFalse);
870 }
871 }
872 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
873 }
874 /*
875 Clone cache pixels.
876 */
877 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
878 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
879 if (pixels == (PixelPacket *) NULL)
880 {
881 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
882 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
883 return(MagickFalse);
884 }
885 (void) ResetMagickMemory(pixels,0,(size_t) length);
886 length=columns*sizeof(*pixels);
887 source_offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
888 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +0000889 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000890 {
891 source_offset-=cache_info->columns*sizeof(*pixels);
892 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
893 length,(unsigned char *) pixels);
894 if ((MagickSizeType) count != length)
895 break;
896 offset-=clone_info->columns*sizeof(*pixels);
897 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
898 (unsigned char *) pixels);
899 if ((MagickSizeType) count != length)
900 break;
901 }
cristybb503372010-05-27 20:51:26 +0000902 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000903 {
904 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
905 ThrowFileException(exception,CacheError,"UnableToCloneCache",
906 cache_info->cache_filename);
907 return(MagickFalse);
908 }
909 if (clone_info->columns > cache_info->columns)
910 {
911 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
912 sizeof(*pixels);
913 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
914 (void) ResetMagickMemory(pixels,0,(size_t) length);
cristybb503372010-05-27 20:51:26 +0000915 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000916 {
917 offset-=clone_info->columns*sizeof(*pixels);
918 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
919 (unsigned char *) pixels);
920 if ((MagickSizeType) count != length)
921 break;
922 }
cristybb503372010-05-27 20:51:26 +0000923 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000924 {
925 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
926 ThrowFileException(exception,CacheError,"UnableToCloneCache",
927 cache_info->cache_filename);
928 return(MagickFalse);
929 }
930 }
931 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
932 return(MagickTrue);
933}
934
935static MagickBooleanType CloneDiskToMemoryPixelCache(CacheInfo *clone_info,
936 CacheInfo *cache_info,ExceptionInfo *exception)
937{
938 MagickOffsetType
939 count,
940 offset;
941
942 MagickSizeType
943 length;
944
cristy3ed852e2009-09-05 21:47:34 +0000945 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000946 *restrict pixels,
947 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000948
cristye076a6e2010-08-15 19:59:43 +0000949 register ssize_t
950 y;
951
cristybb503372010-05-27 20:51:26 +0000952 size_t
cristy3ed852e2009-09-05 21:47:34 +0000953 columns,
954 rows;
955
956 if (cache_info->debug != MagickFalse)
957 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
958 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
959 {
960 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
961 cache_info->cache_filename);
962 return(MagickFalse);
963 }
cristybb503372010-05-27 20:51:26 +0000964 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
965 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +0000966 if ((clone_info->active_index_channel != MagickFalse) &&
967 (cache_info->active_index_channel != MagickFalse))
968 {
969 register IndexPacket
970 *indexes,
971 *q;
972
973 /*
974 Clone cache indexes.
975 */
976 length=MagickMax(clone_info->columns,cache_info->columns)*
977 sizeof(*indexes);
978 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
979 if (indexes == (IndexPacket *) NULL)
980 {
981 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
982 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
983 return(MagickFalse);
984 }
985 (void) ResetMagickMemory(indexes,0,(size_t) length);
986 length=columns*sizeof(IndexPacket);
987 offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
988 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
989 q=clone_info->indexes+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +0000990 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000991 {
992 offset-=cache_info->columns*sizeof(IndexPacket);
993 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,
994 length,(unsigned char *) indexes);
995 if ((MagickSizeType) count != length)
996 break;
997 q-=clone_info->columns;
cristy8f036fe2010-09-18 02:02:00 +0000998 (void) memcpy(q,indexes,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +0000999 if ((MagickSizeType) count != length)
1000 break;
1001 }
cristybb503372010-05-27 20:51:26 +00001002 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001003 {
1004 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1005 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1006 cache_info->cache_filename);
1007 return(MagickFalse);
1008 }
1009 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1010 }
1011 /*
1012 Clone cache pixels.
1013 */
1014 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1015 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1016 if (pixels == (PixelPacket *) NULL)
1017 {
1018 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1019 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1020 return(MagickFalse);
1021 }
1022 (void) ResetMagickMemory(pixels,0,(size_t) length);
1023 length=columns*sizeof(*pixels);
1024 offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
1025 q=clone_info->pixels+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001026 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001027 {
1028 offset-=cache_info->columns*sizeof(*pixels);
1029 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,length,
1030 (unsigned char *) pixels);
1031 if ((MagickSizeType) count != length)
1032 break;
1033 q-=clone_info->columns;
cristy8f036fe2010-09-18 02:02:00 +00001034 (void) memcpy(q,pixels,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00001035 }
cristybb503372010-05-27 20:51:26 +00001036 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001037 {
1038 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1039 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1040 cache_info->cache_filename);
1041 return(MagickFalse);
1042 }
1043 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1044 return(MagickTrue);
1045}
1046
1047static MagickBooleanType CloneMemoryToDiskPixelCache(CacheInfo *clone_info,
1048 CacheInfo *cache_info,ExceptionInfo *exception)
1049{
1050 MagickOffsetType
1051 count,
1052 offset;
1053
1054 MagickSizeType
1055 length;
1056
cristy3ed852e2009-09-05 21:47:34 +00001057 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001058 *restrict p,
1059 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +00001060
cristye076a6e2010-08-15 19:59:43 +00001061 register ssize_t
1062 y;
1063
cristybb503372010-05-27 20:51:26 +00001064 size_t
cristy3ed852e2009-09-05 21:47:34 +00001065 columns,
1066 rows;
1067
1068 if (cache_info->debug != MagickFalse)
1069 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
1070 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
1071 {
1072 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1073 clone_info->cache_filename);
1074 return(MagickFalse);
1075 }
cristybb503372010-05-27 20:51:26 +00001076 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1077 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001078 if ((clone_info->active_index_channel != MagickFalse) &&
1079 (cache_info->active_index_channel != MagickFalse))
1080 {
1081 register IndexPacket
1082 *p,
1083 *indexes;
1084
1085 /*
1086 Clone cache indexes.
1087 */
1088 length=MagickMax(clone_info->columns,cache_info->columns)*
1089 sizeof(*indexes);
1090 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
1091 if (indexes == (IndexPacket *) NULL)
1092 {
1093 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1094 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1095 return(MagickFalse);
1096 }
1097 (void) ResetMagickMemory(indexes,0,(size_t) length);
1098 length=columns*sizeof(*indexes);
1099 p=cache_info->indexes+cache_info->columns*rows;
1100 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1101 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +00001102 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001103 {
1104 p-=cache_info->columns;
cristy8f036fe2010-09-18 02:02:00 +00001105 (void) memcpy(indexes,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00001106 offset-=clone_info->columns*sizeof(*indexes);
1107 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1108 (unsigned char *) indexes);
1109 if ((MagickSizeType) count != length)
1110 break;
1111 }
cristybb503372010-05-27 20:51:26 +00001112 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001113 {
1114 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1115 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1116 cache_info->cache_filename);
1117 return(MagickFalse);
1118 }
1119 if (clone_info->columns > cache_info->columns)
1120 {
1121 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
1122 (void) ResetMagickMemory(indexes,0,(size_t) length);
1123 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1124 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +00001125 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001126 {
1127 offset-=clone_info->columns*sizeof(*indexes);
1128 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
1129 length,(unsigned char *) indexes);
1130 if ((MagickSizeType) count != length)
1131 break;
1132 }
cristybb503372010-05-27 20:51:26 +00001133 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001134 {
1135 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1136 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1137 cache_info->cache_filename);
1138 return(MagickFalse);
1139 }
1140 }
1141 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1142 }
1143 /*
1144 Clone cache pixels.
1145 */
1146 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1147 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1148 if (pixels == (PixelPacket *) NULL)
1149 {
1150 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1151 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1152 return(MagickFalse);
1153 }
1154 (void) ResetMagickMemory(pixels,0,(size_t) length);
1155 length=columns*sizeof(*pixels);
1156 p=cache_info->pixels+cache_info->columns*rows;
1157 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +00001158 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001159 {
1160 p-=cache_info->columns;
cristy8f036fe2010-09-18 02:02:00 +00001161 (void) memcpy(pixels,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00001162 offset-=clone_info->columns*sizeof(*pixels);
1163 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1164 (unsigned char *) pixels);
1165 if ((MagickSizeType) count != length)
1166 break;
1167 }
cristybb503372010-05-27 20:51:26 +00001168 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001169 {
1170 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1171 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1172 cache_info->cache_filename);
1173 return(MagickFalse);
1174 }
1175 if (clone_info->columns > cache_info->columns)
1176 {
1177 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
1178 sizeof(*pixels);
1179 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1180 (void) ResetMagickMemory(pixels,0,(size_t) length);
cristybb503372010-05-27 20:51:26 +00001181 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001182 {
1183 offset-=clone_info->columns*sizeof(*pixels);
1184 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1185 (unsigned char *) pixels);
1186 if ((MagickSizeType) count != length)
1187 break;
1188 }
cristybb503372010-05-27 20:51:26 +00001189 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001190 {
1191 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1192 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1193 cache_info->cache_filename);
1194 return(MagickFalse);
1195 }
1196 }
1197 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1198 return(MagickTrue);
1199}
1200
1201static MagickBooleanType CloneMemoryToMemoryPixelCache(CacheInfo *clone_info,
1202 CacheInfo *cache_info,ExceptionInfo *magick_unused(exception))
1203{
cristy3ed852e2009-09-05 21:47:34 +00001204 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001205 *restrict pixels,
1206 *restrict source_pixels;
cristy3ed852e2009-09-05 21:47:34 +00001207
cristye076a6e2010-08-15 19:59:43 +00001208 register ssize_t
1209 y;
cristy3ed852e2009-09-05 21:47:34 +00001210
cristybb503372010-05-27 20:51:26 +00001211 size_t
cristy3ed852e2009-09-05 21:47:34 +00001212 columns,
cristye076a6e2010-08-15 19:59:43 +00001213 length,
cristy3ed852e2009-09-05 21:47:34 +00001214 rows;
1215
1216 if (cache_info->debug != MagickFalse)
1217 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
cristybb503372010-05-27 20:51:26 +00001218 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1219 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001220 if ((clone_info->active_index_channel != MagickFalse) &&
1221 (cache_info->active_index_channel != MagickFalse))
1222 {
1223 register IndexPacket
1224 *indexes,
1225 *source_indexes;
1226
1227 /*
1228 Clone cache indexes.
1229 */
1230 length=columns*sizeof(*indexes);
1231 if (clone_info->columns == cache_info->columns)
cristy8f036fe2010-09-18 02:02:00 +00001232 (void) memcpy(clone_info->indexes,cache_info->indexes,length*rows);
cristy3ed852e2009-09-05 21:47:34 +00001233 else
1234 {
1235 source_indexes=cache_info->indexes+cache_info->columns*rows;
1236 indexes=clone_info->indexes+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001237 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001238 {
1239 source_indexes-=cache_info->columns;
1240 indexes-=clone_info->columns;
cristy8f036fe2010-09-18 02:02:00 +00001241 (void) memcpy(indexes,source_indexes,length);
cristy3ed852e2009-09-05 21:47:34 +00001242 }
1243 if (clone_info->columns > cache_info->columns)
1244 {
1245 length=(clone_info->columns-cache_info->columns)*
1246 sizeof(*indexes);
1247 indexes=clone_info->indexes+clone_info->columns*rows+
1248 cache_info->columns;
cristybb503372010-05-27 20:51:26 +00001249 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001250 {
1251 indexes-=clone_info->columns;
1252 (void) ResetMagickMemory(indexes,0,length);
1253 }
1254 }
1255 }
1256 }
1257 /*
1258 Clone cache pixels.
1259 */
1260 length=columns*sizeof(*pixels);
1261 if (clone_info->columns == cache_info->columns)
cristy8f036fe2010-09-18 02:02:00 +00001262 (void) memcpy(clone_info->pixels,cache_info->pixels,length*rows);
cristy3ed852e2009-09-05 21:47:34 +00001263 else
1264 {
1265 source_pixels=cache_info->pixels+cache_info->columns*rows;
1266 pixels=clone_info->pixels+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001267 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001268 {
1269 source_pixels-=cache_info->columns;
1270 pixels-=clone_info->columns;
cristy8f036fe2010-09-18 02:02:00 +00001271 (void) memcpy(pixels,source_pixels,length);
cristy3ed852e2009-09-05 21:47:34 +00001272 }
1273 if (clone_info->columns > cache_info->columns)
1274 {
1275 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1276 pixels=clone_info->pixels+clone_info->columns*rows+
1277 cache_info->columns;
cristybb503372010-05-27 20:51:26 +00001278 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001279 {
1280 pixels-=clone_info->columns;
1281 (void) ResetMagickMemory(pixels,0,length);
1282 }
1283 }
1284 }
1285 return(MagickTrue);
1286}
1287
1288static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1289 CacheInfo *cache_info,ExceptionInfo *exception)
1290{
1291 if ((clone_info->type != DiskCache) && (cache_info->type != DiskCache))
1292 return(CloneMemoryToMemoryPixelCache(clone_info,cache_info,exception));
1293 if ((clone_info->type == DiskCache) && (cache_info->type == DiskCache))
1294 return(CloneDiskToDiskPixelCache(clone_info,cache_info,exception));
1295 if (cache_info->type == DiskCache)
1296 return(CloneDiskToMemoryPixelCache(clone_info,cache_info,exception));
1297 return(CloneMemoryToDiskPixelCache(clone_info,cache_info,exception));
1298}
1299
1300/*
1301%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1302% %
1303% %
1304% %
1305+ C l o n e P i x e l C a c h e M e t h o d s %
1306% %
1307% %
1308% %
1309%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1310%
1311% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1312% another.
1313%
1314% The format of the ClonePixelCacheMethods() method is:
1315%
1316% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1317%
1318% A description of each parameter follows:
1319%
1320% o clone: Specifies a pointer to a Cache structure.
1321%
1322% o cache: the pixel cache.
1323%
1324*/
1325MagickExport void ClonePixelCacheMethods(Cache clone,const Cache cache)
1326{
1327 CacheInfo
1328 *cache_info,
1329 *source_info;
1330
1331 assert(clone != (Cache) NULL);
1332 source_info=(CacheInfo *) clone;
1333 assert(source_info->signature == MagickSignature);
1334 if (source_info->debug != MagickFalse)
1335 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1336 source_info->filename);
1337 assert(cache != (Cache) NULL);
1338 cache_info=(CacheInfo *) cache;
1339 assert(cache_info->signature == MagickSignature);
1340 source_info->methods=cache_info->methods;
1341}
1342
1343/*
1344%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1345% %
1346% %
1347% %
1348+ D e s t r o y I m a g e P i x e l C a c h e %
1349% %
1350% %
1351% %
1352%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1353%
1354% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1355%
1356% The format of the DestroyImagePixelCache() method is:
1357%
1358% void DestroyImagePixelCache(Image *image)
1359%
1360% A description of each parameter follows:
1361%
1362% o image: the image.
1363%
1364*/
1365static void DestroyImagePixelCache(Image *image)
1366{
1367 assert(image != (Image *) NULL);
1368 assert(image->signature == MagickSignature);
1369 if (image->debug != MagickFalse)
1370 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1371 if (image->cache == (void *) NULL)
1372 return;
1373 image->cache=DestroyPixelCache(image->cache);
1374}
1375
1376/*
1377%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1378% %
1379% %
1380% %
1381+ D e s t r o y I m a g e P i x e l s %
1382% %
1383% %
1384% %
1385%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1386%
1387% DestroyImagePixels() deallocates memory associated with the pixel cache.
1388%
1389% The format of the DestroyImagePixels() method is:
1390%
1391% void DestroyImagePixels(Image *image)
1392%
1393% A description of each parameter follows:
1394%
1395% o image: the image.
1396%
1397*/
1398MagickExport void DestroyImagePixels(Image *image)
1399{
1400 CacheInfo
1401 *cache_info;
1402
1403 assert(image != (const Image *) NULL);
1404 assert(image->signature == MagickSignature);
1405 if (image->debug != MagickFalse)
1406 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1407 assert(image->cache != (Cache) NULL);
1408 cache_info=(CacheInfo *) image->cache;
1409 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001410 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1411 {
1412 cache_info->methods.destroy_pixel_handler(image);
1413 return;
1414 }
cristy2036f5c2010-09-19 21:18:17 +00001415 image->cache=DestroyPixelCache(image->cache);
cristy3ed852e2009-09-05 21:47:34 +00001416}
1417
1418/*
1419%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1420% %
1421% %
1422% %
1423+ D e s t r o y P i x e l C a c h e %
1424% %
1425% %
1426% %
1427%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1428%
1429% DestroyPixelCache() deallocates memory associated with the pixel cache.
1430%
1431% The format of the DestroyPixelCache() method is:
1432%
1433% Cache DestroyPixelCache(Cache cache)
1434%
1435% A description of each parameter follows:
1436%
1437% o cache: the pixel cache.
1438%
1439*/
1440
1441static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1442{
1443 switch (cache_info->type)
1444 {
1445 case MemoryCache:
1446 {
1447 if (cache_info->mapped == MagickFalse)
1448 cache_info->pixels=(PixelPacket *) RelinquishMagickMemory(
1449 cache_info->pixels);
1450 else
1451 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,
1452 (size_t) cache_info->length);
1453 RelinquishMagickResource(MemoryResource,cache_info->length);
1454 break;
1455 }
1456 case MapCache:
1457 {
1458 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,(size_t)
1459 cache_info->length);
1460 RelinquishMagickResource(MapResource,cache_info->length);
1461 }
1462 case DiskCache:
1463 {
1464 if (cache_info->file != -1)
1465 (void) ClosePixelCacheOnDisk(cache_info);
1466 RelinquishMagickResource(DiskResource,cache_info->length);
1467 break;
1468 }
1469 default:
1470 break;
1471 }
1472 cache_info->type=UndefinedCache;
1473 cache_info->mapped=MagickFalse;
1474 cache_info->indexes=(IndexPacket *) NULL;
1475}
1476
1477MagickExport Cache DestroyPixelCache(Cache cache)
1478{
1479 CacheInfo
1480 *cache_info;
1481
cristy3ed852e2009-09-05 21:47:34 +00001482 assert(cache != (Cache) NULL);
1483 cache_info=(CacheInfo *) cache;
1484 assert(cache_info->signature == MagickSignature);
1485 if (cache_info->debug != MagickFalse)
1486 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1487 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001488 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001489 cache_info->reference_count--;
1490 if (cache_info->reference_count != 0)
1491 {
cristyf84a1932010-01-03 18:00:18 +00001492 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001493 return((Cache) NULL);
1494 }
cristyf84a1932010-01-03 18:00:18 +00001495 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001496 if (cache_resources != (SplayTreeInfo *) NULL)
1497 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
cristy5b8de732009-09-10 23:50:40 +00001498 if (cache_info->debug != MagickFalse)
1499 {
1500 char
1501 message[MaxTextExtent];
1502
1503 (void) FormatMagickString(message,MaxTextExtent,"destroy %s",
1504 cache_info->filename);
1505 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1506 }
cristyc2e1bdd2009-09-10 23:43:34 +00001507 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1508 (cache_info->type != DiskCache)))
1509 RelinquishPixelCachePixels(cache_info);
1510 else
1511 {
1512 RelinquishPixelCachePixels(cache_info);
1513 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1514 }
cristy3ed852e2009-09-05 21:47:34 +00001515 *cache_info->cache_filename='\0';
1516 if (cache_info->nexus_info != (NexusInfo **) NULL)
1517 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1518 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001519 if (cache_info->random_info != (RandomInfo *) NULL)
1520 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001521 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1522 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1523 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1524 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001525 cache_info->signature=(~MagickSignature);
cristyb41ee102010-10-04 16:46:15 +00001526 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001527 cache=(Cache) NULL;
1528 return(cache);
1529}
1530
1531/*
1532%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1533% %
1534% %
1535% %
1536+ D e s t r o y P i x e l C a c h e N e x u s %
1537% %
1538% %
1539% %
1540%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1541%
1542% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1543%
1544% The format of the DestroyPixelCacheNexus() method is:
1545%
1546% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001547% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001548%
1549% A description of each parameter follows:
1550%
1551% o nexus_info: the nexus to destroy.
1552%
1553% o number_threads: the number of nexus threads.
1554%
1555*/
1556
1557static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1558{
1559 if (nexus_info->mapped == MagickFalse)
1560 (void) RelinquishMagickMemory(nexus_info->cache);
1561 else
1562 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1563 nexus_info->cache=(PixelPacket *) NULL;
1564 nexus_info->pixels=(PixelPacket *) NULL;
1565 nexus_info->indexes=(IndexPacket *) NULL;
1566 nexus_info->length=0;
1567 nexus_info->mapped=MagickFalse;
1568}
1569
1570MagickExport NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001571 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001572{
cristybb503372010-05-27 20:51:26 +00001573 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001574 i;
1575
1576 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001577 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001578 {
1579 if (nexus_info[i]->cache != (PixelPacket *) NULL)
1580 RelinquishCacheNexusPixels(nexus_info[i]);
1581 nexus_info[i]->signature=(~MagickSignature);
1582 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
1583 }
cristyb41ee102010-10-04 16:46:15 +00001584 nexus_info=(NexusInfo **) RelinquishMagickMemory(nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00001585 return(nexus_info);
1586}
1587
1588/*
1589%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1590% %
1591% %
1592% %
cristy3ed852e2009-09-05 21:47:34 +00001593+ G e t A u t h e n t i c I n d e x e s F r o m C a c h e %
1594% %
1595% %
1596% %
1597%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1598%
1599% GetAuthenticIndexesFromCache() returns the indexes associated with the last
1600% call to QueueAuthenticPixelsCache() or GetAuthenticPixelsCache().
1601%
1602% The format of the GetAuthenticIndexesFromCache() method is:
1603%
1604% IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1605%
1606% A description of each parameter follows:
1607%
1608% o image: the image.
1609%
1610*/
1611static IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1612{
1613 CacheInfo
1614 *cache_info;
1615
cristy5c9e6f22010-09-17 17:31:01 +00001616 const int
1617 id = GetOpenMPThreadId();
1618
cristye7cc7cf2010-09-21 13:26:47 +00001619 assert(image != (const Image *) NULL);
1620 assert(image->signature == MagickSignature);
1621 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001622 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001623 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001624 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001625 return(GetPixelCacheNexusIndexes(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001626}
1627
1628/*
1629%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1630% %
1631% %
1632% %
1633% G e t A u t h e n t i c I n d e x Q u e u e %
1634% %
1635% %
1636% %
1637%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1638%
1639% GetAuthenticIndexQueue() returns the authentic black channel or the colormap
1640% indexes associated with the last call to QueueAuthenticPixels() or
1641% GetVirtualPixels(). NULL is returned if the black channel or colormap
1642% indexes are not available.
1643%
1644% The format of the GetAuthenticIndexQueue() method is:
1645%
1646% IndexPacket *GetAuthenticIndexQueue(const Image *image)
1647%
1648% A description of each parameter follows:
1649%
1650% o image: the image.
1651%
1652*/
1653MagickExport IndexPacket *GetAuthenticIndexQueue(const Image *image)
1654{
1655 CacheInfo
1656 *cache_info;
1657
cristy2036f5c2010-09-19 21:18:17 +00001658 const int
1659 id = GetOpenMPThreadId();
1660
cristy3ed852e2009-09-05 21:47:34 +00001661 assert(image != (const Image *) NULL);
1662 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001663 assert(image->cache != (Cache) NULL);
1664 cache_info=(CacheInfo *) image->cache;
1665 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001666 if (cache_info->methods.get_authentic_indexes_from_handler !=
cristy3ed852e2009-09-05 21:47:34 +00001667 (GetAuthenticIndexesFromHandler) NULL)
cristyd317f372010-09-18 01:42:20 +00001668 return(cache_info->methods.get_authentic_indexes_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001669 assert(id < (int) cache_info->number_threads);
1670 return(GetPixelCacheNexusIndexes(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001671}
1672
1673/*
1674%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1675% %
1676% %
1677% %
1678+ G e t A u t h e n t i c P i x e l C a c h e N e x u s %
1679% %
1680% %
1681% %
1682%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1683%
1684% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1685% disk pixel cache as defined by the geometry parameters. A pointer to the
1686% pixels is returned if the pixels are transferred, otherwise a NULL is
1687% returned.
1688%
1689% The format of the GetAuthenticPixelCacheNexus() method is:
1690%
cristybb503372010-05-27 20:51:26 +00001691% PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1692% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001693% NexusInfo *nexus_info,ExceptionInfo *exception)
1694%
1695% A description of each parameter follows:
1696%
1697% o image: the image.
1698%
1699% o x,y,columns,rows: These values define the perimeter of a region of
1700% pixels.
1701%
1702% o nexus_info: the cache nexus to return.
1703%
1704% o exception: return any errors or warnings in this structure.
1705%
1706*/
1707
1708static inline MagickBooleanType IsNexusInCore(const CacheInfo *cache_info,
1709 NexusInfo *nexus_info)
1710{
1711 MagickOffsetType
1712 offset;
1713
cristy73724512010-04-12 14:43:14 +00001714 if (cache_info->type == PingCache)
1715 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001716 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1717 nexus_info->region.x;
cristy096bf2c2010-09-22 11:55:02 +00001718 return(nexus_info->pixels == (cache_info->pixels+offset) ? MagickTrue :
1719 MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +00001720}
1721
cristye076a6e2010-08-15 19:59:43 +00001722MagickExport PixelPacket *GetAuthenticPixelCacheNexus(Image *image,
1723 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001724 NexusInfo *nexus_info,ExceptionInfo *exception)
1725{
1726 CacheInfo
1727 *cache_info;
1728
1729 PixelPacket
1730 *pixels;
1731
1732 /*
1733 Transfer pixels from the cache.
1734 */
1735 assert(image != (Image *) NULL);
1736 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001737 pixels=QueueAuthenticNexus(image,x,y,columns,rows,nexus_info,exception);
1738 if (pixels == (PixelPacket *) NULL)
1739 return((PixelPacket *) NULL);
1740 cache_info=(CacheInfo *) image->cache;
1741 assert(cache_info->signature == MagickSignature);
1742 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
1743 return(pixels);
1744 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1745 return((PixelPacket *) NULL);
1746 if (cache_info->active_index_channel != MagickFalse)
1747 if (ReadPixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse)
1748 return((PixelPacket *) NULL);
1749 return(pixels);
1750}
1751
1752/*
1753%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1754% %
1755% %
1756% %
1757+ G e t A u t h e n t i c P i x e l s F r o m C a c h e %
1758% %
1759% %
1760% %
1761%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1762%
1763% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1764% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1765%
1766% The format of the GetAuthenticPixelsFromCache() method is:
1767%
1768% PixelPacket *GetAuthenticPixelsFromCache(const Image image)
1769%
1770% A description of each parameter follows:
1771%
1772% o image: the image.
1773%
1774*/
1775static PixelPacket *GetAuthenticPixelsFromCache(const Image *image)
1776{
1777 CacheInfo
1778 *cache_info;
1779
cristy5c9e6f22010-09-17 17:31:01 +00001780 const int
1781 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001782
cristye7cc7cf2010-09-21 13:26:47 +00001783 assert(image != (const Image *) NULL);
1784 assert(image->signature == MagickSignature);
1785 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001786 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001787 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001788 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001789 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001790}
1791
1792/*
1793%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1794% %
1795% %
1796% %
1797% G e t A u t h e n t i c P i x e l Q u e u e %
1798% %
1799% %
1800% %
1801%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1802%
1803% GetAuthenticPixelQueue() returns the authentic pixels associated with the
1804% last call to QueueAuthenticPixels() or GetAuthenticPixels().
1805%
1806% The format of the GetAuthenticPixelQueue() method is:
1807%
1808% PixelPacket *GetAuthenticPixelQueue(const Image image)
1809%
1810% A description of each parameter follows:
1811%
1812% o image: the image.
1813%
1814*/
1815MagickExport PixelPacket *GetAuthenticPixelQueue(const Image *image)
1816{
1817 CacheInfo
1818 *cache_info;
1819
cristy2036f5c2010-09-19 21:18:17 +00001820 const int
1821 id = GetOpenMPThreadId();
1822
cristy3ed852e2009-09-05 21:47:34 +00001823 assert(image != (const Image *) NULL);
1824 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001825 assert(image->cache != (Cache) NULL);
1826 cache_info=(CacheInfo *) image->cache;
1827 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001828 if (cache_info->methods.get_authentic_pixels_from_handler !=
1829 (GetAuthenticPixelsFromHandler) NULL)
1830 return(cache_info->methods.get_authentic_pixels_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001831 assert(id < (int) cache_info->number_threads);
1832 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001833}
1834
1835/*
1836%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1837% %
1838% %
1839% %
1840% G e t A u t h e n t i c P i x e l s %
1841% %
1842% %
1843% %
1844%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1845%
1846% GetAuthenticPixels() obtains a pixel region for read/write access. If the
1847% region is successfully accessed, a pointer to a PixelPacket array
1848% representing the region is returned, otherwise NULL is returned.
1849%
1850% The returned pointer may point to a temporary working copy of the pixels
1851% or it may point to the original pixels in memory. Performance is maximized
1852% if the selected region is part of one row, or one or more full rows, since
1853% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001854% if the image is in memory, or in a memory-mapped file. The returned pointer
1855% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001856%
1857% Pixels accessed via the returned pointer represent a simple array of type
1858% PixelPacket. If the image type is CMYK or if the storage class is
1859% PseduoClass, call GetAuthenticIndexQueue() after invoking
1860% GetAuthenticPixels() to obtain the black color component or colormap indexes
1861% (of type IndexPacket) corresponding to the region. Once the PixelPacket
1862% (and/or IndexPacket) array has been updated, the changes must be saved back
1863% to the underlying image using SyncAuthenticPixels() or they may be lost.
1864%
1865% The format of the GetAuthenticPixels() method is:
1866%
cristy5f959472010-05-27 22:19:46 +00001867% PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1868% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001869% ExceptionInfo *exception)
1870%
1871% A description of each parameter follows:
1872%
1873% o image: the image.
1874%
1875% o x,y,columns,rows: These values define the perimeter of a region of
1876% pixels.
1877%
1878% o exception: return any errors or warnings in this structure.
1879%
1880*/
cristybb503372010-05-27 20:51:26 +00001881MagickExport PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1882 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001883 ExceptionInfo *exception)
1884{
1885 CacheInfo
1886 *cache_info;
1887
cristy2036f5c2010-09-19 21:18:17 +00001888 const int
1889 id = GetOpenMPThreadId();
1890
cristy3ed852e2009-09-05 21:47:34 +00001891 assert(image != (Image *) NULL);
1892 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001893 assert(image->cache != (Cache) NULL);
1894 cache_info=(CacheInfo *) image->cache;
1895 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001896 if (cache_info->methods.get_authentic_pixels_handler !=
1897 (GetAuthenticPixelsHandler) NULL)
1898 return(cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1899 rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00001900 assert(id < (int) cache_info->number_threads);
1901 return(GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1902 cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00001903}
1904
1905/*
1906%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1907% %
1908% %
1909% %
1910+ G e t A u t h e n t i c P i x e l s C a c h e %
1911% %
1912% %
1913% %
1914%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1915%
1916% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1917% as defined by the geometry parameters. A pointer to the pixels is returned
1918% if the pixels are transferred, otherwise a NULL is returned.
1919%
1920% The format of the GetAuthenticPixelsCache() method is:
1921%
cristybb503372010-05-27 20:51:26 +00001922% PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1923% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001924% ExceptionInfo *exception)
1925%
1926% A description of each parameter follows:
1927%
1928% o image: the image.
1929%
1930% o x,y,columns,rows: These values define the perimeter of a region of
1931% pixels.
1932%
1933% o exception: return any errors or warnings in this structure.
1934%
1935*/
cristybb503372010-05-27 20:51:26 +00001936static PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1937 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001938 ExceptionInfo *exception)
1939{
1940 CacheInfo
1941 *cache_info;
1942
cristy5c9e6f22010-09-17 17:31:01 +00001943 const int
1944 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001945
cristye7cc7cf2010-09-21 13:26:47 +00001946 assert(image != (const Image *) NULL);
1947 assert(image->signature == MagickSignature);
1948 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00001949 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001950 if (cache_info == (Cache) NULL)
1951 return((PixelPacket *) NULL);
cristye7cc7cf2010-09-21 13:26:47 +00001952 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001953 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001954 return(GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1955 cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00001956}
1957
1958/*
1959%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1960% %
1961% %
1962% %
1963+ G e t I m a g e E x t e n t %
1964% %
1965% %
1966% %
1967%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1968%
1969% GetImageExtent() returns the extent of the pixels associated with the
1970% last call to QueueAuthenticPixels() or GetAuthenticPixels().
1971%
1972% The format of the GetImageExtent() method is:
1973%
1974% MagickSizeType GetImageExtent(const Image *image)
1975%
1976% A description of each parameter follows:
1977%
1978% o image: the image.
1979%
1980*/
1981MagickExport MagickSizeType GetImageExtent(const Image *image)
1982{
1983 CacheInfo
1984 *cache_info;
1985
cristy5c9e6f22010-09-17 17:31:01 +00001986 const int
1987 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001988
cristy3ed852e2009-09-05 21:47:34 +00001989 assert(image != (Image *) NULL);
1990 assert(image->signature == MagickSignature);
1991 if (image->debug != MagickFalse)
1992 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1993 assert(image->cache != (Cache) NULL);
1994 cache_info=(CacheInfo *) image->cache;
1995 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001996 assert(id < (int) cache_info->number_threads);
cristy2036f5c2010-09-19 21:18:17 +00001997 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001998}
1999
2000/*
2001%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2002% %
2003% %
2004% %
2005+ G e t I m a g e P i x e l C a c h e %
2006% %
2007% %
2008% %
2009%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2010%
2011% GetImagePixelCache() ensures that there is only a single reference to the
2012% pixel cache to be modified, updating the provided cache pointer to point to
2013% a clone of the original pixel cache if necessary.
2014%
2015% The format of the GetImagePixelCache method is:
2016%
2017% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2018% ExceptionInfo *exception)
2019%
2020% A description of each parameter follows:
2021%
2022% o image: the image.
2023%
2024% o clone: any value other than MagickFalse clones the cache pixels.
2025%
2026% o exception: return any errors or warnings in this structure.
2027%
2028*/
cristy3ed852e2009-09-05 21:47:34 +00002029static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
2030{
2031 CacheInfo
2032 *cache_info;
2033
2034 /*
2035 Does the image match the pixel cache morphology?
2036 */
2037 cache_info=(CacheInfo *) image->cache;
2038 if ((image->storage_class != cache_info->storage_class) ||
2039 (image->colorspace != cache_info->colorspace) ||
2040 (image->columns != cache_info->columns) ||
2041 (image->rows != cache_info->rows) ||
2042 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2043 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2044 return(MagickFalse);
2045 return(MagickTrue);
2046}
2047
cristy77ff0282010-09-13 00:51:10 +00002048static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2049 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002050{
2051 CacheInfo
2052 *cache_info;
2053
cristy3ed852e2009-09-05 21:47:34 +00002054 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00002055 destroy,
cristy3ed852e2009-09-05 21:47:34 +00002056 status;
2057
cristy50a10922010-02-15 18:35:25 +00002058 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00002059 cpu_throttle = 0,
2060 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00002061 time_limit = 0;
2062
cristy1ea34962010-07-01 19:49:21 +00002063 static time_t
cristya21afde2010-07-02 00:45:40 +00002064 cache_genesis = 0;
cristy1ea34962010-07-01 19:49:21 +00002065
cristyc4f9f132010-03-04 18:50:01 +00002066 status=MagickTrue;
2067 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00002068 if (cpu_throttle == 0)
2069 {
2070 char
2071 *limit;
2072
2073 /*
2074 Set CPU throttle in milleseconds.
2075 */
2076 cpu_throttle=MagickResourceInfinity;
2077 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2078 if (limit == (char *) NULL)
2079 limit=GetPolicyValue("throttle");
2080 if (limit != (char *) NULL)
2081 {
2082 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2083 limit=DestroyString(limit);
2084 }
2085 }
2086 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2087 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00002088 if (time_limit == 0)
2089 {
cristy6ebe97c2010-07-03 01:17:28 +00002090 /*
2091 Set the exire time in seconds.
2092 */
cristy1ea34962010-07-01 19:49:21 +00002093 time_limit=GetMagickResourceLimit(TimeResource);
cristya21afde2010-07-02 00:45:40 +00002094 cache_genesis=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00002095 }
2096 if ((time_limit != MagickResourceInfinity) &&
cristya21afde2010-07-02 00:45:40 +00002097 ((MagickSizeType) (time((time_t *) NULL)-cache_genesis) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00002098 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00002099 assert(image->cache != (Cache) NULL);
2100 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002101 destroy=MagickFalse;
cristy01b7eb02009-09-10 23:10:14 +00002102 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002103 {
cristyaaa0cb62010-02-15 17:47:27 +00002104 LockSemaphoreInfo(cache_info->semaphore);
2105 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002106 {
cristyaaa0cb62010-02-15 17:47:27 +00002107 Image
2108 clone_image;
2109
2110 CacheInfo
2111 *clone_info;
2112
2113 /*
2114 Clone pixel cache.
2115 */
2116 clone_image=(*image);
cristy93505cf2010-08-10 21:37:49 +00002117 clone_image.semaphore=AllocateSemaphoreInfo();
2118 clone_image.reference_count=1;
cristyaaa0cb62010-02-15 17:47:27 +00002119 clone_image.cache=ClonePixelCache(cache_info);
2120 clone_info=(CacheInfo *) clone_image.cache;
cristyabd6e372010-09-15 19:11:26 +00002121 status=OpenPixelCache(&clone_image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00002122 if (status != MagickFalse)
2123 {
cristyabd6e372010-09-15 19:11:26 +00002124 if (clone != MagickFalse)
2125 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00002126 if (status != MagickFalse)
2127 {
cristyabd6e372010-09-15 19:11:26 +00002128 destroy=MagickTrue;
2129 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00002130 }
2131 }
cristy93505cf2010-08-10 21:37:49 +00002132 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002133 }
cristyaaa0cb62010-02-15 17:47:27 +00002134 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002135 }
cristy4320e0e2009-09-10 15:00:08 +00002136 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002137 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002138 if (status != MagickFalse)
2139 {
2140 /*
2141 Ensure the image matches the pixel cache morphology.
2142 */
2143 image->taint=MagickTrue;
2144 image->type=UndefinedType;
cristydd438462010-05-06 13:44:04 +00002145 if (image->colorspace == GRAYColorspace)
2146 image->colorspace=RGBColorspace;
cristy3ed852e2009-09-05 21:47:34 +00002147 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2148 status=OpenPixelCache(image,IOMode,exception);
2149 }
cristyf84a1932010-01-03 18:00:18 +00002150 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002151 if (status == MagickFalse)
2152 return((Cache) NULL);
2153 return(image->cache);
2154}
2155
2156/*
2157%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2158% %
2159% %
2160% %
2161% G e t O n e A u t h e n t i c P i x e l %
2162% %
2163% %
2164% %
2165%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2166%
2167% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2168% location. The image background color is returned if an error occurs.
2169%
2170% The format of the GetOneAuthenticPixel() method is:
2171%
cristybb503372010-05-27 20:51:26 +00002172% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2173% const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002174%
2175% A description of each parameter follows:
2176%
2177% o image: the image.
2178%
2179% o x,y: These values define the location of the pixel to return.
2180%
2181% o pixel: return a pixel at the specified (x,y) location.
2182%
2183% o exception: return any errors or warnings in this structure.
2184%
2185*/
cristyacbbb7c2010-06-30 18:56:48 +00002186MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2187 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002188{
2189 CacheInfo
2190 *cache_info;
2191
cristy2036f5c2010-09-19 21:18:17 +00002192 PixelPacket
2193 *pixels;
2194
cristy3ed852e2009-09-05 21:47:34 +00002195 assert(image != (Image *) NULL);
2196 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002197 assert(image->cache != (Cache) NULL);
2198 cache_info=(CacheInfo *) image->cache;
2199 assert(cache_info->signature == MagickSignature);
2200 *pixel=image->background_color;
cristyd317f372010-09-18 01:42:20 +00002201 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2202 (GetOneAuthenticPixelFromHandler) NULL)
2203 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2204 pixel,exception));
cristy2036f5c2010-09-19 21:18:17 +00002205 *pixel=image->background_color;
2206 pixels=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2207 if (pixels == (PixelPacket *) NULL)
2208 return(MagickFalse);
2209 *pixel=(*pixels);
2210 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002211}
2212
2213/*
2214%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2215% %
2216% %
2217% %
2218+ 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 %
2219% %
2220% %
2221% %
2222%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2223%
2224% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2225% location. The image background color is returned if an error occurs.
2226%
2227% The format of the GetOneAuthenticPixelFromCache() method is:
2228%
2229% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy5f959472010-05-27 22:19:46 +00002230% const ssize_t x,const ssize_t y,PixelPacket *pixel,
2231% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002232%
2233% A description of each parameter follows:
2234%
2235% o image: the image.
2236%
2237% o x,y: These values define the location of the pixel to return.
2238%
2239% o pixel: return a pixel at the specified (x,y) location.
2240%
2241% o exception: return any errors or warnings in this structure.
2242%
2243*/
2244static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristybb503372010-05-27 20:51:26 +00002245 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002246{
cristy098f78c2010-09-23 17:28:44 +00002247 CacheInfo
2248 *cache_info;
2249
2250 const int
2251 id = GetOpenMPThreadId();
2252
cristy3ed852e2009-09-05 21:47:34 +00002253 PixelPacket
2254 *pixels;
2255
cristy0158a4b2010-09-20 13:59:45 +00002256 assert(image != (const Image *) NULL);
2257 assert(image->signature == MagickSignature);
2258 assert(image->cache != (Cache) NULL);
cristy098f78c2010-09-23 17:28:44 +00002259 cache_info=(CacheInfo *) image->cache;
2260 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002261 *pixel=image->background_color;
cristy098f78c2010-09-23 17:28:44 +00002262 assert(id < (int) cache_info->number_threads);
2263 pixels=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,
2264 cache_info->nexus_info[id],exception);
cristy3ed852e2009-09-05 21:47:34 +00002265 if (pixels == (PixelPacket *) NULL)
2266 return(MagickFalse);
2267 *pixel=(*pixels);
2268 return(MagickTrue);
2269}
2270
2271/*
2272%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2273% %
2274% %
2275% %
2276% G e t O n e V i r t u a l M a g i c k P i x e l %
2277% %
2278% %
2279% %
2280%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2281%
2282% GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2283% location. The image background color is returned if an error occurs. If
2284% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2285%
2286% The format of the GetOneVirtualMagickPixel() method is:
2287%
2288% MagickBooleanType GetOneVirtualMagickPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002289% const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
cristy3ed852e2009-09-05 21:47:34 +00002290% ExceptionInfo exception)
2291%
2292% A description of each parameter follows:
2293%
2294% o image: the image.
2295%
2296% o x,y: these values define the location of the pixel to return.
2297%
2298% o pixel: return a pixel at the specified (x,y) location.
2299%
2300% o exception: return any errors or warnings in this structure.
2301%
2302*/
2303MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
cristyacbbb7c2010-06-30 18:56:48 +00002304 const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
2305 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002306{
2307 CacheInfo
2308 *cache_info;
2309
cristy0158a4b2010-09-20 13:59:45 +00002310 const int
2311 id = GetOpenMPThreadId();
2312
cristy3ed852e2009-09-05 21:47:34 +00002313 register const IndexPacket
2314 *indexes;
2315
2316 register const PixelPacket
cristy0158a4b2010-09-20 13:59:45 +00002317 *pixels;
cristy3ed852e2009-09-05 21:47:34 +00002318
2319 assert(image != (const Image *) NULL);
2320 assert(image->signature == MagickSignature);
2321 assert(image->cache != (Cache) NULL);
2322 cache_info=(CacheInfo *) image->cache;
2323 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002324 assert(id < (int) cache_info->number_threads);
2325 pixels=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2326 1UL,1UL,cache_info->nexus_info[id],exception);
cristye7cc7cf2010-09-21 13:26:47 +00002327 GetMagickPixelPacket(image,pixel);
cristy0158a4b2010-09-20 13:59:45 +00002328 if (pixels == (const PixelPacket *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002329 return(MagickFalse);
cristy098f78c2010-09-23 17:28:44 +00002330 indexes=GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[id]);
cristy0158a4b2010-09-20 13:59:45 +00002331 SetMagickPixelPacket(image,pixels,indexes,pixel);
cristy3ed852e2009-09-05 21:47:34 +00002332 return(MagickTrue);
2333}
2334
2335/*
2336%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2337% %
2338% %
2339% %
2340% G e t O n e V i r t u a l M e t h o d P i x e l %
2341% %
2342% %
2343% %
2344%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2345%
2346% GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2347% location as defined by specified pixel method. The image background color
2348% is returned if an error occurs. If you plan to modify the pixel, use
2349% GetOneAuthenticPixel() instead.
2350%
2351% The format of the GetOneVirtualMethodPixel() method is:
2352%
2353% MagickBooleanType GetOneVirtualMethodPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002354% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2355% const ssize_t y,Pixelpacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002356%
2357% A description of each parameter follows:
2358%
2359% o image: the image.
2360%
2361% o virtual_pixel_method: the virtual pixel method.
2362%
2363% o x,y: These values define the location of the pixel to return.
2364%
2365% o pixel: return a pixel at the specified (x,y) location.
2366%
2367% o exception: return any errors or warnings in this structure.
2368%
2369*/
2370MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002371 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002372 PixelPacket *pixel,ExceptionInfo *exception)
2373{
cristy3ed852e2009-09-05 21:47:34 +00002374 CacheInfo
2375 *cache_info;
2376
cristy0158a4b2010-09-20 13:59:45 +00002377 const int
2378 id = GetOpenMPThreadId();
2379
cristy2036f5c2010-09-19 21:18:17 +00002380 const PixelPacket
2381 *pixels;
2382
cristy3ed852e2009-09-05 21:47:34 +00002383 assert(image != (const Image *) NULL);
2384 assert(image->signature == MagickSignature);
2385 assert(image->cache != (Cache) NULL);
2386 cache_info=(CacheInfo *) image->cache;
2387 assert(cache_info->signature == MagickSignature);
2388 *pixel=image->background_color;
cristyd317f372010-09-18 01:42:20 +00002389 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2390 (GetOneVirtualPixelFromHandler) NULL)
2391 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2392 virtual_pixel_method,x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002393 assert(id < (int) cache_info->number_threads);
2394 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2395 cache_info->nexus_info[id],exception);
cristy2036f5c2010-09-19 21:18:17 +00002396 if (pixels == (const PixelPacket *) NULL)
2397 return(MagickFalse);
2398 *pixel=(*pixels);
2399 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002400}
2401
2402/*
2403%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2404% %
2405% %
2406% %
2407% G e t O n e V i r t u a l P i x e l %
2408% %
2409% %
2410% %
2411%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2412%
2413% GetOneVirtualPixel() returns a single virtual pixel at the specified
2414% (x,y) location. The image background color is returned if an error occurs.
2415% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2416%
2417% The format of the GetOneVirtualPixel() method is:
2418%
cristybb503372010-05-27 20:51:26 +00002419% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2420% const ssize_t y,PixelPacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002421%
2422% A description of each parameter follows:
2423%
2424% o image: the image.
2425%
2426% o x,y: These values define the location of the pixel to return.
2427%
2428% o pixel: return a pixel at the specified (x,y) location.
2429%
2430% o exception: return any errors or warnings in this structure.
2431%
2432*/
2433MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002434 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002435{
cristy3ed852e2009-09-05 21:47:34 +00002436 CacheInfo
2437 *cache_info;
2438
cristy0158a4b2010-09-20 13:59:45 +00002439 const int
2440 id = GetOpenMPThreadId();
2441
cristy2036f5c2010-09-19 21:18:17 +00002442 const PixelPacket
2443 *pixels;
2444
cristy3ed852e2009-09-05 21:47:34 +00002445 assert(image != (const Image *) NULL);
2446 assert(image->signature == MagickSignature);
2447 assert(image->cache != (Cache) NULL);
2448 cache_info=(CacheInfo *) image->cache;
2449 assert(cache_info->signature == MagickSignature);
2450 *pixel=image->background_color;
cristyd317f372010-09-18 01:42:20 +00002451 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2452 (GetOneVirtualPixelFromHandler) NULL)
2453 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2454 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002455 assert(id < (int) cache_info->number_threads);
2456 pixels=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2457 1UL,1UL,cache_info->nexus_info[id],exception);
cristy2036f5c2010-09-19 21:18:17 +00002458 if (pixels == (const PixelPacket *) NULL)
2459 return(MagickFalse);
2460 *pixel=(*pixels);
2461 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002462}
2463
2464/*
2465%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2466% %
2467% %
2468% %
2469+ 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 %
2470% %
2471% %
2472% %
2473%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2474%
2475% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2476% specified (x,y) location. The image background color is returned if an
2477% error occurs.
2478%
2479% The format of the GetOneVirtualPixelFromCache() method is:
2480%
2481% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristybb503372010-05-27 20:51:26 +00002482% const VirtualPixelPacket method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002483% PixelPacket *pixel,ExceptionInfo *exception)
2484%
2485% A description of each parameter follows:
2486%
2487% o image: the image.
2488%
2489% o virtual_pixel_method: the virtual pixel method.
2490%
2491% o x,y: These values define the location of the pixel to return.
2492%
2493% o pixel: return a pixel at the specified (x,y) location.
2494%
2495% o exception: return any errors or warnings in this structure.
2496%
2497*/
2498static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002499 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002500 PixelPacket *pixel,ExceptionInfo *exception)
2501{
cristy0158a4b2010-09-20 13:59:45 +00002502 CacheInfo
2503 *cache_info;
2504
2505 const int
2506 id = GetOpenMPThreadId();
2507
cristy3ed852e2009-09-05 21:47:34 +00002508 const PixelPacket
2509 *pixels;
2510
cristye7cc7cf2010-09-21 13:26:47 +00002511 assert(image != (const Image *) NULL);
2512 assert(image->signature == MagickSignature);
2513 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002514 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002515 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002516 assert(id < (int) cache_info->number_threads);
cristye7cc7cf2010-09-21 13:26:47 +00002517 *pixel=image->background_color;
cristy0158a4b2010-09-20 13:59:45 +00002518 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2519 cache_info->nexus_info[id],exception);
cristy3ed852e2009-09-05 21:47:34 +00002520 if (pixels == (const PixelPacket *) NULL)
2521 return(MagickFalse);
2522 *pixel=(*pixels);
2523 return(MagickTrue);
2524}
2525
2526/*
2527%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2528% %
2529% %
2530% %
2531+ G e t P i x e l C a c h e C o l o r s p a c e %
2532% %
2533% %
2534% %
2535%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2536%
2537% GetPixelCacheColorspace() returns the class type of the pixel cache.
2538%
2539% The format of the GetPixelCacheColorspace() method is:
2540%
2541% Colorspace GetPixelCacheColorspace(Cache cache)
2542%
2543% A description of each parameter follows:
2544%
2545% o cache: the pixel cache.
2546%
2547*/
2548MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
2549{
2550 CacheInfo
2551 *cache_info;
2552
2553 assert(cache != (Cache) NULL);
2554 cache_info=(CacheInfo *) cache;
2555 assert(cache_info->signature == MagickSignature);
2556 if (cache_info->debug != MagickFalse)
2557 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2558 cache_info->filename);
2559 return(cache_info->colorspace);
2560}
2561
2562/*
2563%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2564% %
2565% %
2566% %
2567+ G e t P i x e l C a c h e M e t h o d s %
2568% %
2569% %
2570% %
2571%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2572%
2573% GetPixelCacheMethods() initializes the CacheMethods structure.
2574%
2575% The format of the GetPixelCacheMethods() method is:
2576%
2577% void GetPixelCacheMethods(CacheMethods *cache_methods)
2578%
2579% A description of each parameter follows:
2580%
2581% o cache_methods: Specifies a pointer to a CacheMethods structure.
2582%
2583*/
2584MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
2585{
2586 assert(cache_methods != (CacheMethods *) NULL);
2587 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2588 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2589 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2590 cache_methods->get_virtual_indexes_from_handler=GetVirtualIndexesFromCache;
2591 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2592 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2593 cache_methods->get_authentic_indexes_from_handler=
2594 GetAuthenticIndexesFromCache;
2595 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2596 cache_methods->get_one_authentic_pixel_from_handler=
2597 GetOneAuthenticPixelFromCache;
2598 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2599 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2600 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2601}
2602
2603/*
2604%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2605% %
2606% %
2607% %
2608+ G e t P i x e l C a c h e N e x u s E x t e n t %
2609% %
2610% %
2611% %
2612%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2613%
2614% GetPixelCacheNexusExtent() returns the extent of the pixels associated with
2615% the last call to SetPixelCacheNexusPixels() or GetPixelCacheNexusPixels().
2616%
2617% The format of the GetPixelCacheNexusExtent() method is:
2618%
2619% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2620% NexusInfo *nexus_info)
2621%
2622% A description of each parameter follows:
2623%
2624% o nexus_info: the nexus info.
2625%
2626*/
2627MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2628 NexusInfo *nexus_info)
2629{
2630 CacheInfo
2631 *cache_info;
2632
2633 MagickSizeType
2634 extent;
2635
cristye7cc7cf2010-09-21 13:26:47 +00002636 assert(cache != (const Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002637 cache_info=(CacheInfo *) cache;
2638 assert(cache_info->signature == MagickSignature);
2639 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2640 if (extent == 0)
2641 return((MagickSizeType) cache_info->columns*cache_info->rows);
2642 return(extent);
2643}
2644
2645/*
2646%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2647% %
2648% %
2649% %
2650+ 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 %
2651% %
2652% %
2653% %
2654%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2655%
2656% GetPixelCacheNexusIndexes() returns the indexes associated with the
2657% specified cache nexus.
2658%
2659% The format of the GetPixelCacheNexusIndexes() method is:
2660%
2661% IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2662% NexusInfo *nexus_info)
2663%
2664% A description of each parameter follows:
2665%
2666% o cache: the pixel cache.
2667%
2668% o nexus_info: the cache nexus to return the colormap indexes.
2669%
2670*/
2671MagickExport IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2672 NexusInfo *nexus_info)
2673{
2674 CacheInfo
2675 *cache_info;
2676
cristye7cc7cf2010-09-21 13:26:47 +00002677 assert(cache != (const Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002678 cache_info=(CacheInfo *) cache;
2679 assert(cache_info->signature == MagickSignature);
2680 if (cache_info->storage_class == UndefinedClass)
2681 return((IndexPacket *) NULL);
2682 return(nexus_info->indexes);
2683}
2684
2685/*
2686%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2687% %
2688% %
2689% %
2690+ G e t P i x e l C a c h e N e x u s P i x e l s %
2691% %
2692% %
2693% %
2694%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2695%
2696% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2697% cache nexus.
2698%
2699% The format of the GetPixelCacheNexusPixels() method is:
2700%
2701% PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2702% NexusInfo *nexus_info)
2703%
2704% A description of each parameter follows:
2705%
2706% o cache: the pixel cache.
2707%
2708% o nexus_info: the cache nexus to return the pixels.
2709%
2710*/
2711MagickExport PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2712 NexusInfo *nexus_info)
2713{
2714 CacheInfo
2715 *cache_info;
2716
cristye7cc7cf2010-09-21 13:26:47 +00002717 assert(cache != (const Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002718 cache_info=(CacheInfo *) cache;
2719 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002720 if (cache_info->storage_class == UndefinedClass)
2721 return((PixelPacket *) NULL);
2722 return(nexus_info->pixels);
2723}
2724
2725/*
2726%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2727% %
2728% %
2729% %
cristy056ba772010-01-02 23:33:54 +00002730+ G e t P i x e l C a c h e P i x e l s %
2731% %
2732% %
2733% %
2734%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2735%
2736% GetPixelCachePixels() returns the pixels associated with the specified image.
2737%
2738% The format of the GetPixelCachePixels() method is:
2739%
cristyf84a1932010-01-03 18:00:18 +00002740% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2741% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002742%
2743% A description of each parameter follows:
2744%
2745% o image: the image.
2746%
2747% o length: the pixel cache length.
2748%
cristyf84a1932010-01-03 18:00:18 +00002749% o exception: return any errors or warnings in this structure.
2750%
cristy056ba772010-01-02 23:33:54 +00002751*/
cristyf84a1932010-01-03 18:00:18 +00002752MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2753 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002754{
2755 CacheInfo
2756 *cache_info;
2757
2758 assert(image != (const Image *) NULL);
2759 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002760 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00002761 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002762 assert(cache_info->signature == MagickSignature);
2763 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002764 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002765 return((void *) NULL);
2766 *length=cache_info->length;
2767 return((void *) cache_info->pixels);
2768}
2769
2770/*
2771%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2772% %
2773% %
2774% %
cristyb32b90a2009-09-07 21:45:48 +00002775+ 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 +00002776% %
2777% %
2778% %
2779%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2780%
2781% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2782%
2783% The format of the GetPixelCacheStorageClass() method is:
2784%
2785% ClassType GetPixelCacheStorageClass(Cache cache)
2786%
2787% A description of each parameter follows:
2788%
2789% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2790%
2791% o cache: the pixel cache.
2792%
2793*/
2794MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
2795{
2796 CacheInfo
2797 *cache_info;
2798
2799 assert(cache != (Cache) NULL);
2800 cache_info=(CacheInfo *) cache;
2801 assert(cache_info->signature == MagickSignature);
2802 if (cache_info->debug != MagickFalse)
2803 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2804 cache_info->filename);
2805 return(cache_info->storage_class);
2806}
2807
2808/*
2809%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2810% %
2811% %
2812% %
cristyb32b90a2009-09-07 21:45:48 +00002813+ G e t P i x e l C a c h e T i l e S i z e %
2814% %
2815% %
2816% %
2817%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2818%
2819% GetPixelCacheTileSize() returns the pixel cache tile size.
2820%
2821% The format of the GetPixelCacheTileSize() method is:
2822%
cristybb503372010-05-27 20:51:26 +00002823% void GetPixelCacheTileSize(const Image *image,size_t *width,
2824% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002825%
2826% A description of each parameter follows:
2827%
2828% o image: the image.
2829%
2830% o width: the optimize cache tile width in pixels.
2831%
2832% o height: the optimize cache tile height in pixels.
2833%
2834*/
cristybb503372010-05-27 20:51:26 +00002835MagickExport void GetPixelCacheTileSize(const Image *image,size_t *width,
2836 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002837{
cristyb32b90a2009-09-07 21:45:48 +00002838 assert(image != (Image *) NULL);
2839 assert(image->signature == MagickSignature);
2840 if (image->debug != MagickFalse)
2841 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristyb32b90a2009-09-07 21:45:48 +00002842 *width=2048UL/sizeof(PixelPacket);
2843 if (GetPixelCacheType(image) == DiskCache)
cristydaa97692009-09-13 02:10:35 +00002844 *width=8192UL/sizeof(PixelPacket);
cristyb32b90a2009-09-07 21:45:48 +00002845 *height=(*width);
2846}
2847
2848/*
2849%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2850% %
2851% %
2852% %
2853+ G e t P i x e l C a c h e T y p e %
2854% %
2855% %
2856% %
2857%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2858%
2859% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2860%
2861% The format of the GetPixelCacheType() method is:
2862%
2863% CacheType GetPixelCacheType(const Image *image)
2864%
2865% A description of each parameter follows:
2866%
2867% o image: the image.
2868%
2869*/
2870MagickExport CacheType GetPixelCacheType(const Image *image)
2871{
2872 CacheInfo
2873 *cache_info;
2874
2875 assert(image != (Image *) NULL);
2876 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002877 assert(image->cache != (Cache) NULL);
2878 cache_info=(CacheInfo *) image->cache;
2879 assert(cache_info->signature == MagickSignature);
2880 return(cache_info->type);
2881}
2882
2883/*
2884%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2885% %
2886% %
2887% %
cristy3ed852e2009-09-05 21:47:34 +00002888+ 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 %
2889% %
2890% %
2891% %
2892%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2893%
2894% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2895% pixel cache. A virtual pixel is any pixel access that is outside the
2896% boundaries of the image cache.
2897%
2898% The format of the GetPixelCacheVirtualMethod() method is:
2899%
2900% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2901%
2902% A description of each parameter follows:
2903%
2904% o image: the image.
2905%
2906*/
2907MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2908{
2909 CacheInfo
2910 *cache_info;
2911
2912 assert(image != (Image *) NULL);
2913 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002914 assert(image->cache != (Cache) NULL);
2915 cache_info=(CacheInfo *) image->cache;
2916 assert(cache_info->signature == MagickSignature);
2917 return(cache_info->virtual_pixel_method);
2918}
2919
2920/*
2921%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2922% %
2923% %
2924% %
2925+ 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 %
2926% %
2927% %
2928% %
2929%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2930%
2931% GetVirtualIndexesFromCache() returns the indexes associated with the last
2932% call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2933%
2934% The format of the GetVirtualIndexesFromCache() method is:
2935%
2936% IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2937%
2938% A description of each parameter follows:
2939%
2940% o image: the image.
2941%
2942*/
2943static const IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2944{
2945 CacheInfo
2946 *cache_info;
2947
cristy5c9e6f22010-09-17 17:31:01 +00002948 const int
2949 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002950
cristye7cc7cf2010-09-21 13:26:47 +00002951 assert(image != (const Image *) NULL);
2952 assert(image->signature == MagickSignature);
2953 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002954 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002955 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002956 assert(id < (int) cache_info->number_threads);
cristye7cc7cf2010-09-21 13:26:47 +00002957 return(GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00002958}
2959
2960/*
2961%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2962% %
2963% %
2964% %
2965+ 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 %
2966% %
2967% %
2968% %
2969%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2970%
2971% GetVirtualIndexesFromNexus() returns the indexes associated with the
2972% specified cache nexus.
2973%
2974% The format of the GetVirtualIndexesFromNexus() method is:
2975%
2976% const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2977% NexusInfo *nexus_info)
2978%
2979% A description of each parameter follows:
2980%
2981% o cache: the pixel cache.
2982%
2983% o nexus_info: the cache nexus to return the colormap indexes.
2984%
2985*/
2986MagickExport const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2987 NexusInfo *nexus_info)
2988{
2989 CacheInfo
2990 *cache_info;
2991
cristye7cc7cf2010-09-21 13:26:47 +00002992 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002993 cache_info=(CacheInfo *) cache;
2994 assert(cache_info->signature == MagickSignature);
2995 if (cache_info->storage_class == UndefinedClass)
2996 return((IndexPacket *) NULL);
2997 return(nexus_info->indexes);
2998}
2999
3000/*
3001%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3002% %
3003% %
3004% %
3005% G e t V i r t u a l I n d e x Q u e u e %
3006% %
3007% %
3008% %
3009%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3010%
3011% GetVirtualIndexQueue() returns the virtual black channel or the
3012% colormap indexes associated with the last call to QueueAuthenticPixels() or
3013% GetVirtualPixels(). NULL is returned if the black channel or colormap
3014% indexes are not available.
3015%
3016% The format of the GetVirtualIndexQueue() method is:
3017%
3018% const IndexPacket *GetVirtualIndexQueue(const Image *image)
3019%
3020% A description of each parameter follows:
3021%
3022% o image: the image.
3023%
3024*/
3025MagickExport const IndexPacket *GetVirtualIndexQueue(const Image *image)
3026{
3027 CacheInfo
3028 *cache_info;
3029
cristy2036f5c2010-09-19 21:18:17 +00003030 const int
3031 id = GetOpenMPThreadId();
3032
cristy3ed852e2009-09-05 21:47:34 +00003033 assert(image != (const Image *) NULL);
3034 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003035 assert(image->cache != (Cache) NULL);
3036 cache_info=(CacheInfo *) image->cache;
3037 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003038 if (cache_info->methods.get_virtual_indexes_from_handler !=
3039 (GetVirtualIndexesFromHandler) NULL)
3040 return(cache_info->methods.get_virtual_indexes_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003041 assert(id < (int) cache_info->number_threads);
3042 return(GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003043}
3044
3045/*
3046%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3047% %
3048% %
3049% %
3050+ 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 %
3051% %
3052% %
3053% %
3054%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3055%
3056% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3057% pixel cache as defined by the geometry parameters. A pointer to the pixels
3058% is returned if the pixels are transferred, otherwise a NULL is returned.
3059%
3060% The format of the GetVirtualPixelsFromNexus() method is:
3061%
3062% PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003063% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00003064% const size_t columns,const size_t rows,NexusInfo *nexus_info,
3065% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003066%
3067% A description of each parameter follows:
3068%
3069% o image: the image.
3070%
3071% o virtual_pixel_method: the virtual pixel method.
3072%
3073% o x,y,columns,rows: These values define the perimeter of a region of
3074% pixels.
3075%
3076% o nexus_info: the cache nexus to acquire.
3077%
3078% o exception: return any errors or warnings in this structure.
3079%
3080*/
3081
cristybb503372010-05-27 20:51:26 +00003082static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003083 DitherMatrix[64] =
3084 {
3085 0, 48, 12, 60, 3, 51, 15, 63,
3086 32, 16, 44, 28, 35, 19, 47, 31,
3087 8, 56, 4, 52, 11, 59, 7, 55,
3088 40, 24, 36, 20, 43, 27, 39, 23,
3089 2, 50, 14, 62, 1, 49, 13, 61,
3090 34, 18, 46, 30, 33, 17, 45, 29,
3091 10, 58, 6, 54, 9, 57, 5, 53,
3092 42, 26, 38, 22, 41, 25, 37, 21
3093 };
3094
cristybb503372010-05-27 20:51:26 +00003095static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003096{
cristybb503372010-05-27 20:51:26 +00003097 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003098 index;
3099
3100 index=x+DitherMatrix[x & 0x07]-32L;
3101 if (index < 0L)
3102 return(0L);
cristybb503372010-05-27 20:51:26 +00003103 if (index >= (ssize_t) columns)
3104 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00003105 return(index);
3106}
3107
cristybb503372010-05-27 20:51:26 +00003108static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003109{
cristybb503372010-05-27 20:51:26 +00003110 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003111 index;
3112
3113 index=y+DitherMatrix[y & 0x07]-32L;
3114 if (index < 0L)
3115 return(0L);
cristybb503372010-05-27 20:51:26 +00003116 if (index >= (ssize_t) rows)
3117 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00003118 return(index);
3119}
3120
cristybb503372010-05-27 20:51:26 +00003121static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003122{
3123 if (x < 0L)
3124 return(0L);
cristybb503372010-05-27 20:51:26 +00003125 if (x >= (ssize_t) columns)
3126 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003127 return(x);
3128}
3129
cristybb503372010-05-27 20:51:26 +00003130static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003131{
3132 if (y < 0L)
3133 return(0L);
cristybb503372010-05-27 20:51:26 +00003134 if (y >= (ssize_t) rows)
3135 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003136 return(y);
3137}
3138
cristybb503372010-05-27 20:51:26 +00003139static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003140{
cristybb503372010-05-27 20:51:26 +00003141 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003142}
3143
cristybb503372010-05-27 20:51:26 +00003144static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003145{
cristybb503372010-05-27 20:51:26 +00003146 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003147}
3148
3149/*
3150 VirtualPixelModulo() computes the remainder of dividing offset by extent. It
3151 returns not only the quotient (tile the offset falls in) but also the positive
3152 remainer within that tile such that 0 <= remainder < extent. This method is
3153 essentially a ldiv() using a floored modulo division rather than the normal
3154 default truncated modulo division.
3155*/
cristybb503372010-05-27 20:51:26 +00003156static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3157 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003158{
3159 MagickModulo
3160 modulo;
3161
cristybb503372010-05-27 20:51:26 +00003162 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003163 if (offset < 0L)
3164 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003165 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003166 return(modulo);
3167}
3168
3169MagickExport const PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003170 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3171 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003172 ExceptionInfo *exception)
3173{
3174 CacheInfo
3175 *cache_info;
3176
cristyc3ec0d42010-04-07 01:18:08 +00003177 IndexPacket
3178 virtual_index;
3179
cristy3ed852e2009-09-05 21:47:34 +00003180 MagickOffsetType
3181 offset;
3182
3183 MagickSizeType
3184 length,
3185 number_pixels;
3186
3187 NexusInfo
3188 **virtual_nexus;
3189
3190 PixelPacket
3191 *pixels,
3192 virtual_pixel;
3193
3194 RectangleInfo
3195 region;
3196
3197 register const IndexPacket
cristyc3ec0d42010-04-07 01:18:08 +00003198 *restrict virtual_indexes;
cristy3ed852e2009-09-05 21:47:34 +00003199
3200 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003201 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003202
3203 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003204 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003205
cristye076a6e2010-08-15 19:59:43 +00003206 register PixelPacket
3207 *restrict q;
3208
cristybb503372010-05-27 20:51:26 +00003209 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003210 u,
3211 v;
3212
cristy3ed852e2009-09-05 21:47:34 +00003213 /*
3214 Acquire pixels.
3215 */
cristye7cc7cf2010-09-21 13:26:47 +00003216 assert(image != (const Image *) NULL);
3217 assert(image->signature == MagickSignature);
3218 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003219 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003220 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003221 if (cache_info->type == UndefinedCache)
cristy3ed852e2009-09-05 21:47:34 +00003222 return((const PixelPacket *) NULL);
3223 region.x=x;
3224 region.y=y;
3225 region.width=columns;
3226 region.height=rows;
3227 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
3228 if (pixels == (PixelPacket *) NULL)
3229 return((const PixelPacket *) NULL);
cristydf415c82010-03-11 16:47:50 +00003230 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3231 nexus_info->region.x;
3232 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3233 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003234 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3235 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003236 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3237 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003238 {
3239 MagickBooleanType
3240 status;
3241
3242 /*
3243 Pixel request is inside cache extents.
3244 */
3245 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
3246 return(pixels);
3247 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3248 if (status == MagickFalse)
3249 return((const PixelPacket *) NULL);
3250 if ((cache_info->storage_class == PseudoClass) ||
3251 (cache_info->colorspace == CMYKColorspace))
3252 {
3253 status=ReadPixelCacheIndexes(cache_info,nexus_info,exception);
3254 if (status == MagickFalse)
3255 return((const PixelPacket *) NULL);
3256 }
3257 return(pixels);
3258 }
3259 /*
3260 Pixel request is outside cache extents.
3261 */
3262 q=pixels;
3263 indexes=GetPixelCacheNexusIndexes(cache_info,nexus_info);
3264 virtual_nexus=AcquirePixelCacheNexus(1);
3265 if (virtual_nexus == (NexusInfo **) NULL)
3266 {
3267 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3268 "UnableToGetCacheNexus","`%s'",image->filename);
3269 return((const PixelPacket *) NULL);
3270 }
3271 switch (virtual_pixel_method)
3272 {
3273 case BlackVirtualPixelMethod:
3274 {
cristy4789f0d2010-01-10 00:01:06 +00003275 SetRedPixelComponent(&virtual_pixel,0);
3276 SetGreenPixelComponent(&virtual_pixel,0);
3277 SetBluePixelComponent(&virtual_pixel,0);
3278 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003279 break;
3280 }
3281 case GrayVirtualPixelMethod:
3282 {
cristy4789f0d2010-01-10 00:01:06 +00003283 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3284 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3285 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3286 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003287 break;
3288 }
3289 case TransparentVirtualPixelMethod:
3290 {
cristy4789f0d2010-01-10 00:01:06 +00003291 SetRedPixelComponent(&virtual_pixel,0);
3292 SetGreenPixelComponent(&virtual_pixel,0);
3293 SetBluePixelComponent(&virtual_pixel,0);
3294 SetOpacityPixelComponent(&virtual_pixel,TransparentOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003295 break;
3296 }
3297 case MaskVirtualPixelMethod:
3298 case WhiteVirtualPixelMethod:
3299 {
cristy4789f0d2010-01-10 00:01:06 +00003300 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3301 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3302 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3303 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003304 break;
3305 }
3306 default:
3307 {
3308 virtual_pixel=image->background_color;
3309 break;
3310 }
3311 }
cristyc3ec0d42010-04-07 01:18:08 +00003312 virtual_index=0;
cristybb503372010-05-27 20:51:26 +00003313 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003314 {
cristybb503372010-05-27 20:51:26 +00003315 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003316 {
3317 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003318 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003319 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3320 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003321 {
3322 MagickModulo
3323 x_modulo,
3324 y_modulo;
3325
3326 /*
3327 Transfer a single pixel.
3328 */
3329 length=(MagickSizeType) 1;
3330 switch (virtual_pixel_method)
3331 {
3332 case BackgroundVirtualPixelMethod:
3333 case ConstantVirtualPixelMethod:
3334 case BlackVirtualPixelMethod:
3335 case GrayVirtualPixelMethod:
3336 case TransparentVirtualPixelMethod:
3337 case MaskVirtualPixelMethod:
3338 case WhiteVirtualPixelMethod:
3339 {
3340 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003341 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003342 break;
3343 }
3344 case EdgeVirtualPixelMethod:
3345 default:
3346 {
3347 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003348 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003349 1UL,1UL,*virtual_nexus,exception);
cristyc3ec0d42010-04-07 01:18:08 +00003350 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003351 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003352 break;
3353 }
3354 case RandomVirtualPixelMethod:
3355 {
3356 if (cache_info->random_info == (RandomInfo *) NULL)
3357 cache_info->random_info=AcquireRandomInfo();
3358 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003359 RandomX(cache_info->random_info,cache_info->columns),
3360 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003361 *virtual_nexus,exception);
cristyc3ec0d42010-04-07 01:18:08 +00003362 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003363 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003364 break;
3365 }
3366 case DitherVirtualPixelMethod:
3367 {
3368 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003369 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003370 1UL,1UL,*virtual_nexus,exception);
cristyc3ec0d42010-04-07 01:18:08 +00003371 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003372 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003373 break;
3374 }
3375 case TileVirtualPixelMethod:
3376 {
3377 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3378 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3379 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003380 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003381 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003382 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003383 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003384 break;
3385 }
3386 case MirrorVirtualPixelMethod:
3387 {
3388 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3389 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003390 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003391 x_modulo.remainder-1L;
3392 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3393 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003394 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003395 y_modulo.remainder-1L;
3396 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003397 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003398 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003399 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003400 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003401 break;
3402 }
3403 case CheckerTileVirtualPixelMethod:
3404 {
3405 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3406 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3407 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3408 {
3409 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003410 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003411 break;
3412 }
3413 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003414 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003415 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003416 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003417 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003418 break;
3419 }
3420 case HorizontalTileVirtualPixelMethod:
3421 {
cristybb503372010-05-27 20:51:26 +00003422 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003423 {
3424 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003425 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003426 break;
3427 }
3428 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3429 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3430 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003431 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003432 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003433 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003434 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003435 break;
3436 }
3437 case VerticalTileVirtualPixelMethod:
3438 {
cristybb503372010-05-27 20:51:26 +00003439 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
cristy3ed852e2009-09-05 21:47:34 +00003440 {
3441 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003442 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003443 break;
3444 }
3445 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3446 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3447 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003448 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003449 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003450 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003451 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003452 break;
3453 }
3454 case HorizontalTileEdgeVirtualPixelMethod:
3455 {
3456 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3457 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003458 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003459 *virtual_nexus,exception);
cristyc3ec0d42010-04-07 01:18:08 +00003460 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003461 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003462 break;
3463 }
3464 case VerticalTileEdgeVirtualPixelMethod:
3465 {
3466 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3467 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003468 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003469 *virtual_nexus,exception);
cristyc3ec0d42010-04-07 01:18:08 +00003470 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003471 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003472 break;
3473 }
3474 }
3475 if (p == (const PixelPacket *) NULL)
3476 break;
3477 *q++=(*p);
cristyc3ec0d42010-04-07 01:18:08 +00003478 if ((indexes != (IndexPacket *) NULL) &&
3479 (virtual_indexes != (const IndexPacket *) NULL))
3480 *indexes++=(*virtual_indexes);
cristy3ed852e2009-09-05 21:47:34 +00003481 continue;
3482 }
3483 /*
3484 Transfer a run of pixels.
3485 */
3486 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,
cristy0a36c742010-10-03 02:10:53 +00003487 (size_t) length,1UL,*virtual_nexus,exception);
cristy3ed852e2009-09-05 21:47:34 +00003488 if (p == (const PixelPacket *) NULL)
3489 break;
cristy0a36c742010-10-03 02:10:53 +00003490 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,*virtual_nexus);
cristy8f036fe2010-09-18 02:02:00 +00003491 (void) memcpy(q,p,(size_t) length*sizeof(*p));
cristy3ed852e2009-09-05 21:47:34 +00003492 q+=length;
cristyc3ec0d42010-04-07 01:18:08 +00003493 if ((indexes != (IndexPacket *) NULL) &&
3494 (virtual_indexes != (const IndexPacket *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003495 {
cristy8f036fe2010-09-18 02:02:00 +00003496 (void) memcpy(indexes,virtual_indexes,(size_t) length*
cristyc3ec0d42010-04-07 01:18:08 +00003497 sizeof(*virtual_indexes));
3498 indexes+=length;
cristy3ed852e2009-09-05 21:47:34 +00003499 }
3500 }
3501 }
3502 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3503 return(pixels);
3504}
3505
3506/*
3507%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3508% %
3509% %
3510% %
3511+ G e t V i r t u a l P i x e l C a c h e %
3512% %
3513% %
3514% %
3515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3516%
3517% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3518% cache as defined by the geometry parameters. A pointer to the pixels
3519% is returned if the pixels are transferred, otherwise a NULL is returned.
3520%
3521% The format of the GetVirtualPixelCache() method is:
3522%
3523% const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003524% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3525% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003526% ExceptionInfo *exception)
3527%
3528% A description of each parameter follows:
3529%
3530% o image: the image.
3531%
3532% o virtual_pixel_method: the virtual pixel method.
3533%
3534% o x,y,columns,rows: These values define the perimeter of a region of
3535% pixels.
3536%
3537% o exception: return any errors or warnings in this structure.
3538%
3539*/
3540static const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003541 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3542 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003543{
3544 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003545 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003546
cristy5c9e6f22010-09-17 17:31:01 +00003547 const int
3548 id = GetOpenMPThreadId();
3549
cristye7cc7cf2010-09-21 13:26:47 +00003550 assert(image != (const Image *) NULL);
3551 assert(image->signature == MagickSignature);
3552 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003553 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003554 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003555 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003556 return(GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3557 cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00003558}
3559
3560/*
3561%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3562% %
3563% %
3564% %
3565% G e t V i r t u a l P i x e l Q u e u e %
3566% %
3567% %
3568% %
3569%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3570%
3571% GetVirtualPixelQueue() returns the virtual pixels associated with the
3572% last call to QueueAuthenticPixels() or GetVirtualPixels().
3573%
3574% The format of the GetVirtualPixelQueue() method is:
3575%
3576% const PixelPacket *GetVirtualPixelQueue(const Image image)
3577%
3578% A description of each parameter follows:
3579%
3580% o image: the image.
3581%
3582*/
3583MagickExport const PixelPacket *GetVirtualPixelQueue(const Image *image)
3584{
3585 CacheInfo
3586 *cache_info;
3587
cristy2036f5c2010-09-19 21:18:17 +00003588 const int
3589 id = GetOpenMPThreadId();
3590
cristy3ed852e2009-09-05 21:47:34 +00003591 assert(image != (const Image *) NULL);
3592 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003593 assert(image->cache != (Cache) NULL);
3594 cache_info=(CacheInfo *) image->cache;
3595 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003596 if (cache_info->methods.get_virtual_pixels_handler !=
3597 (GetVirtualPixelsHandler) NULL)
3598 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003599 assert(id < (int) cache_info->number_threads);
3600 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003601}
3602
3603/*
3604%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3605% %
3606% %
3607% %
3608% G e t V i r t u a l P i x e l s %
3609% %
3610% %
3611% %
3612%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3613%
3614% GetVirtualPixels() returns an immutable pixel region. If the
3615% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003616% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003617% copy of the pixels or it may point to the original pixels in memory.
3618% Performance is maximized if the selected region is part of one row, or one
3619% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003620% (without a copy) if the image is in memory, or in a memory-mapped file. The
3621% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003622%
3623% Pixels accessed via the returned pointer represent a simple array of type
3624% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
3625% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to access
3626% the black color component or to obtain the colormap indexes (of type
3627% IndexPacket) corresponding to the region.
3628%
3629% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3630%
3631% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3632% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3633% GetCacheViewAuthenticPixels() instead.
3634%
3635% The format of the GetVirtualPixels() method is:
3636%
cristybb503372010-05-27 20:51:26 +00003637% const PixelPacket *GetVirtualPixels(const Image *image,const ssize_t x,
3638% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003639% ExceptionInfo *exception)
3640%
3641% A description of each parameter follows:
3642%
3643% o image: the image.
3644%
3645% o x,y,columns,rows: These values define the perimeter of a region of
3646% pixels.
3647%
3648% o exception: return any errors or warnings in this structure.
3649%
3650*/
3651MagickExport const PixelPacket *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003652 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3653 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003654{
3655 CacheInfo
3656 *cache_info;
3657
cristy2036f5c2010-09-19 21:18:17 +00003658 const int
3659 id = GetOpenMPThreadId();
3660
cristy3ed852e2009-09-05 21:47:34 +00003661 assert(image != (const Image *) NULL);
3662 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003663 assert(image->cache != (Cache) NULL);
3664 cache_info=(CacheInfo *) image->cache;
3665 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003666 if (cache_info->methods.get_virtual_pixel_handler !=
3667 (GetVirtualPixelHandler) NULL)
3668 return(cache_info->methods.get_virtual_pixel_handler(image,
3669 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003670 assert(id < (int) cache_info->number_threads);
3671 return(GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3672 columns,rows,cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00003673}
3674
3675/*
3676%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3677% %
3678% %
3679% %
3680+ 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 %
3681% %
3682% %
3683% %
3684%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3685%
3686% GetVirtualPixelsCache() returns the pixels associated with the last call
3687% to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3688%
3689% The format of the GetVirtualPixelsCache() method is:
3690%
3691% PixelPacket *GetVirtualPixelsCache(const Image *image)
3692%
3693% A description of each parameter follows:
3694%
3695% o image: the image.
3696%
3697*/
3698static const PixelPacket *GetVirtualPixelsCache(const Image *image)
3699{
3700 CacheInfo
3701 *cache_info;
3702
cristy5c9e6f22010-09-17 17:31:01 +00003703 const int
3704 id = GetOpenMPThreadId();
3705
cristye7cc7cf2010-09-21 13:26:47 +00003706 assert(image != (const Image *) NULL);
3707 assert(image->signature == MagickSignature);
3708 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003709 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003710 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003711 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003712 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003713}
3714
3715/*
3716%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3717% %
3718% %
3719% %
3720+ G e t V i r t u a l P i x e l s N e x u s %
3721% %
3722% %
3723% %
3724%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3725%
3726% GetVirtualPixelsNexus() returns the pixels associated with the specified
3727% cache nexus.
3728%
3729% The format of the GetVirtualPixelsNexus() method is:
3730%
3731% const IndexPacket *GetVirtualPixelsNexus(const Cache cache,
3732% NexusInfo *nexus_info)
3733%
3734% A description of each parameter follows:
3735%
3736% o cache: the pixel cache.
3737%
3738% o nexus_info: the cache nexus to return the colormap pixels.
3739%
3740*/
3741MagickExport const PixelPacket *GetVirtualPixelsNexus(const Cache cache,
3742 NexusInfo *nexus_info)
3743{
3744 CacheInfo
3745 *cache_info;
3746
cristye7cc7cf2010-09-21 13:26:47 +00003747 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003748 cache_info=(CacheInfo *) cache;
3749 assert(cache_info->signature == MagickSignature);
3750 if (cache_info->storage_class == UndefinedClass)
3751 return((PixelPacket *) NULL);
3752 return((const PixelPacket *) nexus_info->pixels);
3753}
3754
3755/*
3756%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3757% %
3758% %
3759% %
3760+ M a s k P i x e l C a c h e N e x u s %
3761% %
3762% %
3763% %
3764%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3765%
3766% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3767% The method returns MagickTrue if the pixel region is masked, otherwise
3768% MagickFalse.
3769%
3770% The format of the MaskPixelCacheNexus() method is:
3771%
3772% MagickBooleanType MaskPixelCacheNexus(Image *image,
3773% NexusInfo *nexus_info,ExceptionInfo *exception)
3774%
3775% A description of each parameter follows:
3776%
3777% o image: the image.
3778%
3779% o nexus_info: the cache nexus to clip.
3780%
3781% o exception: return any errors or warnings in this structure.
3782%
3783*/
3784
3785static inline void MagickPixelCompositeMask(const MagickPixelPacket *p,
3786 const MagickRealType alpha,const MagickPixelPacket *q,
3787 const MagickRealType beta,MagickPixelPacket *composite)
3788{
3789 MagickRealType
3790 gamma;
3791
3792 if (alpha == TransparentOpacity)
3793 {
3794 *composite=(*q);
3795 return;
3796 }
3797 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3798 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3799 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3800 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3801 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3802 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3803 composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
3804}
3805
3806static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3807 ExceptionInfo *exception)
3808{
3809 CacheInfo
3810 *cache_info;
3811
3812 MagickPixelPacket
3813 alpha,
3814 beta;
3815
3816 MagickSizeType
3817 number_pixels;
3818
3819 NexusInfo
3820 **clip_nexus,
3821 **image_nexus;
3822
3823 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003824 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003825
3826 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003827 *restrict nexus_indexes,
3828 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003829
cristy3ed852e2009-09-05 21:47:34 +00003830 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003831 *restrict p,
3832 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003833
cristye076a6e2010-08-15 19:59:43 +00003834 register ssize_t
3835 i;
3836
cristy3ed852e2009-09-05 21:47:34 +00003837 /*
3838 Apply clip mask.
3839 */
3840 if (image->debug != MagickFalse)
3841 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3842 if (image->mask == (Image *) NULL)
3843 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +00003844 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00003845 if (cache_info == (Cache) NULL)
3846 return(MagickFalse);
3847 image_nexus=AcquirePixelCacheNexus(1);
3848 clip_nexus=AcquirePixelCacheNexus(1);
3849 if ((image_nexus == (NexusInfo **) NULL) ||
3850 (clip_nexus == (NexusInfo **) NULL))
3851 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy09449f72010-01-23 03:08:36 +00003852 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,
3853 nexus_info->region.y,nexus_info->region.width,nexus_info->region.height,
3854 image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003855 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
3856 q=nexus_info->pixels;
3857 nexus_indexes=nexus_info->indexes;
3858 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3859 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3860 nexus_info->region.height,clip_nexus[0],&image->exception);
3861 GetMagickPixelPacket(image,&alpha);
3862 GetMagickPixelPacket(image,&beta);
3863 number_pixels=(MagickSizeType) nexus_info->region.width*
3864 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +00003865 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +00003866 {
3867 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
3868 break;
3869 SetMagickPixelPacket(image,p,indexes+i,&alpha);
3870 SetMagickPixelPacket(image,q,nexus_indexes+i,&beta);
3871 MagickPixelCompositeMask(&beta,(MagickRealType) PixelIntensityToQuantum(r),
3872 &alpha,alpha.opacity,&beta);
cristyce70c172010-01-07 17:15:30 +00003873 q->red=ClampToQuantum(beta.red);
3874 q->green=ClampToQuantum(beta.green);
3875 q->blue=ClampToQuantum(beta.blue);
3876 q->opacity=ClampToQuantum(beta.opacity);
cristy3ed852e2009-09-05 21:47:34 +00003877 if (cache_info->active_index_channel != MagickFalse)
3878 nexus_indexes[i]=indexes[i];
3879 p++;
3880 q++;
3881 r++;
3882 }
3883 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3884 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +00003885 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003886 return(MagickFalse);
3887 return(MagickTrue);
3888}
3889
3890/*
3891%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3892% %
3893% %
3894% %
3895+ O p e n P i x e l C a c h e %
3896% %
3897% %
3898% %
3899%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3900%
3901% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3902% dimensions, allocating space for the image pixels and optionally the
3903% colormap indexes, and memory mapping the cache if it is disk based. The
3904% cache nexus array is initialized as well.
3905%
3906% The format of the OpenPixelCache() method is:
3907%
3908% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3909% ExceptionInfo *exception)
3910%
3911% A description of each parameter follows:
3912%
3913% o image: the image.
3914%
3915% o mode: ReadMode, WriteMode, or IOMode.
3916%
3917% o exception: return any errors or warnings in this structure.
3918%
3919*/
3920
cristyd43a46b2010-01-21 02:13:41 +00003921static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003922{
3923 cache_info->mapped=MagickFalse;
3924 cache_info->pixels=(PixelPacket *) AcquireMagickMemory((size_t)
3925 cache_info->length);
3926 if (cache_info->pixels == (PixelPacket *) NULL)
3927 {
3928 cache_info->mapped=MagickTrue;
3929 cache_info->pixels=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
3930 cache_info->length);
3931 }
3932}
3933
3934static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3935{
3936 CacheInfo
3937 *cache_info;
3938
3939 MagickOffsetType
3940 count,
3941 extent,
3942 offset;
3943
3944 cache_info=(CacheInfo *) image->cache;
3945 if (image->debug != MagickFalse)
3946 {
3947 char
3948 format[MaxTextExtent],
3949 message[MaxTextExtent];
3950
cristyb9080c92009-12-01 20:13:26 +00003951 (void) FormatMagickSize(length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00003952 (void) FormatMagickString(message,MaxTextExtent,
cristy2ce15c92010-03-12 14:03:41 +00003953 "extend %s (%s[%d], disk, %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003954 cache_info->cache_filename,cache_info->file,format);
3955 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3956 }
3957 if (length != (MagickSizeType) ((MagickOffsetType) length))
3958 return(MagickFalse);
3959 extent=(MagickOffsetType) MagickSeek(cache_info->file,0,SEEK_END);
3960 if (extent < 0)
3961 return(MagickFalse);
3962 if ((MagickSizeType) extent >= length)
3963 return(MagickTrue);
3964 offset=(MagickOffsetType) length-1;
3965 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3966 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3967}
3968
3969static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3970 ExceptionInfo *exception)
3971{
3972 char
3973 format[MaxTextExtent],
3974 message[MaxTextExtent];
3975
3976 CacheInfo
3977 *cache_info,
3978 source_info;
3979
3980 MagickSizeType
3981 length,
3982 number_pixels;
3983
3984 MagickStatusType
3985 status;
3986
3987 size_t
cristye076a6e2010-08-15 19:59:43 +00003988 columns,
cristy3ed852e2009-09-05 21:47:34 +00003989 packet_size;
3990
cristye7cc7cf2010-09-21 13:26:47 +00003991 assert(image != (const Image *) NULL);
3992 assert(image->signature == MagickSignature);
3993 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003994 if (image->debug != MagickFalse)
3995 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3996 if ((image->columns == 0) || (image->rows == 0))
3997 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3998 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003999 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004000 source_info=(*cache_info);
4001 source_info.file=(-1);
cristye8c25f92010-06-03 00:53:06 +00004002 (void) FormatMagickString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
4003 image->filename,(double) GetImageIndexInList(image));
cristy87528ea2009-09-10 14:53:56 +00004004 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +00004005 cache_info->rows=image->rows;
4006 cache_info->columns=image->columns;
4007 cache_info->active_index_channel=((image->storage_class == PseudoClass) ||
4008 (image->colorspace == CMYKColorspace)) ? MagickTrue : MagickFalse;
cristy73724512010-04-12 14:43:14 +00004009 if (image->ping != MagickFalse)
4010 {
4011 cache_info->storage_class=image->storage_class;
4012 cache_info->colorspace=image->colorspace;
4013 cache_info->type=PingCache;
4014 cache_info->pixels=(PixelPacket *) NULL;
4015 cache_info->indexes=(IndexPacket *) NULL;
4016 cache_info->length=0;
4017 return(MagickTrue);
4018 }
cristy3ed852e2009-09-05 21:47:34 +00004019 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4020 packet_size=sizeof(PixelPacket);
4021 if (cache_info->active_index_channel != MagickFalse)
4022 packet_size+=sizeof(IndexPacket);
4023 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00004024 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00004025 if (cache_info->columns != columns)
4026 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4027 image->filename);
4028 cache_info->length=length;
4029 status=AcquireMagickResource(AreaResource,cache_info->length);
4030 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4031 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4032 {
4033 status=AcquireMagickResource(MemoryResource,cache_info->length);
4034 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4035 (cache_info->type == MemoryCache))
4036 {
cristyd43a46b2010-01-21 02:13:41 +00004037 AllocatePixelCachePixels(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004038 if (cache_info->pixels == (PixelPacket *) NULL)
4039 cache_info->pixels=source_info.pixels;
4040 else
4041 {
4042 /*
4043 Create memory pixel cache.
4044 */
4045 if (image->debug != MagickFalse)
4046 {
cristy97e7a572009-12-05 15:07:53 +00004047 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004048 format);
cristy3ed852e2009-09-05 21:47:34 +00004049 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004050 "open %s (%s memory, %.20gx%.20g %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00004051 cache_info->mapped != MagickFalse ? "anonymous" : "heap",
cristye8c25f92010-06-03 00:53:06 +00004052 (double) cache_info->columns,(double) cache_info->rows,
4053 format);
cristy3ed852e2009-09-05 21:47:34 +00004054 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4055 message);
4056 }
4057 cache_info->storage_class=image->storage_class;
4058 cache_info->colorspace=image->colorspace;
4059 cache_info->type=MemoryCache;
4060 cache_info->indexes=(IndexPacket *) NULL;
4061 if (cache_info->active_index_channel != MagickFalse)
4062 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4063 number_pixels);
4064 if (source_info.storage_class != UndefinedClass)
4065 {
4066 status|=ClonePixelCachePixels(cache_info,&source_info,
4067 exception);
4068 RelinquishPixelCachePixels(&source_info);
4069 }
4070 return(MagickTrue);
4071 }
4072 }
4073 RelinquishMagickResource(MemoryResource,cache_info->length);
4074 }
4075 /*
4076 Create pixel cache on disk.
4077 */
4078 status=AcquireMagickResource(DiskResource,cache_info->length);
4079 if (status == MagickFalse)
4080 {
4081 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4082 "CacheResourcesExhausted","`%s'",image->filename);
4083 return(MagickFalse);
4084 }
4085 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4086 {
4087 RelinquishMagickResource(DiskResource,cache_info->length);
4088 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4089 image->filename);
4090 return(MagickFalse);
4091 }
4092 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4093 cache_info->length);
4094 if (status == MagickFalse)
4095 {
4096 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4097 image->filename);
4098 return(MagickFalse);
4099 }
4100 cache_info->storage_class=image->storage_class;
4101 cache_info->colorspace=image->colorspace;
4102 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4103 status=AcquireMagickResource(AreaResource,cache_info->length);
4104 if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4105 cache_info->type=DiskCache;
4106 else
4107 {
4108 status=AcquireMagickResource(MapResource,cache_info->length);
4109 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4110 (cache_info->type != MemoryCache))
4111 cache_info->type=DiskCache;
4112 else
4113 {
4114 cache_info->pixels=(PixelPacket *) MapBlob(cache_info->file,mode,
4115 cache_info->offset,(size_t) cache_info->length);
4116 if (cache_info->pixels == (PixelPacket *) NULL)
4117 {
4118 cache_info->pixels=source_info.pixels;
4119 cache_info->type=DiskCache;
4120 }
4121 else
4122 {
4123 /*
4124 Create file-backed memory-mapped pixel cache.
4125 */
4126 (void) ClosePixelCacheOnDisk(cache_info);
4127 cache_info->type=MapCache;
4128 cache_info->mapped=MagickTrue;
4129 cache_info->indexes=(IndexPacket *) NULL;
4130 if (cache_info->active_index_channel != MagickFalse)
4131 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4132 number_pixels);
4133 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4134 {
4135 status=ClonePixelCachePixels(cache_info,&source_info,
4136 exception);
4137 RelinquishPixelCachePixels(&source_info);
4138 }
4139 if (image->debug != MagickFalse)
4140 {
cristy97e7a572009-12-05 15:07:53 +00004141 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004142 format);
cristy3ed852e2009-09-05 21:47:34 +00004143 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004144 "open %s (%s[%d], memory-mapped, %.20gx%.20g %sB)",
cristy3ed852e2009-09-05 21:47:34 +00004145 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004146 cache_info->file,(double) cache_info->columns,(double)
4147 cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004148 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4149 message);
4150 }
4151 return(MagickTrue);
4152 }
4153 }
4154 RelinquishMagickResource(MapResource,cache_info->length);
4155 }
4156 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4157 {
4158 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4159 RelinquishPixelCachePixels(&source_info);
4160 }
4161 if (image->debug != MagickFalse)
4162 {
cristyb9080c92009-12-01 20:13:26 +00004163 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00004164 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004165 "open %s (%s[%d], disk, %.20gx%.20g %sB)",cache_info->filename,
4166 cache_info->cache_filename,cache_info->file,(double)
4167 cache_info->columns,(double) cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004168 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4169 }
4170 return(MagickTrue);
4171}
4172
4173/*
4174%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4175% %
4176% %
4177% %
4178+ P e r s i s t P i x e l C a c h e %
4179% %
4180% %
4181% %
4182%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4183%
4184% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4185% persistent pixel cache is one that resides on disk and is not destroyed
4186% when the program exits.
4187%
4188% The format of the PersistPixelCache() method is:
4189%
4190% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4191% const MagickBooleanType attach,MagickOffsetType *offset,
4192% ExceptionInfo *exception)
4193%
4194% A description of each parameter follows:
4195%
4196% o image: the image.
4197%
4198% o filename: the persistent pixel cache filename.
4199%
cristy01b7eb02009-09-10 23:10:14 +00004200% o attach: A value other than zero initializes the persistent pixel
4201% cache.
4202%
cristy3ed852e2009-09-05 21:47:34 +00004203% o initialize: A value other than zero initializes the persistent pixel
4204% cache.
4205%
4206% o offset: the offset in the persistent cache to store pixels.
4207%
4208% o exception: return any errors or warnings in this structure.
4209%
4210*/
4211MagickExport MagickBooleanType PersistPixelCache(Image *image,
4212 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4213 ExceptionInfo *exception)
4214{
4215 CacheInfo
4216 *cache_info,
4217 *clone_info;
4218
4219 Image
4220 clone_image;
4221
cristy3ed852e2009-09-05 21:47:34 +00004222 MagickBooleanType
4223 status;
4224
cristye076a6e2010-08-15 19:59:43 +00004225 ssize_t
4226 page_size;
4227
cristy3ed852e2009-09-05 21:47:34 +00004228 assert(image != (Image *) NULL);
4229 assert(image->signature == MagickSignature);
4230 if (image->debug != MagickFalse)
4231 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4232 assert(image->cache != (void *) NULL);
4233 assert(filename != (const char *) NULL);
4234 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004235 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004236 cache_info=(CacheInfo *) image->cache;
4237 assert(cache_info->signature == MagickSignature);
4238 if (attach != MagickFalse)
4239 {
4240 /*
cristy01b7eb02009-09-10 23:10:14 +00004241 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004242 */
4243 if (image->debug != MagickFalse)
4244 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004245 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004246 (void) CopyMagickString(cache_info->cache_filename,filename,
4247 MaxTextExtent);
4248 cache_info->type=DiskCache;
4249 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004250 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004251 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004252 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004253 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004254 }
cristy01b7eb02009-09-10 23:10:14 +00004255 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4256 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004257 {
cristyf84a1932010-01-03 18:00:18 +00004258 LockSemaphoreInfo(cache_info->semaphore);
cristy09449f72010-01-23 03:08:36 +00004259 if ((cache_info->mode != ReadMode) &&
4260 (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004261 (cache_info->reference_count == 1))
4262 {
4263 int
4264 status;
4265
4266 /*
cristy01b7eb02009-09-10 23:10:14 +00004267 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004268 */
4269 status=rename(cache_info->cache_filename,filename);
4270 if (status == 0)
4271 {
4272 (void) CopyMagickString(cache_info->cache_filename,filename,
4273 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004274 *offset+=cache_info->length+page_size-(cache_info->length %
4275 page_size);
cristyf84a1932010-01-03 18:00:18 +00004276 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004277 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004278 if (image->debug != MagickFalse)
4279 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4280 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004281 return(MagickTrue);
4282 }
4283 }
cristyf84a1932010-01-03 18:00:18 +00004284 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004285 }
4286 /*
cristy01b7eb02009-09-10 23:10:14 +00004287 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004288 */
4289 clone_image=(*image);
4290 clone_info=(CacheInfo *) clone_image.cache;
4291 image->cache=ClonePixelCache(cache_info);
4292 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4293 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4294 cache_info->type=DiskCache;
4295 cache_info->offset=(*offset);
4296 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004297 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004298 if (status != MagickFalse)
cristycfae90a2010-10-04 14:43:33 +00004299 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
cristy688f07b2009-09-27 15:19:13 +00004300 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004301 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4302 return(status);
4303}
4304
4305/*
4306%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4307% %
4308% %
4309% %
4310+ Q u e u e A u t h e n t i c N e x u s %
4311% %
4312% %
4313% %
4314%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4315%
4316% QueueAuthenticNexus() allocates an region to store image pixels as defined
4317% by the region rectangle and returns a pointer to the region. This region is
4318% subsequently transferred from the pixel cache with
4319% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4320% pixels are transferred, otherwise a NULL is returned.
4321%
4322% The format of the QueueAuthenticNexus() method is:
4323%
cristy5f959472010-05-27 22:19:46 +00004324% PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
4325% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004326% NexusInfo *nexus_info,ExceptionInfo *exception)
4327%
4328% A description of each parameter follows:
4329%
4330% o image: the image.
4331%
4332% o x,y,columns,rows: These values define the perimeter of a region of
4333% pixels.
4334%
4335% o nexus_info: the cache nexus to set.
4336%
4337% o exception: return any errors or warnings in this structure.
4338%
4339*/
cristybb503372010-05-27 20:51:26 +00004340MagickExport PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy30097232010-07-01 02:16:30 +00004341 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
4342 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004343{
4344 CacheInfo
4345 *cache_info;
4346
4347 MagickOffsetType
4348 offset;
4349
4350 MagickSizeType
4351 number_pixels;
4352
4353 RectangleInfo
4354 region;
4355
4356 /*
4357 Validate pixel cache geometry.
4358 */
cristye7cc7cf2010-09-21 13:26:47 +00004359 assert(image != (const Image *) NULL);
4360 assert(image->signature == MagickSignature);
4361 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004362 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
cristye7cc7cf2010-09-21 13:26:47 +00004363 assert(cache_info->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00004364 if (cache_info == (Cache) NULL)
4365 return((PixelPacket *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004366 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4367 {
4368 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4369 "NoPixelsDefinedInCache","`%s'",image->filename);
4370 return((PixelPacket *) NULL);
4371 }
cristybb503372010-05-27 20:51:26 +00004372 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4373 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004374 {
4375 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4376 "PixelsAreNotAuthentic","`%s'",image->filename);
4377 return((PixelPacket *) NULL);
4378 }
4379 offset=(MagickOffsetType) y*cache_info->columns+x;
4380 if (offset < 0)
4381 return((PixelPacket *) NULL);
4382 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4383 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4384 if ((MagickSizeType) offset >= number_pixels)
4385 return((PixelPacket *) NULL);
4386 /*
4387 Return pixel cache.
4388 */
4389 region.x=x;
4390 region.y=y;
4391 region.width=columns;
4392 region.height=rows;
4393 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4394}
4395
4396/*
4397%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4398% %
4399% %
4400% %
4401+ 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 %
4402% %
4403% %
4404% %
4405%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4406%
4407% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4408% defined by the region rectangle and returns a pointer to the region. This
4409% region is subsequently transferred from the pixel cache with
4410% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4411% pixels are transferred, otherwise a NULL is returned.
4412%
4413% The format of the QueueAuthenticPixelsCache() method is:
4414%
cristybb503372010-05-27 20:51:26 +00004415% PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4416% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004417% ExceptionInfo *exception)
4418%
4419% A description of each parameter follows:
4420%
4421% o image: the image.
4422%
4423% o x,y,columns,rows: These values define the perimeter of a region of
4424% pixels.
4425%
4426% o exception: return any errors or warnings in this structure.
4427%
4428*/
cristybb503372010-05-27 20:51:26 +00004429static PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4430 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004431 ExceptionInfo *exception)
4432{
4433 CacheInfo
4434 *cache_info;
4435
cristy5c9e6f22010-09-17 17:31:01 +00004436 const int
4437 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004438
cristye7cc7cf2010-09-21 13:26:47 +00004439 assert(image != (const Image *) NULL);
4440 assert(image->signature == MagickSignature);
4441 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004442 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004443 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004444 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00004445 return(QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4446 exception));
cristy3ed852e2009-09-05 21:47:34 +00004447}
4448
4449/*
4450%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4451% %
4452% %
4453% %
4454% Q u e u e A u t h e n t i c P i x e l s %
4455% %
4456% %
4457% %
4458%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4459%
4460% QueueAuthenticPixels() queues a mutable pixel region. If the region is
4461% successfully intialized a pointer to a PixelPacket array representing the
4462% region is returned, otherwise NULL is returned. The returned pointer may
4463% point to a temporary working buffer for the pixels or it may point to the
4464% final location of the pixels in memory.
4465%
4466% Write-only access means that any existing pixel values corresponding to
4467% the region are ignored. This is useful if the initial image is being
4468% created from scratch, or if the existing pixel values are to be
4469% completely replaced without need to refer to their pre-existing values.
4470% The application is free to read and write the pixel buffer returned by
4471% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4472% initialize the pixel array values. Initializing pixel array values is the
4473% application's responsibility.
4474%
4475% Performance is maximized if the selected region is part of one row, or
4476% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004477% pixels in-place (without a copy) if the image is in memory, or in a
4478% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004479% by the user.
4480%
4481% Pixels accessed via the returned pointer represent a simple array of type
4482% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
4483% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
4484% the black color component or the colormap indexes (of type IndexPacket)
4485% corresponding to the region. Once the PixelPacket (and/or IndexPacket)
4486% array has been updated, the changes must be saved back to the underlying
4487% image using SyncAuthenticPixels() or they may be lost.
4488%
4489% The format of the QueueAuthenticPixels() method is:
4490%
cristy5f959472010-05-27 22:19:46 +00004491% PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4492% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004493% ExceptionInfo *exception)
4494%
4495% A description of each parameter follows:
4496%
4497% o image: the image.
4498%
4499% o x,y,columns,rows: These values define the perimeter of a region of
4500% pixels.
4501%
4502% o exception: return any errors or warnings in this structure.
4503%
4504*/
cristybb503372010-05-27 20:51:26 +00004505MagickExport PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4506 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004507 ExceptionInfo *exception)
4508{
4509 CacheInfo
4510 *cache_info;
4511
cristy2036f5c2010-09-19 21:18:17 +00004512 const int
4513 id = GetOpenMPThreadId();
4514
cristy3ed852e2009-09-05 21:47:34 +00004515 assert(image != (Image *) NULL);
4516 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004517 assert(image->cache != (Cache) NULL);
4518 cache_info=(CacheInfo *) image->cache;
4519 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004520 if (cache_info->methods.queue_authentic_pixels_handler !=
4521 (QueueAuthenticPixelsHandler) NULL)
4522 return(cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4523 rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00004524 assert(id < (int) cache_info->number_threads);
4525 return(QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4526 exception));
cristy3ed852e2009-09-05 21:47:34 +00004527}
4528
4529/*
4530%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4531% %
4532% %
4533% %
4534+ R e a d P i x e l C a c h e I n d e x e s %
4535% %
4536% %
4537% %
4538%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4539%
4540% ReadPixelCacheIndexes() reads colormap indexes from the specified region of
4541% the pixel cache.
4542%
4543% The format of the ReadPixelCacheIndexes() method is:
4544%
4545% MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4546% NexusInfo *nexus_info,ExceptionInfo *exception)
4547%
4548% A description of each parameter follows:
4549%
4550% o cache_info: the pixel cache.
4551%
4552% o nexus_info: the cache nexus to read the colormap indexes.
4553%
4554% o exception: return any errors or warnings in this structure.
4555%
4556*/
4557static MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4558 NexusInfo *nexus_info,ExceptionInfo *exception)
4559{
4560 MagickOffsetType
4561 count,
4562 offset;
4563
4564 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004565 extent,
4566 length;
cristy3ed852e2009-09-05 21:47:34 +00004567
4568 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004569 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004570
cristybb503372010-05-27 20:51:26 +00004571 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004572 y;
4573
cristybb503372010-05-27 20:51:26 +00004574 size_t
cristy3ed852e2009-09-05 21:47:34 +00004575 rows;
4576
cristy3ed852e2009-09-05 21:47:34 +00004577 if (cache_info->active_index_channel == MagickFalse)
4578 return(MagickFalse);
4579 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4580 return(MagickTrue);
4581 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4582 nexus_info->region.x;
4583 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
4584 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004585 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004586 q=nexus_info->indexes;
4587 switch (cache_info->type)
4588 {
4589 case MemoryCache:
4590 case MapCache:
4591 {
4592 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004593 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004594
4595 /*
4596 Read indexes from memory.
4597 */
cristydd341db2010-03-04 19:06:38 +00004598 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004599 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004600 {
cristy48078b12010-09-23 17:11:01 +00004601 length=extent;
cristydd341db2010-03-04 19:06:38 +00004602 rows=1UL;
4603 }
cristy3ed852e2009-09-05 21:47:34 +00004604 p=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00004605 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004606 {
cristy8f036fe2010-09-18 02:02:00 +00004607 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00004608 p+=cache_info->columns;
4609 q+=nexus_info->region.width;
4610 }
4611 break;
4612 }
4613 case DiskCache:
4614 {
4615 /*
4616 Read indexes from disk.
4617 */
4618 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4619 {
4620 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4621 cache_info->cache_filename);
4622 return(MagickFalse);
4623 }
cristydd341db2010-03-04 19:06:38 +00004624 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004625 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004626 {
cristy48078b12010-09-23 17:11:01 +00004627 length=extent;
cristydd341db2010-03-04 19:06:38 +00004628 rows=1UL;
4629 }
cristy48078b12010-09-23 17:11:01 +00004630 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004631 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004632 {
cristy48078b12010-09-23 17:11:01 +00004633 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristy3ed852e2009-09-05 21:47:34 +00004634 sizeof(PixelPacket)+offset*sizeof(*q),length,(unsigned char *) q);
4635 if ((MagickSizeType) count < length)
4636 break;
4637 offset+=cache_info->columns;
4638 q+=nexus_info->region.width;
4639 }
cristybb503372010-05-27 20:51:26 +00004640 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004641 {
4642 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4643 cache_info->cache_filename);
4644 return(MagickFalse);
4645 }
4646 break;
4647 }
4648 default:
4649 break;
4650 }
4651 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004652 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004653 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004654 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004655 nexus_info->region.width,(double) nexus_info->region.height,(double)
4656 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004657 return(MagickTrue);
4658}
4659
4660/*
4661%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4662% %
4663% %
4664% %
4665+ R e a d P i x e l C a c h e P i x e l s %
4666% %
4667% %
4668% %
4669%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4670%
4671% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4672% cache.
4673%
4674% The format of the ReadPixelCachePixels() method is:
4675%
4676% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4677% NexusInfo *nexus_info,ExceptionInfo *exception)
4678%
4679% A description of each parameter follows:
4680%
4681% o cache_info: the pixel cache.
4682%
4683% o nexus_info: the cache nexus to read the pixels.
4684%
4685% o exception: return any errors or warnings in this structure.
4686%
4687*/
4688static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4689 NexusInfo *nexus_info,ExceptionInfo *exception)
4690{
4691 MagickOffsetType
4692 count,
4693 offset;
4694
4695 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004696 extent,
4697 length;
cristy3ed852e2009-09-05 21:47:34 +00004698
cristy3ed852e2009-09-05 21:47:34 +00004699 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004700 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004701
cristye076a6e2010-08-15 19:59:43 +00004702 register ssize_t
4703 y;
4704
cristybb503372010-05-27 20:51:26 +00004705 size_t
cristy3ed852e2009-09-05 21:47:34 +00004706 rows;
4707
cristy3ed852e2009-09-05 21:47:34 +00004708 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4709 return(MagickTrue);
4710 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4711 nexus_info->region.x;
4712 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
4713 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004714 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004715 q=nexus_info->pixels;
4716 switch (cache_info->type)
4717 {
4718 case MemoryCache:
4719 case MapCache:
4720 {
4721 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004722 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004723
4724 /*
4725 Read pixels from memory.
4726 */
cristydd341db2010-03-04 19:06:38 +00004727 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004728 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004729 {
cristy48078b12010-09-23 17:11:01 +00004730 length=extent;
cristydd341db2010-03-04 19:06:38 +00004731 rows=1UL;
4732 }
cristy3ed852e2009-09-05 21:47:34 +00004733 p=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00004734 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004735 {
cristy8f036fe2010-09-18 02:02:00 +00004736 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00004737 p+=cache_info->columns;
4738 q+=nexus_info->region.width;
4739 }
4740 break;
4741 }
4742 case DiskCache:
4743 {
4744 /*
4745 Read pixels from disk.
4746 */
4747 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4748 {
4749 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4750 cache_info->cache_filename);
4751 return(MagickFalse);
4752 }
cristydd341db2010-03-04 19:06:38 +00004753 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004754 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004755 {
cristy48078b12010-09-23 17:11:01 +00004756 length=extent;
cristydd341db2010-03-04 19:06:38 +00004757 rows=1UL;
4758 }
cristybb503372010-05-27 20:51:26 +00004759 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004760 {
4761 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4762 sizeof(*q),length,(unsigned char *) q);
4763 if ((MagickSizeType) count < length)
4764 break;
4765 offset+=cache_info->columns;
4766 q+=nexus_info->region.width;
4767 }
cristybb503372010-05-27 20:51:26 +00004768 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004769 {
4770 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4771 cache_info->cache_filename);
4772 return(MagickFalse);
4773 }
4774 break;
4775 }
4776 default:
4777 break;
4778 }
4779 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004780 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004781 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004782 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004783 nexus_info->region.width,(double) nexus_info->region.height,(double)
4784 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004785 return(MagickTrue);
4786}
4787
4788/*
4789%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4790% %
4791% %
4792% %
4793+ R e f e r e n c e P i x e l C a c h e %
4794% %
4795% %
4796% %
4797%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4798%
4799% ReferencePixelCache() increments the reference count associated with the
4800% pixel cache returning a pointer to the cache.
4801%
4802% The format of the ReferencePixelCache method is:
4803%
4804% Cache ReferencePixelCache(Cache cache_info)
4805%
4806% A description of each parameter follows:
4807%
4808% o cache_info: the pixel cache.
4809%
4810*/
4811MagickExport Cache ReferencePixelCache(Cache cache)
4812{
4813 CacheInfo
4814 *cache_info;
4815
4816 assert(cache != (Cache *) NULL);
4817 cache_info=(CacheInfo *) cache;
4818 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004819 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004820 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004821 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004822 return(cache_info);
4823}
4824
4825/*
4826%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4827% %
4828% %
4829% %
4830+ S e t P i x e l C a c h e M e t h o d s %
4831% %
4832% %
4833% %
4834%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4835%
4836% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4837%
4838% The format of the SetPixelCacheMethods() method is:
4839%
4840% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4841%
4842% A description of each parameter follows:
4843%
4844% o cache: the pixel cache.
4845%
4846% o cache_methods: Specifies a pointer to a CacheMethods structure.
4847%
4848*/
4849MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4850{
4851 CacheInfo
4852 *cache_info;
4853
4854 GetOneAuthenticPixelFromHandler
4855 get_one_authentic_pixel_from_handler;
4856
4857 GetOneVirtualPixelFromHandler
4858 get_one_virtual_pixel_from_handler;
4859
4860 /*
4861 Set cache pixel methods.
4862 */
4863 assert(cache != (Cache) NULL);
4864 assert(cache_methods != (CacheMethods *) NULL);
4865 cache_info=(CacheInfo *) cache;
4866 assert(cache_info->signature == MagickSignature);
4867 if (cache_info->debug != MagickFalse)
4868 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4869 cache_info->filename);
4870 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4871 cache_info->methods.get_virtual_pixel_handler=
4872 cache_methods->get_virtual_pixel_handler;
4873 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4874 cache_info->methods.destroy_pixel_handler=
4875 cache_methods->destroy_pixel_handler;
4876 if (cache_methods->get_virtual_indexes_from_handler !=
4877 (GetVirtualIndexesFromHandler) NULL)
4878 cache_info->methods.get_virtual_indexes_from_handler=
4879 cache_methods->get_virtual_indexes_from_handler;
4880 if (cache_methods->get_authentic_pixels_handler !=
4881 (GetAuthenticPixelsHandler) NULL)
4882 cache_info->methods.get_authentic_pixels_handler=
4883 cache_methods->get_authentic_pixels_handler;
4884 if (cache_methods->queue_authentic_pixels_handler !=
4885 (QueueAuthenticPixelsHandler) NULL)
4886 cache_info->methods.queue_authentic_pixels_handler=
4887 cache_methods->queue_authentic_pixels_handler;
4888 if (cache_methods->sync_authentic_pixels_handler !=
4889 (SyncAuthenticPixelsHandler) NULL)
4890 cache_info->methods.sync_authentic_pixels_handler=
4891 cache_methods->sync_authentic_pixels_handler;
4892 if (cache_methods->get_authentic_pixels_from_handler !=
4893 (GetAuthenticPixelsFromHandler) NULL)
4894 cache_info->methods.get_authentic_pixels_from_handler=
4895 cache_methods->get_authentic_pixels_from_handler;
4896 if (cache_methods->get_authentic_indexes_from_handler !=
4897 (GetAuthenticIndexesFromHandler) NULL)
4898 cache_info->methods.get_authentic_indexes_from_handler=
4899 cache_methods->get_authentic_indexes_from_handler;
4900 get_one_virtual_pixel_from_handler=
4901 cache_info->methods.get_one_virtual_pixel_from_handler;
4902 if (get_one_virtual_pixel_from_handler !=
4903 (GetOneVirtualPixelFromHandler) NULL)
4904 cache_info->methods.get_one_virtual_pixel_from_handler=
4905 cache_methods->get_one_virtual_pixel_from_handler;
4906 get_one_authentic_pixel_from_handler=
4907 cache_methods->get_one_authentic_pixel_from_handler;
4908 if (get_one_authentic_pixel_from_handler !=
4909 (GetOneAuthenticPixelFromHandler) NULL)
4910 cache_info->methods.get_one_authentic_pixel_from_handler=
4911 cache_methods->get_one_authentic_pixel_from_handler;
4912}
4913
4914/*
4915%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4916% %
4917% %
4918% %
4919+ S e t P i x e l C a c h e N e x u s P i x e l s %
4920% %
4921% %
4922% %
4923%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4924%
4925% SetPixelCacheNexusPixels() defines the region of the cache for the
4926% specified cache nexus.
4927%
4928% The format of the SetPixelCacheNexusPixels() method is:
4929%
4930% PixelPacket SetPixelCacheNexusPixels(const Image *image,
4931% const RectangleInfo *region,NexusInfo *nexus_info,
4932% ExceptionInfo *exception)
4933%
4934% A description of each parameter follows:
4935%
4936% o image: the image.
4937%
4938% o region: A pointer to the RectangleInfo structure that defines the
4939% region of this particular cache nexus.
4940%
4941% o nexus_info: the cache nexus to set.
4942%
4943% o exception: return any errors or warnings in this structure.
4944%
4945*/
cristyabd6e372010-09-15 19:11:26 +00004946
4947static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4948 NexusInfo *nexus_info,ExceptionInfo *exception)
4949{
4950 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4951 return(MagickFalse);
4952 nexus_info->mapped=MagickFalse;
4953 nexus_info->cache=(PixelPacket *) AcquireMagickMemory((size_t)
4954 nexus_info->length);
4955 if (nexus_info->cache == (PixelPacket *) NULL)
4956 {
4957 nexus_info->mapped=MagickTrue;
4958 nexus_info->cache=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
4959 nexus_info->length);
4960 }
4961 if (nexus_info->cache == (PixelPacket *) NULL)
4962 {
4963 (void) ThrowMagickException(exception,GetMagickModule(),
4964 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4965 cache_info->filename);
4966 return(MagickFalse);
4967 }
4968 return(MagickTrue);
4969}
4970
cristy3ed852e2009-09-05 21:47:34 +00004971static PixelPacket *SetPixelCacheNexusPixels(const Image *image,
4972 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4973{
4974 CacheInfo
4975 *cache_info;
4976
4977 MagickBooleanType
4978 status;
4979
cristy3ed852e2009-09-05 21:47:34 +00004980 MagickSizeType
4981 length,
4982 number_pixels;
4983
cristy3ed852e2009-09-05 21:47:34 +00004984 cache_info=(CacheInfo *) image->cache;
4985 assert(cache_info->signature == MagickSignature);
4986 if (cache_info->type == UndefinedCache)
4987 return((PixelPacket *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00004988 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00004989 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
4990 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00004991 {
cristybb503372010-05-27 20:51:26 +00004992 ssize_t
cristybad067a2010-02-15 17:20:55 +00004993 x,
4994 y;
cristy3ed852e2009-09-05 21:47:34 +00004995
cristyeaedf062010-05-29 22:36:02 +00004996 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4997 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00004998 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4999 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00005000 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00005001 ((nexus_info->region.width == cache_info->columns) ||
5002 ((nexus_info->region.width % cache_info->columns) == 0)))))
5003 {
5004 MagickOffsetType
5005 offset;
5006
5007 /*
5008 Pixels are accessed directly from memory.
5009 */
5010 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5011 nexus_info->region.x;
5012 nexus_info->pixels=cache_info->pixels+offset;
5013 nexus_info->indexes=(IndexPacket *) NULL;
5014 if (cache_info->active_index_channel != MagickFalse)
5015 nexus_info->indexes=cache_info->indexes+offset;
5016 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00005017 }
5018 }
5019 /*
5020 Pixels are stored in a cache region until they are synced to the cache.
5021 */
5022 number_pixels=(MagickSizeType) nexus_info->region.width*
5023 nexus_info->region.height;
5024 length=number_pixels*sizeof(PixelPacket);
5025 if (cache_info->active_index_channel != MagickFalse)
5026 length+=number_pixels*sizeof(IndexPacket);
5027 if (nexus_info->cache == (PixelPacket *) NULL)
5028 {
5029 nexus_info->length=length;
5030 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5031 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005032 {
5033 nexus_info->length=0;
5034 return((PixelPacket *) NULL);
5035 }
cristy3ed852e2009-09-05 21:47:34 +00005036 }
5037 else
5038 if (nexus_info->length != length)
5039 {
5040 RelinquishCacheNexusPixels(nexus_info);
5041 nexus_info->length=length;
5042 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5043 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005044 {
5045 nexus_info->length=0;
5046 return((PixelPacket *) NULL);
5047 }
cristy3ed852e2009-09-05 21:47:34 +00005048 }
5049 nexus_info->pixels=nexus_info->cache;
5050 nexus_info->indexes=(IndexPacket *) NULL;
5051 if (cache_info->active_index_channel != MagickFalse)
5052 nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
5053 return(nexus_info->pixels);
5054}
5055
5056/*
5057%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5058% %
5059% %
5060% %
5061% 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 %
5062% %
5063% %
5064% %
5065%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5066%
5067% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5068% pixel cache and returns the previous setting. A virtual pixel is any pixel
5069% access that is outside the boundaries of the image cache.
5070%
5071% The format of the SetPixelCacheVirtualMethod() method is:
5072%
5073% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5074% const VirtualPixelMethod virtual_pixel_method)
5075%
5076% A description of each parameter follows:
5077%
5078% o image: the image.
5079%
5080% o virtual_pixel_method: choose the type of virtual pixel.
5081%
5082*/
5083MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5084 const VirtualPixelMethod virtual_pixel_method)
5085{
5086 CacheInfo
5087 *cache_info;
5088
5089 VirtualPixelMethod
5090 method;
5091
5092 assert(image != (Image *) NULL);
5093 assert(image->signature == MagickSignature);
5094 if (image->debug != MagickFalse)
5095 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5096 assert(image->cache != (Cache) NULL);
5097 cache_info=(CacheInfo *) image->cache;
5098 assert(cache_info->signature == MagickSignature);
5099 method=cache_info->virtual_pixel_method;
5100 cache_info->virtual_pixel_method=virtual_pixel_method;
5101 return(method);
5102}
5103
5104/*
5105%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5106% %
5107% %
5108% %
5109+ 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 %
5110% %
5111% %
5112% %
5113%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5114%
5115% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5116% in-memory or disk cache. The method returns MagickTrue if the pixel region
5117% is synced, otherwise MagickFalse.
5118%
5119% The format of the SyncAuthenticPixelCacheNexus() method is:
5120%
5121% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5122% NexusInfo *nexus_info,ExceptionInfo *exception)
5123%
5124% A description of each parameter follows:
5125%
5126% o image: the image.
5127%
5128% o nexus_info: the cache nexus to sync.
5129%
5130% o exception: return any errors or warnings in this structure.
5131%
5132*/
5133MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5134 NexusInfo *nexus_info,ExceptionInfo *exception)
5135{
5136 CacheInfo
5137 *cache_info;
5138
5139 MagickBooleanType
5140 status;
5141
5142 /*
5143 Transfer pixels to the cache.
5144 */
5145 assert(image != (Image *) NULL);
5146 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005147 if (image->cache == (Cache) NULL)
5148 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5149 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005150 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005151 if (cache_info->type == UndefinedCache)
5152 return(MagickFalse);
5153 if ((image->clip_mask != (Image *) NULL) &&
5154 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5155 return(MagickFalse);
5156 if ((image->mask != (Image *) NULL) &&
5157 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5158 return(MagickFalse);
5159 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5160 return(MagickTrue);
5161 assert(cache_info->signature == MagickSignature);
5162 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5163 if ((cache_info->active_index_channel != MagickFalse) &&
5164 (WritePixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse))
5165 return(MagickFalse);
5166 return(status);
5167}
5168
5169/*
5170%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5171% %
5172% %
5173% %
5174+ S y n c A u t h e n t i c P i x e l C a c h e %
5175% %
5176% %
5177% %
5178%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5179%
5180% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5181% or disk cache. The method returns MagickTrue if the pixel region is synced,
5182% otherwise MagickFalse.
5183%
5184% The format of the SyncAuthenticPixelsCache() method is:
5185%
5186% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5187% ExceptionInfo *exception)
5188%
5189% A description of each parameter follows:
5190%
5191% o image: the image.
5192%
5193% o exception: return any errors or warnings in this structure.
5194%
5195*/
5196static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5197 ExceptionInfo *exception)
5198{
5199 CacheInfo
5200 *cache_info;
5201
cristy5c9e6f22010-09-17 17:31:01 +00005202 const int
5203 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005204
cristye7cc7cf2010-09-21 13:26:47 +00005205 assert(image != (Image *) NULL);
5206 assert(image->signature == MagickSignature);
5207 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005208 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005209 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005210 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00005211 return(SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5212 exception));
cristy3ed852e2009-09-05 21:47:34 +00005213}
5214
5215/*
5216%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5217% %
5218% %
5219% %
5220% S y n c A u t h e n t i c P i x e l s %
5221% %
5222% %
5223% %
5224%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5225%
5226% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5227% The method returns MagickTrue if the pixel region is flushed, otherwise
5228% MagickFalse.
5229%
5230% The format of the SyncAuthenticPixels() method is:
5231%
5232% MagickBooleanType SyncAuthenticPixels(Image *image,
5233% ExceptionInfo *exception)
5234%
5235% A description of each parameter follows:
5236%
5237% o image: the image.
5238%
5239% o exception: return any errors or warnings in this structure.
5240%
5241*/
5242MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5243 ExceptionInfo *exception)
5244{
5245 CacheInfo
5246 *cache_info;
5247
cristy2036f5c2010-09-19 21:18:17 +00005248 const int
5249 id = GetOpenMPThreadId();
5250
cristy3ed852e2009-09-05 21:47:34 +00005251 assert(image != (Image *) NULL);
5252 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005253 assert(image->cache != (Cache) NULL);
5254 cache_info=(CacheInfo *) image->cache;
5255 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005256 if (cache_info->methods.sync_authentic_pixels_handler !=
5257 (SyncAuthenticPixelsHandler) NULL)
5258 return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
cristy2036f5c2010-09-19 21:18:17 +00005259 assert(id < (int) cache_info->number_threads);
5260 return(SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5261 exception));
cristy3ed852e2009-09-05 21:47:34 +00005262}
5263
5264/*
5265%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5266% %
5267% %
5268% %
5269+ W r i t e P i x e l C a c h e I n d e x e s %
5270% %
5271% %
5272% %
5273%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5274%
5275% WritePixelCacheIndexes() writes the colormap indexes to the specified
5276% region of the pixel cache.
5277%
5278% The format of the WritePixelCacheIndexes() method is:
5279%
5280% MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5281% NexusInfo *nexus_info,ExceptionInfo *exception)
5282%
5283% A description of each parameter follows:
5284%
5285% o cache_info: the pixel cache.
5286%
5287% o nexus_info: the cache nexus to write the colormap indexes.
5288%
5289% o exception: return any errors or warnings in this structure.
5290%
5291*/
5292static MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5293 NexusInfo *nexus_info,ExceptionInfo *exception)
5294{
5295 MagickOffsetType
5296 count,
5297 offset;
5298
5299 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005300 extent,
5301 length;
cristy3ed852e2009-09-05 21:47:34 +00005302
5303 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005304 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005305
cristybb503372010-05-27 20:51:26 +00005306 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005307 y;
5308
cristybb503372010-05-27 20:51:26 +00005309 size_t
cristy3ed852e2009-09-05 21:47:34 +00005310 rows;
5311
cristy3ed852e2009-09-05 21:47:34 +00005312 if (cache_info->active_index_channel == MagickFalse)
5313 return(MagickFalse);
5314 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5315 return(MagickTrue);
5316 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5317 nexus_info->region.x;
5318 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
5319 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005320 extent=(MagickSizeType) length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005321 p=nexus_info->indexes;
5322 switch (cache_info->type)
5323 {
5324 case MemoryCache:
5325 case MapCache:
5326 {
5327 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005328 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005329
5330 /*
5331 Write indexes to memory.
5332 */
cristydd341db2010-03-04 19:06:38 +00005333 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005334 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005335 {
cristy48078b12010-09-23 17:11:01 +00005336 length=extent;
cristydd341db2010-03-04 19:06:38 +00005337 rows=1UL;
5338 }
cristy3ed852e2009-09-05 21:47:34 +00005339 q=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00005340 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005341 {
cristy8f036fe2010-09-18 02:02:00 +00005342 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00005343 p+=nexus_info->region.width;
5344 q+=cache_info->columns;
5345 }
5346 break;
5347 }
5348 case DiskCache:
5349 {
5350 /*
5351 Write indexes to disk.
5352 */
5353 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5354 {
5355 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5356 cache_info->cache_filename);
5357 return(MagickFalse);
5358 }
cristydd341db2010-03-04 19:06:38 +00005359 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005360 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005361 {
cristy48078b12010-09-23 17:11:01 +00005362 length=extent;
cristydd341db2010-03-04 19:06:38 +00005363 rows=1UL;
5364 }
cristy48078b12010-09-23 17:11:01 +00005365 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005366 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005367 {
cristy48078b12010-09-23 17:11:01 +00005368 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5369 sizeof(PixelPacket)+offset*sizeof(*p),length,(const unsigned char *)
5370 p);
cristy3ed852e2009-09-05 21:47:34 +00005371 if ((MagickSizeType) count < length)
5372 break;
5373 p+=nexus_info->region.width;
5374 offset+=cache_info->columns;
5375 }
cristybb503372010-05-27 20:51:26 +00005376 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005377 {
5378 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5379 cache_info->cache_filename);
5380 return(MagickFalse);
5381 }
5382 break;
5383 }
5384 default:
5385 break;
5386 }
5387 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005388 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005389 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005390 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005391 nexus_info->region.width,(double) nexus_info->region.height,(double)
5392 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005393 return(MagickTrue);
5394}
5395
5396/*
5397%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5398% %
5399% %
5400% %
5401+ W r i t e C a c h e P i x e l s %
5402% %
5403% %
5404% %
5405%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5406%
5407% WritePixelCachePixels() writes image pixels to the specified region of the
5408% pixel cache.
5409%
5410% The format of the WritePixelCachePixels() method is:
5411%
5412% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5413% NexusInfo *nexus_info,ExceptionInfo *exception)
5414%
5415% A description of each parameter follows:
5416%
5417% o cache_info: the pixel cache.
5418%
5419% o nexus_info: the cache nexus to write the pixels.
5420%
5421% o exception: return any errors or warnings in this structure.
5422%
5423*/
5424static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5425 NexusInfo *nexus_info,ExceptionInfo *exception)
5426{
5427 MagickOffsetType
5428 count,
5429 offset;
5430
5431 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005432 extent,
5433 length;
cristy3ed852e2009-09-05 21:47:34 +00005434
cristy3ed852e2009-09-05 21:47:34 +00005435 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005436 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005437
cristybb503372010-05-27 20:51:26 +00005438 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005439 y;
5440
cristybb503372010-05-27 20:51:26 +00005441 size_t
cristy3ed852e2009-09-05 21:47:34 +00005442 rows;
5443
cristy3ed852e2009-09-05 21:47:34 +00005444 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5445 return(MagickTrue);
5446 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5447 nexus_info->region.x;
5448 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
5449 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005450 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005451 p=nexus_info->pixels;
5452 switch (cache_info->type)
5453 {
5454 case MemoryCache:
5455 case MapCache:
5456 {
5457 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005458 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005459
5460 /*
5461 Write pixels to memory.
5462 */
cristydd341db2010-03-04 19:06:38 +00005463 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005464 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005465 {
cristy48078b12010-09-23 17:11:01 +00005466 length=extent;
cristydd341db2010-03-04 19:06:38 +00005467 rows=1UL;
5468 }
cristy3ed852e2009-09-05 21:47:34 +00005469 q=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00005470 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005471 {
cristy8f036fe2010-09-18 02:02:00 +00005472 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00005473 p+=nexus_info->region.width;
5474 q+=cache_info->columns;
5475 }
5476 break;
5477 }
5478 case DiskCache:
5479 {
5480 /*
5481 Write pixels to disk.
5482 */
5483 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5484 {
5485 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5486 cache_info->cache_filename);
5487 return(MagickFalse);
5488 }
cristydd341db2010-03-04 19:06:38 +00005489 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005490 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005491 {
cristy48078b12010-09-23 17:11:01 +00005492 length=extent;
cristydd341db2010-03-04 19:06:38 +00005493 rows=1UL;
5494 }
cristybb503372010-05-27 20:51:26 +00005495 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005496 {
5497 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5498 sizeof(*p),length,(const unsigned char *) p);
5499 if ((MagickSizeType) count < length)
5500 break;
5501 p+=nexus_info->region.width;
5502 offset+=cache_info->columns;
5503 }
cristybb503372010-05-27 20:51:26 +00005504 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005505 {
5506 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5507 cache_info->cache_filename);
5508 return(MagickFalse);
5509 }
5510 break;
5511 }
5512 default:
5513 break;
5514 }
5515 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005516 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005517 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005518 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005519 nexus_info->region.width,(double) nexus_info->region.height,(double)
5520 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005521 return(MagickTrue);
5522}