blob: 826e6af5a7199228dbe5772e60442d0143bf6450 [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% %
cristy7e41fe82010-12-04 23:12:08 +000020% Copyright 1999-2011 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);
cristy7f317702011-02-18 20:40:28 +0000694 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000695 {
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,
cristy2c38b272011-02-18 23:25:33 +0000708 (MagickSizeType) SSIZE_MAX),offset+i);
cristy3ed852e2009-09-05 21:47:34 +0000709#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);
cristy7f317702011-02-18 20:40:28 +0000738 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000739 {
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,
cristy2c38b272011-02-18 23:25:33 +0000752 (MagickSizeType) SSIZE_MAX),offset+i);
cristy3ed852e2009-09-05 21:47:34 +0000753#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*
cristye3fe0242011-02-19 14:37:09 +0000827 sizeof(*pixels);
cristy3ed852e2009-09-05 21:47:34 +0000828 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
cristye3fe0242011-02-19 14:37:09 +0000829 sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +0000830 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000831 {
cristy3ed852e2009-09-05 21:47:34 +0000832 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
833 length,(unsigned char *) indexes);
834 if ((MagickSizeType) count != length)
835 break;
cristy3ed852e2009-09-05 21:47:34 +0000836 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
837 (unsigned char *) indexes);
838 if ((MagickSizeType) count != length)
839 break;
cristye3fe0242011-02-19 14:37:09 +0000840 source_offset+=cache_info->columns*sizeof(*indexes);
841 offset+=clone_info->columns*sizeof(*indexes);
cristy3ed852e2009-09-05 21:47:34 +0000842 }
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*
cristye3fe0242011-02-19 14:37:09 +0000855 sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +0000856 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000857 {
cristy3ed852e2009-09-05 21:47:34 +0000858 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
859 length,(unsigned char *) indexes);
860 if ((MagickSizeType) count != length)
861 break;
cristye3fe0242011-02-19 14:37:09 +0000862 offset+=clone_info->columns*sizeof(*indexes);
cristy3ed852e2009-09-05 21:47:34 +0000863 }
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);
cristye3fe0242011-02-19 14:37:09 +0000887 source_offset=0;
888 offset=0;
cristybb503372010-05-27 20:51:26 +0000889 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000890 {
cristy3ed852e2009-09-05 21:47:34 +0000891 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
892 length,(unsigned char *) pixels);
893 if ((MagickSizeType) count != length)
894 break;
cristy3ed852e2009-09-05 21:47:34 +0000895 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
896 (unsigned char *) pixels);
897 if ((MagickSizeType) count != length)
898 break;
cristye3fe0242011-02-19 14:37:09 +0000899 source_offset+=cache_info->columns*sizeof(*pixels);
900 offset+=clone_info->columns*sizeof(*pixels);
cristy3ed852e2009-09-05 21:47:34 +0000901 }
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 {
cristy3ed852e2009-09-05 21:47:34 +0000911 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
912 (void) ResetMagickMemory(pixels,0,(size_t) length);
cristye3fe0242011-02-19 14:37:09 +0000913 offset=(MagickOffsetType) columns*sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +0000914 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000915 {
cristy3ed852e2009-09-05 21:47:34 +0000916 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
917 (unsigned char *) pixels);
918 if ((MagickSizeType) count != length)
919 break;
cristye3fe0242011-02-19 14:37:09 +0000920 offset+=clone_info->columns*sizeof(*pixels);
cristy3ed852e2009-09-05 21:47:34 +0000921 }
cristybb503372010-05-27 20:51:26 +0000922 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000923 {
924 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
925 ThrowFileException(exception,CacheError,"UnableToCloneCache",
926 cache_info->cache_filename);
927 return(MagickFalse);
928 }
929 }
930 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
931 return(MagickTrue);
932}
933
934static MagickBooleanType CloneDiskToMemoryPixelCache(CacheInfo *clone_info,
935 CacheInfo *cache_info,ExceptionInfo *exception)
936{
937 MagickOffsetType
938 count,
939 offset;
940
941 MagickSizeType
942 length;
943
cristy3ed852e2009-09-05 21:47:34 +0000944 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000945 *restrict pixels,
946 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000947
cristye076a6e2010-08-15 19:59:43 +0000948 register ssize_t
949 y;
950
cristybb503372010-05-27 20:51:26 +0000951 size_t
cristy3ed852e2009-09-05 21:47:34 +0000952 columns,
953 rows;
954
955 if (cache_info->debug != MagickFalse)
956 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
957 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
958 {
959 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
960 cache_info->cache_filename);
961 return(MagickFalse);
962 }
cristybb503372010-05-27 20:51:26 +0000963 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
964 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +0000965 if ((clone_info->active_index_channel != MagickFalse) &&
966 (cache_info->active_index_channel != MagickFalse))
967 {
968 register IndexPacket
969 *indexes,
970 *q;
971
972 /*
973 Clone cache indexes.
974 */
975 length=MagickMax(clone_info->columns,cache_info->columns)*
976 sizeof(*indexes);
977 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
978 if (indexes == (IndexPacket *) NULL)
979 {
980 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
981 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
982 return(MagickFalse);
983 }
984 (void) ResetMagickMemory(indexes,0,(size_t) length);
985 length=columns*sizeof(IndexPacket);
986 offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
cristye3fe0242011-02-19 14:37:09 +0000987 sizeof(*pixels);
988 q=clone_info->indexes;
cristybb503372010-05-27 20:51:26 +0000989 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000990 {
cristy3ed852e2009-09-05 21:47:34 +0000991 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,
992 length,(unsigned char *) indexes);
993 if ((MagickSizeType) count != length)
994 break;
cristy8f036fe2010-09-18 02:02:00 +0000995 (void) memcpy(q,indexes,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +0000996 if ((MagickSizeType) count != length)
997 break;
cristye3fe0242011-02-19 14:37:09 +0000998 offset+=cache_info->columns*sizeof(*indexes);
999 q+=clone_info->columns;
cristy3ed852e2009-09-05 21:47:34 +00001000 }
cristybb503372010-05-27 20:51:26 +00001001 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001002 {
1003 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1004 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1005 cache_info->cache_filename);
1006 return(MagickFalse);
1007 }
1008 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1009 }
1010 /*
1011 Clone cache pixels.
1012 */
1013 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1014 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1015 if (pixels == (PixelPacket *) NULL)
1016 {
1017 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1018 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1019 return(MagickFalse);
1020 }
1021 (void) ResetMagickMemory(pixels,0,(size_t) length);
1022 length=columns*sizeof(*pixels);
cristye3fe0242011-02-19 14:37:09 +00001023 offset=0;
1024 q=clone_info->pixels;
cristybb503372010-05-27 20:51:26 +00001025 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001026 {
cristy3ed852e2009-09-05 21:47:34 +00001027 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,length,
1028 (unsigned char *) pixels);
1029 if ((MagickSizeType) count != length)
1030 break;
cristy8f036fe2010-09-18 02:02:00 +00001031 (void) memcpy(q,pixels,(size_t) length);
cristye3fe0242011-02-19 14:37:09 +00001032 offset+=cache_info->columns*sizeof(*pixels);
1033 q+=clone_info->columns;
cristy3ed852e2009-09-05 21:47:34 +00001034 }
cristybb503372010-05-27 20:51:26 +00001035 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001036 {
1037 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1038 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1039 cache_info->cache_filename);
1040 return(MagickFalse);
1041 }
1042 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1043 return(MagickTrue);
1044}
1045
1046static MagickBooleanType CloneMemoryToDiskPixelCache(CacheInfo *clone_info,
1047 CacheInfo *cache_info,ExceptionInfo *exception)
1048{
1049 MagickOffsetType
1050 count,
1051 offset;
1052
1053 MagickSizeType
1054 length;
1055
cristy3ed852e2009-09-05 21:47:34 +00001056 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001057 *restrict p,
1058 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +00001059
cristye076a6e2010-08-15 19:59:43 +00001060 register ssize_t
1061 y;
1062
cristybb503372010-05-27 20:51:26 +00001063 size_t
cristy3ed852e2009-09-05 21:47:34 +00001064 columns,
1065 rows;
1066
1067 if (cache_info->debug != MagickFalse)
1068 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
1069 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
1070 {
1071 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1072 clone_info->cache_filename);
1073 return(MagickFalse);
1074 }
cristybb503372010-05-27 20:51:26 +00001075 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1076 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001077 if ((clone_info->active_index_channel != MagickFalse) &&
1078 (cache_info->active_index_channel != MagickFalse))
1079 {
1080 register IndexPacket
1081 *p,
1082 *indexes;
1083
1084 /*
1085 Clone cache indexes.
1086 */
1087 length=MagickMax(clone_info->columns,cache_info->columns)*
1088 sizeof(*indexes);
1089 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
1090 if (indexes == (IndexPacket *) NULL)
1091 {
1092 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1093 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1094 return(MagickFalse);
1095 }
1096 (void) ResetMagickMemory(indexes,0,(size_t) length);
1097 length=columns*sizeof(*indexes);
cristye3fe0242011-02-19 14:37:09 +00001098 p=cache_info->indexes;
cristy3ed852e2009-09-05 21:47:34 +00001099 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
cristye3fe0242011-02-19 14:37:09 +00001100 sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +00001101 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001102 {
cristy8f036fe2010-09-18 02:02:00 +00001103 (void) memcpy(indexes,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00001104 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1105 (unsigned char *) indexes);
1106 if ((MagickSizeType) count != length)
1107 break;
cristye3fe0242011-02-19 14:37:09 +00001108 p+=cache_info->columns;
1109 offset+=clone_info->columns*sizeof(*indexes);
cristy3ed852e2009-09-05 21:47:34 +00001110 }
cristybb503372010-05-27 20:51:26 +00001111 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001112 {
1113 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1114 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1115 cache_info->cache_filename);
1116 return(MagickFalse);
1117 }
1118 if (clone_info->columns > cache_info->columns)
1119 {
1120 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
1121 (void) ResetMagickMemory(indexes,0,(size_t) length);
1122 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
cristye3fe0242011-02-19 14:37:09 +00001123 sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +00001124 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001125 {
cristy3ed852e2009-09-05 21:47:34 +00001126 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
1127 length,(unsigned char *) indexes);
1128 if ((MagickSizeType) count != length)
1129 break;
cristye3fe0242011-02-19 14:37:09 +00001130 offset+=clone_info->columns*sizeof(*indexes);
cristy3ed852e2009-09-05 21:47:34 +00001131 }
cristybb503372010-05-27 20:51:26 +00001132 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001133 {
1134 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1135 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1136 cache_info->cache_filename);
1137 return(MagickFalse);
1138 }
1139 }
1140 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1141 }
1142 /*
1143 Clone cache pixels.
1144 */
1145 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1146 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1147 if (pixels == (PixelPacket *) NULL)
1148 {
1149 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1150 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1151 return(MagickFalse);
1152 }
1153 (void) ResetMagickMemory(pixels,0,(size_t) length);
1154 length=columns*sizeof(*pixels);
cristye3fe0242011-02-19 14:37:09 +00001155 p=cache_info->pixels;
1156 offset=0;
cristybb503372010-05-27 20:51:26 +00001157 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001158 {
cristy8f036fe2010-09-18 02:02:00 +00001159 (void) memcpy(pixels,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00001160 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1161 (unsigned char *) pixels);
1162 if ((MagickSizeType) count != length)
1163 break;
cristye3fe0242011-02-19 14:37:09 +00001164 p+=cache_info->columns;
1165 offset+=clone_info->columns*sizeof(*pixels);
cristy3ed852e2009-09-05 21:47:34 +00001166 }
cristybb503372010-05-27 20:51:26 +00001167 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001168 {
1169 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1170 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1171 cache_info->cache_filename);
1172 return(MagickFalse);
1173 }
1174 if (clone_info->columns > cache_info->columns)
1175 {
cristy3ed852e2009-09-05 21:47:34 +00001176 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1177 (void) ResetMagickMemory(pixels,0,(size_t) length);
cristye3fe0242011-02-19 14:37:09 +00001178 offset=(MagickOffsetType) columns*sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +00001179 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001180 {
cristy3ed852e2009-09-05 21:47:34 +00001181 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1182 (unsigned char *) pixels);
1183 if ((MagickSizeType) count != length)
1184 break;
cristye3fe0242011-02-19 14:37:09 +00001185 offset+=clone_info->columns*sizeof(*pixels);
cristy3ed852e2009-09-05 21:47:34 +00001186 }
cristybb503372010-05-27 20:51:26 +00001187 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001188 {
1189 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1190 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1191 cache_info->cache_filename);
1192 return(MagickFalse);
1193 }
1194 }
1195 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1196 return(MagickTrue);
1197}
1198
1199static MagickBooleanType CloneMemoryToMemoryPixelCache(CacheInfo *clone_info,
1200 CacheInfo *cache_info,ExceptionInfo *magick_unused(exception))
1201{
cristy3ed852e2009-09-05 21:47:34 +00001202 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001203 *restrict pixels,
1204 *restrict source_pixels;
cristy3ed852e2009-09-05 21:47:34 +00001205
cristye076a6e2010-08-15 19:59:43 +00001206 register ssize_t
1207 y;
cristy3ed852e2009-09-05 21:47:34 +00001208
cristybb503372010-05-27 20:51:26 +00001209 size_t
cristy3ed852e2009-09-05 21:47:34 +00001210 columns,
cristye076a6e2010-08-15 19:59:43 +00001211 length,
cristy3ed852e2009-09-05 21:47:34 +00001212 rows;
1213
1214 if (cache_info->debug != MagickFalse)
1215 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
cristybb503372010-05-27 20:51:26 +00001216 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1217 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001218 if ((clone_info->active_index_channel != MagickFalse) &&
1219 (cache_info->active_index_channel != MagickFalse))
1220 {
1221 register IndexPacket
1222 *indexes,
1223 *source_indexes;
1224
1225 /*
1226 Clone cache indexes.
1227 */
1228 length=columns*sizeof(*indexes);
1229 if (clone_info->columns == cache_info->columns)
cristy8f036fe2010-09-18 02:02:00 +00001230 (void) memcpy(clone_info->indexes,cache_info->indexes,length*rows);
cristy3ed852e2009-09-05 21:47:34 +00001231 else
1232 {
cristye3fe0242011-02-19 14:37:09 +00001233 source_indexes=cache_info->indexes;
1234 indexes=clone_info->indexes;
cristybb503372010-05-27 20:51:26 +00001235 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001236 {
cristy8f036fe2010-09-18 02:02:00 +00001237 (void) memcpy(indexes,source_indexes,length);
cristye3fe0242011-02-19 14:37:09 +00001238 source_indexes+=cache_info->columns;
1239 indexes+=clone_info->columns;
cristy3ed852e2009-09-05 21:47:34 +00001240 }
1241 if (clone_info->columns > cache_info->columns)
1242 {
cristye3fe0242011-02-19 14:37:09 +00001243 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
1244 indexes=clone_info->indexes+cache_info->columns;
cristybb503372010-05-27 20:51:26 +00001245 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001246 {
cristy3ed852e2009-09-05 21:47:34 +00001247 (void) ResetMagickMemory(indexes,0,length);
cristye3fe0242011-02-19 14:37:09 +00001248 indexes+=clone_info->columns;
cristy3ed852e2009-09-05 21:47:34 +00001249 }
1250 }
1251 }
1252 }
1253 /*
1254 Clone cache pixels.
1255 */
1256 length=columns*sizeof(*pixels);
1257 if (clone_info->columns == cache_info->columns)
cristy8f036fe2010-09-18 02:02:00 +00001258 (void) memcpy(clone_info->pixels,cache_info->pixels,length*rows);
cristy3ed852e2009-09-05 21:47:34 +00001259 else
1260 {
cristye3fe0242011-02-19 14:37:09 +00001261 source_pixels=cache_info->pixels;
1262 pixels=clone_info->pixels;
cristybb503372010-05-27 20:51:26 +00001263 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001264 {
cristy8f036fe2010-09-18 02:02:00 +00001265 (void) memcpy(pixels,source_pixels,length);
cristye3fe0242011-02-19 14:37:09 +00001266 source_pixels+=cache_info->columns;
1267 pixels+=clone_info->columns;
cristy3ed852e2009-09-05 21:47:34 +00001268 }
1269 if (clone_info->columns > cache_info->columns)
1270 {
1271 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
cristye3fe0242011-02-19 14:37:09 +00001272 pixels=clone_info->pixels+cache_info->columns;
cristybb503372010-05-27 20:51:26 +00001273 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001274 {
cristy3ed852e2009-09-05 21:47:34 +00001275 (void) ResetMagickMemory(pixels,0,length);
cristye3fe0242011-02-19 14:37:09 +00001276 pixels+=clone_info->columns;
cristy3ed852e2009-09-05 21:47:34 +00001277 }
1278 }
1279 }
1280 return(MagickTrue);
1281}
1282
1283static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1284 CacheInfo *cache_info,ExceptionInfo *exception)
1285{
cristy5a7fbfb2010-11-06 16:10:59 +00001286 if (cache_info->type == PingCache)
1287 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001288 if ((clone_info->type != DiskCache) && (cache_info->type != DiskCache))
1289 return(CloneMemoryToMemoryPixelCache(clone_info,cache_info,exception));
1290 if ((clone_info->type == DiskCache) && (cache_info->type == DiskCache))
1291 return(CloneDiskToDiskPixelCache(clone_info,cache_info,exception));
1292 if (cache_info->type == DiskCache)
1293 return(CloneDiskToMemoryPixelCache(clone_info,cache_info,exception));
1294 return(CloneMemoryToDiskPixelCache(clone_info,cache_info,exception));
1295}
1296
1297/*
1298%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1299% %
1300% %
1301% %
1302+ C l o n e P i x e l C a c h e M e t h o d s %
1303% %
1304% %
1305% %
1306%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1307%
1308% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1309% another.
1310%
1311% The format of the ClonePixelCacheMethods() method is:
1312%
1313% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1314%
1315% A description of each parameter follows:
1316%
1317% o clone: Specifies a pointer to a Cache structure.
1318%
1319% o cache: the pixel cache.
1320%
1321*/
1322MagickExport void ClonePixelCacheMethods(Cache clone,const Cache cache)
1323{
1324 CacheInfo
1325 *cache_info,
1326 *source_info;
1327
1328 assert(clone != (Cache) NULL);
1329 source_info=(CacheInfo *) clone;
1330 assert(source_info->signature == MagickSignature);
1331 if (source_info->debug != MagickFalse)
1332 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1333 source_info->filename);
1334 assert(cache != (Cache) NULL);
1335 cache_info=(CacheInfo *) cache;
1336 assert(cache_info->signature == MagickSignature);
1337 source_info->methods=cache_info->methods;
1338}
1339
1340/*
1341%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1342% %
1343% %
1344% %
1345+ D e s t r o y I m a g e P i x e l C a c h e %
1346% %
1347% %
1348% %
1349%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1350%
1351% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1352%
1353% The format of the DestroyImagePixelCache() method is:
1354%
1355% void DestroyImagePixelCache(Image *image)
1356%
1357% A description of each parameter follows:
1358%
1359% o image: the image.
1360%
1361*/
1362static void DestroyImagePixelCache(Image *image)
1363{
1364 assert(image != (Image *) NULL);
1365 assert(image->signature == MagickSignature);
1366 if (image->debug != MagickFalse)
1367 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1368 if (image->cache == (void *) NULL)
1369 return;
1370 image->cache=DestroyPixelCache(image->cache);
1371}
1372
1373/*
1374%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1375% %
1376% %
1377% %
1378+ D e s t r o y I m a g e P i x e l s %
1379% %
1380% %
1381% %
1382%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1383%
1384% DestroyImagePixels() deallocates memory associated with the pixel cache.
1385%
1386% The format of the DestroyImagePixels() method is:
1387%
1388% void DestroyImagePixels(Image *image)
1389%
1390% A description of each parameter follows:
1391%
1392% o image: the image.
1393%
1394*/
1395MagickExport void DestroyImagePixels(Image *image)
1396{
1397 CacheInfo
1398 *cache_info;
1399
1400 assert(image != (const Image *) NULL);
1401 assert(image->signature == MagickSignature);
1402 if (image->debug != MagickFalse)
1403 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1404 assert(image->cache != (Cache) NULL);
1405 cache_info=(CacheInfo *) image->cache;
1406 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001407 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1408 {
1409 cache_info->methods.destroy_pixel_handler(image);
1410 return;
1411 }
cristy2036f5c2010-09-19 21:18:17 +00001412 image->cache=DestroyPixelCache(image->cache);
cristy3ed852e2009-09-05 21:47:34 +00001413}
1414
1415/*
1416%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1417% %
1418% %
1419% %
1420+ D e s t r o y P i x e l C a c h e %
1421% %
1422% %
1423% %
1424%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1425%
1426% DestroyPixelCache() deallocates memory associated with the pixel cache.
1427%
1428% The format of the DestroyPixelCache() method is:
1429%
1430% Cache DestroyPixelCache(Cache cache)
1431%
1432% A description of each parameter follows:
1433%
1434% o cache: the pixel cache.
1435%
1436*/
1437
1438static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1439{
1440 switch (cache_info->type)
1441 {
1442 case MemoryCache:
1443 {
1444 if (cache_info->mapped == MagickFalse)
1445 cache_info->pixels=(PixelPacket *) RelinquishMagickMemory(
1446 cache_info->pixels);
1447 else
1448 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,
1449 (size_t) cache_info->length);
1450 RelinquishMagickResource(MemoryResource,cache_info->length);
1451 break;
1452 }
1453 case MapCache:
1454 {
1455 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,(size_t)
1456 cache_info->length);
1457 RelinquishMagickResource(MapResource,cache_info->length);
1458 }
1459 case DiskCache:
1460 {
1461 if (cache_info->file != -1)
1462 (void) ClosePixelCacheOnDisk(cache_info);
1463 RelinquishMagickResource(DiskResource,cache_info->length);
1464 break;
1465 }
1466 default:
1467 break;
1468 }
1469 cache_info->type=UndefinedCache;
1470 cache_info->mapped=MagickFalse;
1471 cache_info->indexes=(IndexPacket *) NULL;
1472}
1473
1474MagickExport Cache DestroyPixelCache(Cache cache)
1475{
1476 CacheInfo
1477 *cache_info;
1478
cristy3ed852e2009-09-05 21:47:34 +00001479 assert(cache != (Cache) NULL);
1480 cache_info=(CacheInfo *) cache;
1481 assert(cache_info->signature == MagickSignature);
1482 if (cache_info->debug != MagickFalse)
1483 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1484 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001485 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001486 cache_info->reference_count--;
1487 if (cache_info->reference_count != 0)
1488 {
cristyf84a1932010-01-03 18:00:18 +00001489 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001490 return((Cache) NULL);
1491 }
cristyf84a1932010-01-03 18:00:18 +00001492 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001493 if (cache_resources != (SplayTreeInfo *) NULL)
1494 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
cristy5b8de732009-09-10 23:50:40 +00001495 if (cache_info->debug != MagickFalse)
1496 {
1497 char
1498 message[MaxTextExtent];
1499
1500 (void) FormatMagickString(message,MaxTextExtent,"destroy %s",
1501 cache_info->filename);
1502 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1503 }
cristyc2e1bdd2009-09-10 23:43:34 +00001504 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1505 (cache_info->type != DiskCache)))
1506 RelinquishPixelCachePixels(cache_info);
1507 else
1508 {
1509 RelinquishPixelCachePixels(cache_info);
1510 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1511 }
cristy3ed852e2009-09-05 21:47:34 +00001512 *cache_info->cache_filename='\0';
1513 if (cache_info->nexus_info != (NexusInfo **) NULL)
1514 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1515 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001516 if (cache_info->random_info != (RandomInfo *) NULL)
1517 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001518 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1519 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1520 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1521 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001522 cache_info->signature=(~MagickSignature);
cristyb41ee102010-10-04 16:46:15 +00001523 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001524 cache=(Cache) NULL;
1525 return(cache);
1526}
1527
1528/*
1529%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1530% %
1531% %
1532% %
1533+ D e s t r o y P i x e l C a c h e N e x u s %
1534% %
1535% %
1536% %
1537%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1538%
1539% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1540%
1541% The format of the DestroyPixelCacheNexus() method is:
1542%
1543% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001544% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001545%
1546% A description of each parameter follows:
1547%
1548% o nexus_info: the nexus to destroy.
1549%
1550% o number_threads: the number of nexus threads.
1551%
1552*/
1553
1554static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1555{
1556 if (nexus_info->mapped == MagickFalse)
1557 (void) RelinquishMagickMemory(nexus_info->cache);
1558 else
1559 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1560 nexus_info->cache=(PixelPacket *) NULL;
1561 nexus_info->pixels=(PixelPacket *) NULL;
1562 nexus_info->indexes=(IndexPacket *) NULL;
1563 nexus_info->length=0;
1564 nexus_info->mapped=MagickFalse;
1565}
1566
1567MagickExport NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001568 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001569{
cristybb503372010-05-27 20:51:26 +00001570 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001571 i;
1572
1573 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001574 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001575 {
1576 if (nexus_info[i]->cache != (PixelPacket *) NULL)
1577 RelinquishCacheNexusPixels(nexus_info[i]);
1578 nexus_info[i]->signature=(~MagickSignature);
1579 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
1580 }
cristyb41ee102010-10-04 16:46:15 +00001581 nexus_info=(NexusInfo **) RelinquishMagickMemory(nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00001582 return(nexus_info);
1583}
1584
1585/*
1586%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1587% %
1588% %
1589% %
cristy3ed852e2009-09-05 21:47:34 +00001590+ 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 %
1591% %
1592% %
1593% %
1594%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1595%
1596% GetAuthenticIndexesFromCache() returns the indexes associated with the last
1597% call to QueueAuthenticPixelsCache() or GetAuthenticPixelsCache().
1598%
1599% The format of the GetAuthenticIndexesFromCache() method is:
1600%
1601% IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1602%
1603% A description of each parameter follows:
1604%
1605% o image: the image.
1606%
1607*/
1608static IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1609{
1610 CacheInfo
1611 *cache_info;
1612
cristy5c9e6f22010-09-17 17:31:01 +00001613 const int
1614 id = GetOpenMPThreadId();
1615
cristye7cc7cf2010-09-21 13:26:47 +00001616 assert(image != (const Image *) NULL);
1617 assert(image->signature == MagickSignature);
1618 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001619 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001620 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001621 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001622 return(GetPixelCacheNexusIndexes(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001623}
1624
1625/*
1626%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1627% %
1628% %
1629% %
1630% G e t A u t h e n t i c I n d e x Q u e u e %
1631% %
1632% %
1633% %
1634%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1635%
1636% GetAuthenticIndexQueue() returns the authentic black channel or the colormap
1637% indexes associated with the last call to QueueAuthenticPixels() or
1638% GetVirtualPixels(). NULL is returned if the black channel or colormap
1639% indexes are not available.
1640%
1641% The format of the GetAuthenticIndexQueue() method is:
1642%
1643% IndexPacket *GetAuthenticIndexQueue(const Image *image)
1644%
1645% A description of each parameter follows:
1646%
1647% o image: the image.
1648%
1649*/
1650MagickExport IndexPacket *GetAuthenticIndexQueue(const Image *image)
1651{
1652 CacheInfo
1653 *cache_info;
1654
cristy2036f5c2010-09-19 21:18:17 +00001655 const int
1656 id = GetOpenMPThreadId();
1657
cristy3ed852e2009-09-05 21:47:34 +00001658 assert(image != (const Image *) NULL);
1659 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001660 assert(image->cache != (Cache) NULL);
1661 cache_info=(CacheInfo *) image->cache;
1662 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001663 if (cache_info->methods.get_authentic_indexes_from_handler !=
cristy3ed852e2009-09-05 21:47:34 +00001664 (GetAuthenticIndexesFromHandler) NULL)
cristyd317f372010-09-18 01:42:20 +00001665 return(cache_info->methods.get_authentic_indexes_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001666 assert(id < (int) cache_info->number_threads);
1667 return(GetPixelCacheNexusIndexes(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001668}
1669
1670/*
1671%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1672% %
1673% %
1674% %
1675+ 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 %
1676% %
1677% %
1678% %
1679%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1680%
1681% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1682% disk pixel cache as defined by the geometry parameters. A pointer to the
1683% pixels is returned if the pixels are transferred, otherwise a NULL is
1684% returned.
1685%
1686% The format of the GetAuthenticPixelCacheNexus() method is:
1687%
cristybb503372010-05-27 20:51:26 +00001688% PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1689% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001690% NexusInfo *nexus_info,ExceptionInfo *exception)
1691%
1692% A description of each parameter follows:
1693%
1694% o image: the image.
1695%
1696% o x,y,columns,rows: These values define the perimeter of a region of
1697% pixels.
1698%
1699% o nexus_info: the cache nexus to return.
1700%
1701% o exception: return any errors or warnings in this structure.
1702%
1703*/
1704
1705static inline MagickBooleanType IsNexusInCore(const CacheInfo *cache_info,
1706 NexusInfo *nexus_info)
1707{
1708 MagickOffsetType
1709 offset;
1710
cristy73724512010-04-12 14:43:14 +00001711 if (cache_info->type == PingCache)
1712 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001713 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1714 nexus_info->region.x;
cristy096bf2c2010-09-22 11:55:02 +00001715 return(nexus_info->pixels == (cache_info->pixels+offset) ? MagickTrue :
1716 MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +00001717}
1718
cristye076a6e2010-08-15 19:59:43 +00001719MagickExport PixelPacket *GetAuthenticPixelCacheNexus(Image *image,
1720 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001721 NexusInfo *nexus_info,ExceptionInfo *exception)
1722{
1723 CacheInfo
1724 *cache_info;
1725
1726 PixelPacket
1727 *pixels;
1728
1729 /*
1730 Transfer pixels from the cache.
1731 */
1732 assert(image != (Image *) NULL);
1733 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001734 pixels=QueueAuthenticNexus(image,x,y,columns,rows,nexus_info,exception);
1735 if (pixels == (PixelPacket *) NULL)
1736 return((PixelPacket *) NULL);
1737 cache_info=(CacheInfo *) image->cache;
1738 assert(cache_info->signature == MagickSignature);
1739 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
1740 return(pixels);
1741 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1742 return((PixelPacket *) NULL);
1743 if (cache_info->active_index_channel != MagickFalse)
1744 if (ReadPixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse)
1745 return((PixelPacket *) NULL);
1746 return(pixels);
1747}
1748
1749/*
1750%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1751% %
1752% %
1753% %
1754+ 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 %
1755% %
1756% %
1757% %
1758%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1759%
1760% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1761% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1762%
1763% The format of the GetAuthenticPixelsFromCache() method is:
1764%
1765% PixelPacket *GetAuthenticPixelsFromCache(const Image image)
1766%
1767% A description of each parameter follows:
1768%
1769% o image: the image.
1770%
1771*/
1772static PixelPacket *GetAuthenticPixelsFromCache(const Image *image)
1773{
1774 CacheInfo
1775 *cache_info;
1776
cristy5c9e6f22010-09-17 17:31:01 +00001777 const int
1778 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001779
cristye7cc7cf2010-09-21 13:26:47 +00001780 assert(image != (const Image *) NULL);
1781 assert(image->signature == MagickSignature);
1782 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001783 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001784 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001785 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001786 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001787}
1788
1789/*
1790%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1791% %
1792% %
1793% %
1794% G e t A u t h e n t i c P i x e l Q u e u e %
1795% %
1796% %
1797% %
1798%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1799%
1800% GetAuthenticPixelQueue() returns the authentic pixels associated with the
1801% last call to QueueAuthenticPixels() or GetAuthenticPixels().
1802%
1803% The format of the GetAuthenticPixelQueue() method is:
1804%
1805% PixelPacket *GetAuthenticPixelQueue(const Image image)
1806%
1807% A description of each parameter follows:
1808%
1809% o image: the image.
1810%
1811*/
1812MagickExport PixelPacket *GetAuthenticPixelQueue(const Image *image)
1813{
1814 CacheInfo
1815 *cache_info;
1816
cristy2036f5c2010-09-19 21:18:17 +00001817 const int
1818 id = GetOpenMPThreadId();
1819
cristy3ed852e2009-09-05 21:47:34 +00001820 assert(image != (const Image *) NULL);
1821 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001822 assert(image->cache != (Cache) NULL);
1823 cache_info=(CacheInfo *) image->cache;
1824 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001825 if (cache_info->methods.get_authentic_pixels_from_handler !=
1826 (GetAuthenticPixelsFromHandler) NULL)
1827 return(cache_info->methods.get_authentic_pixels_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001828 assert(id < (int) cache_info->number_threads);
1829 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001830}
1831
1832/*
1833%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1834% %
1835% %
1836% %
1837% G e t A u t h e n t i c P i x e l s %
1838% %
1839% %
1840% %
1841%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1842%
1843% GetAuthenticPixels() obtains a pixel region for read/write access. If the
1844% region is successfully accessed, a pointer to a PixelPacket array
1845% representing the region is returned, otherwise NULL is returned.
1846%
1847% The returned pointer may point to a temporary working copy of the pixels
1848% or it may point to the original pixels in memory. Performance is maximized
1849% if the selected region is part of one row, or one or more full rows, since
1850% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001851% if the image is in memory, or in a memory-mapped file. The returned pointer
1852% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001853%
1854% Pixels accessed via the returned pointer represent a simple array of type
1855% PixelPacket. If the image type is CMYK or if the storage class is
1856% PseduoClass, call GetAuthenticIndexQueue() after invoking
1857% GetAuthenticPixels() to obtain the black color component or colormap indexes
1858% (of type IndexPacket) corresponding to the region. Once the PixelPacket
1859% (and/or IndexPacket) array has been updated, the changes must be saved back
1860% to the underlying image using SyncAuthenticPixels() or they may be lost.
1861%
1862% The format of the GetAuthenticPixels() method is:
1863%
cristy5f959472010-05-27 22:19:46 +00001864% PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1865% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001866% ExceptionInfo *exception)
1867%
1868% A description of each parameter follows:
1869%
1870% o image: the image.
1871%
1872% o x,y,columns,rows: These values define the perimeter of a region of
1873% pixels.
1874%
1875% o exception: return any errors or warnings in this structure.
1876%
1877*/
cristybb503372010-05-27 20:51:26 +00001878MagickExport PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1879 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001880 ExceptionInfo *exception)
1881{
1882 CacheInfo
1883 *cache_info;
1884
cristy2036f5c2010-09-19 21:18:17 +00001885 const int
1886 id = GetOpenMPThreadId();
1887
cristy3ed852e2009-09-05 21:47:34 +00001888 assert(image != (Image *) NULL);
1889 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001890 assert(image->cache != (Cache) NULL);
1891 cache_info=(CacheInfo *) image->cache;
1892 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001893 if (cache_info->methods.get_authentic_pixels_handler !=
1894 (GetAuthenticPixelsHandler) NULL)
1895 return(cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1896 rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00001897 assert(id < (int) cache_info->number_threads);
1898 return(GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1899 cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00001900}
1901
1902/*
1903%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1904% %
1905% %
1906% %
1907+ G e t A u t h e n t i c P i x e l s C a c h e %
1908% %
1909% %
1910% %
1911%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1912%
1913% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1914% as defined by the geometry parameters. A pointer to the pixels is returned
1915% if the pixels are transferred, otherwise a NULL is returned.
1916%
1917% The format of the GetAuthenticPixelsCache() method is:
1918%
cristybb503372010-05-27 20:51:26 +00001919% PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1920% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001921% ExceptionInfo *exception)
1922%
1923% A description of each parameter follows:
1924%
1925% o image: the image.
1926%
1927% o x,y,columns,rows: These values define the perimeter of a region of
1928% pixels.
1929%
1930% o exception: return any errors or warnings in this structure.
1931%
1932*/
cristybb503372010-05-27 20:51:26 +00001933static PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1934 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001935 ExceptionInfo *exception)
1936{
1937 CacheInfo
1938 *cache_info;
1939
cristy5c9e6f22010-09-17 17:31:01 +00001940 const int
1941 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001942
cristye7cc7cf2010-09-21 13:26:47 +00001943 assert(image != (const Image *) NULL);
1944 assert(image->signature == MagickSignature);
1945 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00001946 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001947 if (cache_info == (Cache) NULL)
1948 return((PixelPacket *) NULL);
cristye7cc7cf2010-09-21 13:26:47 +00001949 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001950 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001951 return(GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1952 cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00001953}
1954
1955/*
1956%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1957% %
1958% %
1959% %
1960+ G e t I m a g e E x t e n t %
1961% %
1962% %
1963% %
1964%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1965%
1966% GetImageExtent() returns the extent of the pixels associated with the
1967% last call to QueueAuthenticPixels() or GetAuthenticPixels().
1968%
1969% The format of the GetImageExtent() method is:
1970%
1971% MagickSizeType GetImageExtent(const Image *image)
1972%
1973% A description of each parameter follows:
1974%
1975% o image: the image.
1976%
1977*/
1978MagickExport MagickSizeType GetImageExtent(const Image *image)
1979{
1980 CacheInfo
1981 *cache_info;
1982
cristy5c9e6f22010-09-17 17:31:01 +00001983 const int
1984 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001985
cristy3ed852e2009-09-05 21:47:34 +00001986 assert(image != (Image *) NULL);
1987 assert(image->signature == MagickSignature);
1988 if (image->debug != MagickFalse)
1989 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1990 assert(image->cache != (Cache) NULL);
1991 cache_info=(CacheInfo *) image->cache;
1992 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001993 assert(id < (int) cache_info->number_threads);
cristy2036f5c2010-09-19 21:18:17 +00001994 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001995}
1996
1997/*
1998%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1999% %
2000% %
2001% %
2002+ G e t I m a g e P i x e l C a c h e %
2003% %
2004% %
2005% %
2006%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2007%
2008% GetImagePixelCache() ensures that there is only a single reference to the
2009% pixel cache to be modified, updating the provided cache pointer to point to
2010% a clone of the original pixel cache if necessary.
2011%
2012% The format of the GetImagePixelCache method is:
2013%
2014% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2015% ExceptionInfo *exception)
2016%
2017% A description of each parameter follows:
2018%
2019% o image: the image.
2020%
2021% o clone: any value other than MagickFalse clones the cache pixels.
2022%
2023% o exception: return any errors or warnings in this structure.
2024%
2025*/
cristy3ed852e2009-09-05 21:47:34 +00002026static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
2027{
2028 CacheInfo
2029 *cache_info;
2030
2031 /*
2032 Does the image match the pixel cache morphology?
2033 */
2034 cache_info=(CacheInfo *) image->cache;
2035 if ((image->storage_class != cache_info->storage_class) ||
2036 (image->colorspace != cache_info->colorspace) ||
2037 (image->columns != cache_info->columns) ||
2038 (image->rows != cache_info->rows) ||
2039 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2040 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2041 return(MagickFalse);
2042 return(MagickTrue);
2043}
2044
cristy77ff0282010-09-13 00:51:10 +00002045static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2046 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002047{
2048 CacheInfo
2049 *cache_info;
2050
cristy3ed852e2009-09-05 21:47:34 +00002051 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00002052 destroy,
cristy3ed852e2009-09-05 21:47:34 +00002053 status;
2054
cristy50a10922010-02-15 18:35:25 +00002055 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00002056 cpu_throttle = 0,
2057 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00002058 time_limit = 0;
2059
cristy1ea34962010-07-01 19:49:21 +00002060 static time_t
cristya21afde2010-07-02 00:45:40 +00002061 cache_genesis = 0;
cristy1ea34962010-07-01 19:49:21 +00002062
cristyc4f9f132010-03-04 18:50:01 +00002063 status=MagickTrue;
2064 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00002065 if (cpu_throttle == 0)
2066 {
2067 char
2068 *limit;
2069
2070 /*
2071 Set CPU throttle in milleseconds.
2072 */
2073 cpu_throttle=MagickResourceInfinity;
2074 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2075 if (limit == (char *) NULL)
2076 limit=GetPolicyValue("throttle");
2077 if (limit != (char *) NULL)
2078 {
2079 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2080 limit=DestroyString(limit);
2081 }
2082 }
2083 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2084 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00002085 if (time_limit == 0)
2086 {
cristy6ebe97c2010-07-03 01:17:28 +00002087 /*
2088 Set the exire time in seconds.
2089 */
cristy1ea34962010-07-01 19:49:21 +00002090 time_limit=GetMagickResourceLimit(TimeResource);
cristya21afde2010-07-02 00:45:40 +00002091 cache_genesis=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00002092 }
2093 if ((time_limit != MagickResourceInfinity) &&
cristya21afde2010-07-02 00:45:40 +00002094 ((MagickSizeType) (time((time_t *) NULL)-cache_genesis) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00002095 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00002096 assert(image->cache != (Cache) NULL);
2097 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002098 destroy=MagickFalse;
cristyceb55ee2010-11-06 16:05:49 +00002099 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002100 {
cristyceb55ee2010-11-06 16:05:49 +00002101 LockSemaphoreInfo(cache_info->semaphore);
cristy4e6fa712010-11-06 16:06:12 +00002102 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002103 {
cristyceb55ee2010-11-06 16:05:49 +00002104 Image
2105 clone_image;
2106
2107 CacheInfo
2108 *clone_info;
2109
2110 /*
2111 Clone pixel cache.
2112 */
2113 clone_image=(*image);
2114 clone_image.semaphore=AllocateSemaphoreInfo();
2115 clone_image.reference_count=1;
2116 clone_image.cache=ClonePixelCache(cache_info);
2117 clone_info=(CacheInfo *) clone_image.cache;
2118 status=OpenPixelCache(&clone_image,IOMode,exception);
2119 if (status != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00002120 {
cristy5a7fbfb2010-11-06 16:10:59 +00002121 if (clone != MagickFalse)
cristy4e6fa712010-11-06 16:06:12 +00002122 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00002123 if (status != MagickFalse)
2124 {
cristyceb55ee2010-11-06 16:05:49 +00002125 destroy=MagickTrue;
2126 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00002127 }
2128 }
cristyceb55ee2010-11-06 16:05:49 +00002129 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002130 }
cristyceb55ee2010-11-06 16:05:49 +00002131 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002132 }
cristy4320e0e2009-09-10 15:00:08 +00002133 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002134 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002135 if (status != MagickFalse)
2136 {
2137 /*
2138 Ensure the image matches the pixel cache morphology.
2139 */
2140 image->taint=MagickTrue;
cristy5f1c1ff2010-12-23 21:38:06 +00002141 image->type=UndefinedType;
cristydd438462010-05-06 13:44:04 +00002142 if (image->colorspace == GRAYColorspace)
2143 image->colorspace=RGBColorspace;
cristy3ed852e2009-09-05 21:47:34 +00002144 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2145 status=OpenPixelCache(image,IOMode,exception);
2146 }
cristyf84a1932010-01-03 18:00:18 +00002147 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002148 if (status == MagickFalse)
2149 return((Cache) NULL);
2150 return(image->cache);
2151}
2152
2153/*
2154%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2155% %
2156% %
2157% %
2158% G e t O n e A u t h e n t i c P i x e l %
2159% %
2160% %
2161% %
2162%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2163%
2164% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2165% location. The image background color is returned if an error occurs.
2166%
2167% The format of the GetOneAuthenticPixel() method is:
2168%
cristybb503372010-05-27 20:51:26 +00002169% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2170% const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002171%
2172% A description of each parameter follows:
2173%
2174% o image: the image.
2175%
2176% o x,y: These values define the location of the pixel to return.
2177%
2178% o pixel: return a pixel at the specified (x,y) location.
2179%
2180% o exception: return any errors or warnings in this structure.
2181%
2182*/
cristyacbbb7c2010-06-30 18:56:48 +00002183MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2184 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002185{
2186 CacheInfo
2187 *cache_info;
2188
cristy2036f5c2010-09-19 21:18:17 +00002189 PixelPacket
2190 *pixels;
2191
cristy3ed852e2009-09-05 21:47:34 +00002192 assert(image != (Image *) NULL);
2193 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002194 assert(image->cache != (Cache) NULL);
2195 cache_info=(CacheInfo *) image->cache;
2196 assert(cache_info->signature == MagickSignature);
2197 *pixel=image->background_color;
cristyd317f372010-09-18 01:42:20 +00002198 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2199 (GetOneAuthenticPixelFromHandler) NULL)
2200 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2201 pixel,exception));
cristy2036f5c2010-09-19 21:18:17 +00002202 *pixel=image->background_color;
2203 pixels=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2204 if (pixels == (PixelPacket *) NULL)
2205 return(MagickFalse);
2206 *pixel=(*pixels);
2207 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002208}
2209
2210/*
2211%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2212% %
2213% %
2214% %
2215+ 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 %
2216% %
2217% %
2218% %
2219%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2220%
2221% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2222% location. The image background color is returned if an error occurs.
2223%
2224% The format of the GetOneAuthenticPixelFromCache() method is:
2225%
2226% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy5f959472010-05-27 22:19:46 +00002227% const ssize_t x,const ssize_t y,PixelPacket *pixel,
2228% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002229%
2230% A description of each parameter follows:
2231%
2232% o image: the image.
2233%
2234% o x,y: These values define the location of the pixel to return.
2235%
2236% o pixel: return a pixel at the specified (x,y) location.
2237%
2238% o exception: return any errors or warnings in this structure.
2239%
2240*/
2241static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristybb503372010-05-27 20:51:26 +00002242 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002243{
cristy098f78c2010-09-23 17:28:44 +00002244 CacheInfo
2245 *cache_info;
2246
2247 const int
2248 id = GetOpenMPThreadId();
2249
cristy3ed852e2009-09-05 21:47:34 +00002250 PixelPacket
2251 *pixels;
2252
cristy0158a4b2010-09-20 13:59:45 +00002253 assert(image != (const Image *) NULL);
2254 assert(image->signature == MagickSignature);
2255 assert(image->cache != (Cache) NULL);
cristy098f78c2010-09-23 17:28:44 +00002256 cache_info=(CacheInfo *) image->cache;
2257 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002258 *pixel=image->background_color;
cristy098f78c2010-09-23 17:28:44 +00002259 assert(id < (int) cache_info->number_threads);
2260 pixels=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,
2261 cache_info->nexus_info[id],exception);
cristy3ed852e2009-09-05 21:47:34 +00002262 if (pixels == (PixelPacket *) NULL)
2263 return(MagickFalse);
2264 *pixel=(*pixels);
2265 return(MagickTrue);
2266}
2267
2268/*
2269%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2270% %
2271% %
2272% %
2273% G e t O n e V i r t u a l M a g i c k P i x e l %
2274% %
2275% %
2276% %
2277%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2278%
2279% GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2280% location. The image background color is returned if an error occurs. If
2281% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2282%
2283% The format of the GetOneVirtualMagickPixel() method is:
2284%
2285% MagickBooleanType GetOneVirtualMagickPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002286% const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
cristy3ed852e2009-09-05 21:47:34 +00002287% ExceptionInfo exception)
2288%
2289% A description of each parameter follows:
2290%
2291% o image: the image.
2292%
2293% o x,y: these values define the location of the pixel to return.
2294%
2295% o pixel: return a pixel at the specified (x,y) location.
2296%
2297% o exception: return any errors or warnings in this structure.
2298%
2299*/
2300MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
cristyacbbb7c2010-06-30 18:56:48 +00002301 const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
2302 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002303{
2304 CacheInfo
2305 *cache_info;
2306
cristy0158a4b2010-09-20 13:59:45 +00002307 const int
2308 id = GetOpenMPThreadId();
2309
cristy3ed852e2009-09-05 21:47:34 +00002310 register const IndexPacket
2311 *indexes;
2312
2313 register const PixelPacket
cristy0158a4b2010-09-20 13:59:45 +00002314 *pixels;
cristy3ed852e2009-09-05 21:47:34 +00002315
2316 assert(image != (const Image *) NULL);
2317 assert(image->signature == MagickSignature);
2318 assert(image->cache != (Cache) NULL);
2319 cache_info=(CacheInfo *) image->cache;
2320 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002321 assert(id < (int) cache_info->number_threads);
2322 pixels=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2323 1UL,1UL,cache_info->nexus_info[id],exception);
cristye7cc7cf2010-09-21 13:26:47 +00002324 GetMagickPixelPacket(image,pixel);
cristy0158a4b2010-09-20 13:59:45 +00002325 if (pixels == (const PixelPacket *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002326 return(MagickFalse);
cristy098f78c2010-09-23 17:28:44 +00002327 indexes=GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[id]);
cristy0158a4b2010-09-20 13:59:45 +00002328 SetMagickPixelPacket(image,pixels,indexes,pixel);
cristy3ed852e2009-09-05 21:47:34 +00002329 return(MagickTrue);
2330}
2331
2332/*
2333%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2334% %
2335% %
2336% %
2337% G e t O n e V i r t u a l M e t h o d P i x e l %
2338% %
2339% %
2340% %
2341%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2342%
2343% GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2344% location as defined by specified pixel method. The image background color
2345% is returned if an error occurs. If you plan to modify the pixel, use
2346% GetOneAuthenticPixel() instead.
2347%
2348% The format of the GetOneVirtualMethodPixel() method is:
2349%
2350% MagickBooleanType GetOneVirtualMethodPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002351% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2352% const ssize_t y,Pixelpacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002353%
2354% A description of each parameter follows:
2355%
2356% o image: the image.
2357%
2358% o virtual_pixel_method: the virtual pixel method.
2359%
2360% o x,y: These values define the location of the pixel to return.
2361%
2362% o pixel: return a pixel at the specified (x,y) location.
2363%
2364% o exception: return any errors or warnings in this structure.
2365%
2366*/
2367MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002368 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002369 PixelPacket *pixel,ExceptionInfo *exception)
2370{
cristy3ed852e2009-09-05 21:47:34 +00002371 CacheInfo
2372 *cache_info;
2373
cristy0158a4b2010-09-20 13:59:45 +00002374 const int
2375 id = GetOpenMPThreadId();
2376
cristy2036f5c2010-09-19 21:18:17 +00002377 const PixelPacket
2378 *pixels;
2379
cristy3ed852e2009-09-05 21:47:34 +00002380 assert(image != (const Image *) NULL);
2381 assert(image->signature == MagickSignature);
2382 assert(image->cache != (Cache) NULL);
2383 cache_info=(CacheInfo *) image->cache;
2384 assert(cache_info->signature == MagickSignature);
2385 *pixel=image->background_color;
cristyd317f372010-09-18 01:42:20 +00002386 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2387 (GetOneVirtualPixelFromHandler) NULL)
2388 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2389 virtual_pixel_method,x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002390 assert(id < (int) cache_info->number_threads);
2391 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2392 cache_info->nexus_info[id],exception);
cristy2036f5c2010-09-19 21:18:17 +00002393 if (pixels == (const PixelPacket *) NULL)
2394 return(MagickFalse);
2395 *pixel=(*pixels);
2396 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002397}
2398
2399/*
2400%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2401% %
2402% %
2403% %
2404% G e t O n e V i r t u a l P i x e l %
2405% %
2406% %
2407% %
2408%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2409%
2410% GetOneVirtualPixel() returns a single virtual pixel at the specified
2411% (x,y) location. The image background color is returned if an error occurs.
2412% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2413%
2414% The format of the GetOneVirtualPixel() method is:
2415%
cristybb503372010-05-27 20:51:26 +00002416% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2417% const ssize_t y,PixelPacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002418%
2419% A description of each parameter follows:
2420%
2421% o image: the image.
2422%
2423% o x,y: These values define the location of the pixel to return.
2424%
2425% o pixel: return a pixel at the specified (x,y) location.
2426%
2427% o exception: return any errors or warnings in this structure.
2428%
2429*/
2430MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002431 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002432{
cristy3ed852e2009-09-05 21:47:34 +00002433 CacheInfo
2434 *cache_info;
2435
cristy0158a4b2010-09-20 13:59:45 +00002436 const int
2437 id = GetOpenMPThreadId();
2438
cristy2036f5c2010-09-19 21:18:17 +00002439 const PixelPacket
2440 *pixels;
2441
cristy3ed852e2009-09-05 21:47:34 +00002442 assert(image != (const Image *) NULL);
2443 assert(image->signature == MagickSignature);
2444 assert(image->cache != (Cache) NULL);
2445 cache_info=(CacheInfo *) image->cache;
2446 assert(cache_info->signature == MagickSignature);
2447 *pixel=image->background_color;
cristyd317f372010-09-18 01:42:20 +00002448 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2449 (GetOneVirtualPixelFromHandler) NULL)
2450 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2451 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002452 assert(id < (int) cache_info->number_threads);
2453 pixels=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2454 1UL,1UL,cache_info->nexus_info[id],exception);
cristy2036f5c2010-09-19 21:18:17 +00002455 if (pixels == (const PixelPacket *) NULL)
2456 return(MagickFalse);
2457 *pixel=(*pixels);
2458 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002459}
2460
2461/*
2462%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2463% %
2464% %
2465% %
2466+ 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 %
2467% %
2468% %
2469% %
2470%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2471%
2472% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2473% specified (x,y) location. The image background color is returned if an
2474% error occurs.
2475%
2476% The format of the GetOneVirtualPixelFromCache() method is:
2477%
2478% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristybb503372010-05-27 20:51:26 +00002479% const VirtualPixelPacket method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002480% PixelPacket *pixel,ExceptionInfo *exception)
2481%
2482% A description of each parameter follows:
2483%
2484% o image: the image.
2485%
2486% o virtual_pixel_method: the virtual pixel method.
2487%
2488% o x,y: These values define the location of the pixel to return.
2489%
2490% o pixel: return a pixel at the specified (x,y) location.
2491%
2492% o exception: return any errors or warnings in this structure.
2493%
2494*/
2495static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002496 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002497 PixelPacket *pixel,ExceptionInfo *exception)
2498{
cristy0158a4b2010-09-20 13:59:45 +00002499 CacheInfo
2500 *cache_info;
2501
2502 const int
2503 id = GetOpenMPThreadId();
2504
cristy3ed852e2009-09-05 21:47:34 +00002505 const PixelPacket
2506 *pixels;
2507
cristye7cc7cf2010-09-21 13:26:47 +00002508 assert(image != (const Image *) NULL);
2509 assert(image->signature == MagickSignature);
2510 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002511 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002512 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002513 assert(id < (int) cache_info->number_threads);
cristye7cc7cf2010-09-21 13:26:47 +00002514 *pixel=image->background_color;
cristy0158a4b2010-09-20 13:59:45 +00002515 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2516 cache_info->nexus_info[id],exception);
cristy3ed852e2009-09-05 21:47:34 +00002517 if (pixels == (const PixelPacket *) NULL)
2518 return(MagickFalse);
2519 *pixel=(*pixels);
2520 return(MagickTrue);
2521}
2522
2523/*
2524%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2525% %
2526% %
2527% %
2528+ G e t P i x e l C a c h e C o l o r s p a c e %
2529% %
2530% %
2531% %
2532%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2533%
2534% GetPixelCacheColorspace() returns the class type of the pixel cache.
2535%
2536% The format of the GetPixelCacheColorspace() method is:
2537%
2538% Colorspace GetPixelCacheColorspace(Cache cache)
2539%
2540% A description of each parameter follows:
2541%
2542% o cache: the pixel cache.
2543%
2544*/
2545MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
2546{
2547 CacheInfo
2548 *cache_info;
2549
2550 assert(cache != (Cache) NULL);
2551 cache_info=(CacheInfo *) cache;
2552 assert(cache_info->signature == MagickSignature);
2553 if (cache_info->debug != MagickFalse)
2554 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2555 cache_info->filename);
2556 return(cache_info->colorspace);
2557}
2558
2559/*
2560%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2561% %
2562% %
2563% %
2564+ G e t P i x e l C a c h e M e t h o d s %
2565% %
2566% %
2567% %
2568%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2569%
2570% GetPixelCacheMethods() initializes the CacheMethods structure.
2571%
2572% The format of the GetPixelCacheMethods() method is:
2573%
2574% void GetPixelCacheMethods(CacheMethods *cache_methods)
2575%
2576% A description of each parameter follows:
2577%
2578% o cache_methods: Specifies a pointer to a CacheMethods structure.
2579%
2580*/
2581MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
2582{
2583 assert(cache_methods != (CacheMethods *) NULL);
2584 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2585 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2586 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2587 cache_methods->get_virtual_indexes_from_handler=GetVirtualIndexesFromCache;
2588 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2589 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2590 cache_methods->get_authentic_indexes_from_handler=
2591 GetAuthenticIndexesFromCache;
2592 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2593 cache_methods->get_one_authentic_pixel_from_handler=
2594 GetOneAuthenticPixelFromCache;
2595 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2596 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2597 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2598}
2599
2600/*
2601%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2602% %
2603% %
2604% %
2605+ G e t P i x e l C a c h e N e x u s E x t e n t %
2606% %
2607% %
2608% %
2609%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2610%
2611% GetPixelCacheNexusExtent() returns the extent of the pixels associated with
2612% the last call to SetPixelCacheNexusPixels() or GetPixelCacheNexusPixels().
2613%
2614% The format of the GetPixelCacheNexusExtent() method is:
2615%
2616% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2617% NexusInfo *nexus_info)
2618%
2619% A description of each parameter follows:
2620%
2621% o nexus_info: the nexus info.
2622%
2623*/
2624MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2625 NexusInfo *nexus_info)
2626{
2627 CacheInfo
2628 *cache_info;
2629
2630 MagickSizeType
2631 extent;
2632
cristye7cc7cf2010-09-21 13:26:47 +00002633 assert(cache != (const Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002634 cache_info=(CacheInfo *) cache;
2635 assert(cache_info->signature == MagickSignature);
2636 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2637 if (extent == 0)
2638 return((MagickSizeType) cache_info->columns*cache_info->rows);
2639 return(extent);
2640}
2641
2642/*
2643%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2644% %
2645% %
2646% %
2647+ 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 %
2648% %
2649% %
2650% %
2651%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2652%
2653% GetPixelCacheNexusIndexes() returns the indexes associated with the
2654% specified cache nexus.
2655%
2656% The format of the GetPixelCacheNexusIndexes() method is:
2657%
2658% IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2659% NexusInfo *nexus_info)
2660%
2661% A description of each parameter follows:
2662%
2663% o cache: the pixel cache.
2664%
2665% o nexus_info: the cache nexus to return the colormap indexes.
2666%
2667*/
2668MagickExport IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2669 NexusInfo *nexus_info)
2670{
2671 CacheInfo
2672 *cache_info;
2673
cristye7cc7cf2010-09-21 13:26:47 +00002674 assert(cache != (const Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002675 cache_info=(CacheInfo *) cache;
2676 assert(cache_info->signature == MagickSignature);
2677 if (cache_info->storage_class == UndefinedClass)
2678 return((IndexPacket *) NULL);
2679 return(nexus_info->indexes);
2680}
2681
2682/*
2683%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2684% %
2685% %
2686% %
2687+ G e t P i x e l C a c h e N e x u s P i x e l s %
2688% %
2689% %
2690% %
2691%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2692%
2693% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2694% cache nexus.
2695%
2696% The format of the GetPixelCacheNexusPixels() method is:
2697%
2698% PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2699% NexusInfo *nexus_info)
2700%
2701% A description of each parameter follows:
2702%
2703% o cache: the pixel cache.
2704%
2705% o nexus_info: the cache nexus to return the pixels.
2706%
2707*/
2708MagickExport PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2709 NexusInfo *nexus_info)
2710{
2711 CacheInfo
2712 *cache_info;
2713
cristye7cc7cf2010-09-21 13:26:47 +00002714 assert(cache != (const Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002715 cache_info=(CacheInfo *) cache;
2716 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002717 if (cache_info->storage_class == UndefinedClass)
2718 return((PixelPacket *) NULL);
2719 return(nexus_info->pixels);
2720}
2721
2722/*
2723%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2724% %
2725% %
2726% %
cristy056ba772010-01-02 23:33:54 +00002727+ G e t P i x e l C a c h e P i x e l s %
2728% %
2729% %
2730% %
2731%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2732%
2733% GetPixelCachePixels() returns the pixels associated with the specified image.
2734%
2735% The format of the GetPixelCachePixels() method is:
2736%
cristyf84a1932010-01-03 18:00:18 +00002737% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2738% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002739%
2740% A description of each parameter follows:
2741%
2742% o image: the image.
2743%
2744% o length: the pixel cache length.
2745%
cristyf84a1932010-01-03 18:00:18 +00002746% o exception: return any errors or warnings in this structure.
2747%
cristy056ba772010-01-02 23:33:54 +00002748*/
cristyf84a1932010-01-03 18:00:18 +00002749MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2750 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002751{
2752 CacheInfo
2753 *cache_info;
2754
2755 assert(image != (const Image *) NULL);
2756 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002757 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00002758 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002759 assert(cache_info->signature == MagickSignature);
2760 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002761 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002762 return((void *) NULL);
2763 *length=cache_info->length;
2764 return((void *) cache_info->pixels);
2765}
2766
2767/*
2768%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2769% %
2770% %
2771% %
cristyb32b90a2009-09-07 21:45:48 +00002772+ 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 +00002773% %
2774% %
2775% %
2776%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2777%
2778% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2779%
2780% The format of the GetPixelCacheStorageClass() method is:
2781%
2782% ClassType GetPixelCacheStorageClass(Cache cache)
2783%
2784% A description of each parameter follows:
2785%
2786% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2787%
2788% o cache: the pixel cache.
2789%
2790*/
2791MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
2792{
2793 CacheInfo
2794 *cache_info;
2795
2796 assert(cache != (Cache) NULL);
2797 cache_info=(CacheInfo *) cache;
2798 assert(cache_info->signature == MagickSignature);
2799 if (cache_info->debug != MagickFalse)
2800 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2801 cache_info->filename);
2802 return(cache_info->storage_class);
2803}
2804
2805/*
2806%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2807% %
2808% %
2809% %
cristyb32b90a2009-09-07 21:45:48 +00002810+ G e t P i x e l C a c h e T i l e S i z e %
2811% %
2812% %
2813% %
2814%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2815%
2816% GetPixelCacheTileSize() returns the pixel cache tile size.
2817%
2818% The format of the GetPixelCacheTileSize() method is:
2819%
cristybb503372010-05-27 20:51:26 +00002820% void GetPixelCacheTileSize(const Image *image,size_t *width,
2821% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002822%
2823% A description of each parameter follows:
2824%
2825% o image: the image.
2826%
2827% o width: the optimize cache tile width in pixels.
2828%
2829% o height: the optimize cache tile height in pixels.
2830%
2831*/
cristybb503372010-05-27 20:51:26 +00002832MagickExport void GetPixelCacheTileSize(const Image *image,size_t *width,
2833 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002834{
cristyb32b90a2009-09-07 21:45:48 +00002835 assert(image != (Image *) NULL);
2836 assert(image->signature == MagickSignature);
2837 if (image->debug != MagickFalse)
2838 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristyb32b90a2009-09-07 21:45:48 +00002839 *width=2048UL/sizeof(PixelPacket);
2840 if (GetPixelCacheType(image) == DiskCache)
cristydaa97692009-09-13 02:10:35 +00002841 *width=8192UL/sizeof(PixelPacket);
cristyb32b90a2009-09-07 21:45:48 +00002842 *height=(*width);
2843}
2844
2845/*
2846%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2847% %
2848% %
2849% %
2850+ G e t P i x e l C a c h e T y p e %
2851% %
2852% %
2853% %
2854%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2855%
2856% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2857%
2858% The format of the GetPixelCacheType() method is:
2859%
2860% CacheType GetPixelCacheType(const Image *image)
2861%
2862% A description of each parameter follows:
2863%
2864% o image: the image.
2865%
2866*/
2867MagickExport CacheType GetPixelCacheType(const Image *image)
2868{
2869 CacheInfo
2870 *cache_info;
2871
2872 assert(image != (Image *) NULL);
2873 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002874 assert(image->cache != (Cache) NULL);
2875 cache_info=(CacheInfo *) image->cache;
2876 assert(cache_info->signature == MagickSignature);
2877 return(cache_info->type);
2878}
2879
2880/*
2881%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2882% %
2883% %
2884% %
cristy3ed852e2009-09-05 21:47:34 +00002885+ 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 %
2886% %
2887% %
2888% %
2889%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2890%
2891% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2892% pixel cache. A virtual pixel is any pixel access that is outside the
2893% boundaries of the image cache.
2894%
2895% The format of the GetPixelCacheVirtualMethod() method is:
2896%
2897% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2898%
2899% A description of each parameter follows:
2900%
2901% o image: the image.
2902%
2903*/
2904MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2905{
2906 CacheInfo
2907 *cache_info;
2908
2909 assert(image != (Image *) NULL);
2910 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002911 assert(image->cache != (Cache) NULL);
2912 cache_info=(CacheInfo *) image->cache;
2913 assert(cache_info->signature == MagickSignature);
2914 return(cache_info->virtual_pixel_method);
2915}
2916
2917/*
2918%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2919% %
2920% %
2921% %
2922+ 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 %
2923% %
2924% %
2925% %
2926%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2927%
2928% GetVirtualIndexesFromCache() returns the indexes associated with the last
2929% call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2930%
2931% The format of the GetVirtualIndexesFromCache() method is:
2932%
2933% IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2934%
2935% A description of each parameter follows:
2936%
2937% o image: the image.
2938%
2939*/
2940static const IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2941{
2942 CacheInfo
2943 *cache_info;
2944
cristy5c9e6f22010-09-17 17:31:01 +00002945 const int
2946 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002947
cristye7cc7cf2010-09-21 13:26:47 +00002948 assert(image != (const Image *) NULL);
2949 assert(image->signature == MagickSignature);
2950 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002951 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002952 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002953 assert(id < (int) cache_info->number_threads);
cristye7cc7cf2010-09-21 13:26:47 +00002954 return(GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00002955}
2956
2957/*
2958%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2959% %
2960% %
2961% %
2962+ 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 %
2963% %
2964% %
2965% %
2966%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2967%
2968% GetVirtualIndexesFromNexus() returns the indexes associated with the
2969% specified cache nexus.
2970%
2971% The format of the GetVirtualIndexesFromNexus() method is:
2972%
2973% const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2974% NexusInfo *nexus_info)
2975%
2976% A description of each parameter follows:
2977%
2978% o cache: the pixel cache.
2979%
2980% o nexus_info: the cache nexus to return the colormap indexes.
2981%
2982*/
2983MagickExport const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2984 NexusInfo *nexus_info)
2985{
2986 CacheInfo
2987 *cache_info;
2988
cristye7cc7cf2010-09-21 13:26:47 +00002989 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002990 cache_info=(CacheInfo *) cache;
2991 assert(cache_info->signature == MagickSignature);
2992 if (cache_info->storage_class == UndefinedClass)
2993 return((IndexPacket *) NULL);
2994 return(nexus_info->indexes);
2995}
2996
2997/*
2998%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2999% %
3000% %
3001% %
3002% G e t V i r t u a l I n d e x Q u e u e %
3003% %
3004% %
3005% %
3006%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3007%
3008% GetVirtualIndexQueue() returns the virtual black channel or the
3009% colormap indexes associated with the last call to QueueAuthenticPixels() or
3010% GetVirtualPixels(). NULL is returned if the black channel or colormap
3011% indexes are not available.
3012%
3013% The format of the GetVirtualIndexQueue() method is:
3014%
3015% const IndexPacket *GetVirtualIndexQueue(const Image *image)
3016%
3017% A description of each parameter follows:
3018%
3019% o image: the image.
3020%
3021*/
3022MagickExport const IndexPacket *GetVirtualIndexQueue(const Image *image)
3023{
3024 CacheInfo
3025 *cache_info;
3026
cristy2036f5c2010-09-19 21:18:17 +00003027 const int
3028 id = GetOpenMPThreadId();
3029
cristy3ed852e2009-09-05 21:47:34 +00003030 assert(image != (const Image *) NULL);
3031 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003032 assert(image->cache != (Cache) NULL);
3033 cache_info=(CacheInfo *) image->cache;
3034 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003035 if (cache_info->methods.get_virtual_indexes_from_handler !=
3036 (GetVirtualIndexesFromHandler) NULL)
3037 return(cache_info->methods.get_virtual_indexes_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003038 assert(id < (int) cache_info->number_threads);
3039 return(GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003040}
3041
3042/*
3043%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3044% %
3045% %
3046% %
3047+ 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 %
3048% %
3049% %
3050% %
3051%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3052%
3053% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3054% pixel cache as defined by the geometry parameters. A pointer to the pixels
3055% is returned if the pixels are transferred, otherwise a NULL is returned.
3056%
3057% The format of the GetVirtualPixelsFromNexus() method is:
3058%
3059% PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003060% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00003061% const size_t columns,const size_t rows,NexusInfo *nexus_info,
3062% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003063%
3064% A description of each parameter follows:
3065%
3066% o image: the image.
3067%
3068% o virtual_pixel_method: the virtual pixel method.
3069%
3070% o x,y,columns,rows: These values define the perimeter of a region of
3071% pixels.
3072%
3073% o nexus_info: the cache nexus to acquire.
3074%
3075% o exception: return any errors or warnings in this structure.
3076%
3077*/
3078
cristybb503372010-05-27 20:51:26 +00003079static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003080 DitherMatrix[64] =
3081 {
3082 0, 48, 12, 60, 3, 51, 15, 63,
3083 32, 16, 44, 28, 35, 19, 47, 31,
3084 8, 56, 4, 52, 11, 59, 7, 55,
3085 40, 24, 36, 20, 43, 27, 39, 23,
3086 2, 50, 14, 62, 1, 49, 13, 61,
3087 34, 18, 46, 30, 33, 17, 45, 29,
3088 10, 58, 6, 54, 9, 57, 5, 53,
3089 42, 26, 38, 22, 41, 25, 37, 21
3090 };
3091
cristybb503372010-05-27 20:51:26 +00003092static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003093{
cristybb503372010-05-27 20:51:26 +00003094 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003095 index;
3096
3097 index=x+DitherMatrix[x & 0x07]-32L;
3098 if (index < 0L)
3099 return(0L);
cristybb503372010-05-27 20:51:26 +00003100 if (index >= (ssize_t) columns)
3101 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00003102 return(index);
3103}
3104
cristybb503372010-05-27 20:51:26 +00003105static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003106{
cristybb503372010-05-27 20:51:26 +00003107 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003108 index;
3109
3110 index=y+DitherMatrix[y & 0x07]-32L;
3111 if (index < 0L)
3112 return(0L);
cristybb503372010-05-27 20:51:26 +00003113 if (index >= (ssize_t) rows)
3114 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00003115 return(index);
3116}
3117
cristybb503372010-05-27 20:51:26 +00003118static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003119{
3120 if (x < 0L)
3121 return(0L);
cristybb503372010-05-27 20:51:26 +00003122 if (x >= (ssize_t) columns)
3123 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003124 return(x);
3125}
3126
cristybb503372010-05-27 20:51:26 +00003127static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003128{
3129 if (y < 0L)
3130 return(0L);
cristybb503372010-05-27 20:51:26 +00003131 if (y >= (ssize_t) rows)
3132 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003133 return(y);
3134}
3135
cristybb503372010-05-27 20:51:26 +00003136static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003137{
cristybb503372010-05-27 20:51:26 +00003138 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003139}
3140
cristybb503372010-05-27 20:51:26 +00003141static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003142{
cristybb503372010-05-27 20:51:26 +00003143 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003144}
3145
3146/*
3147 VirtualPixelModulo() computes the remainder of dividing offset by extent. It
3148 returns not only the quotient (tile the offset falls in) but also the positive
3149 remainer within that tile such that 0 <= remainder < extent. This method is
3150 essentially a ldiv() using a floored modulo division rather than the normal
3151 default truncated modulo division.
3152*/
cristybb503372010-05-27 20:51:26 +00003153static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3154 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003155{
3156 MagickModulo
3157 modulo;
3158
cristybb503372010-05-27 20:51:26 +00003159 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003160 if (offset < 0L)
3161 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003162 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003163 return(modulo);
3164}
3165
3166MagickExport const PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003167 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3168 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003169 ExceptionInfo *exception)
3170{
3171 CacheInfo
3172 *cache_info;
3173
cristyc3ec0d42010-04-07 01:18:08 +00003174 IndexPacket
3175 virtual_index;
3176
cristy3ed852e2009-09-05 21:47:34 +00003177 MagickOffsetType
3178 offset;
3179
3180 MagickSizeType
3181 length,
3182 number_pixels;
3183
3184 NexusInfo
3185 **virtual_nexus;
3186
3187 PixelPacket
3188 *pixels,
3189 virtual_pixel;
3190
3191 RectangleInfo
3192 region;
3193
3194 register const IndexPacket
cristyc3ec0d42010-04-07 01:18:08 +00003195 *restrict virtual_indexes;
cristy3ed852e2009-09-05 21:47:34 +00003196
3197 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003198 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003199
3200 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003201 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003202
cristye076a6e2010-08-15 19:59:43 +00003203 register PixelPacket
3204 *restrict q;
3205
cristybb503372010-05-27 20:51:26 +00003206 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003207 u,
3208 v;
3209
cristy3ed852e2009-09-05 21:47:34 +00003210 /*
3211 Acquire pixels.
3212 */
cristye7cc7cf2010-09-21 13:26:47 +00003213 assert(image != (const Image *) NULL);
3214 assert(image->signature == MagickSignature);
3215 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003216 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003217 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003218 if (cache_info->type == UndefinedCache)
cristy3ed852e2009-09-05 21:47:34 +00003219 return((const PixelPacket *) NULL);
3220 region.x=x;
3221 region.y=y;
3222 region.width=columns;
3223 region.height=rows;
3224 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
3225 if (pixels == (PixelPacket *) NULL)
3226 return((const PixelPacket *) NULL);
cristydf415c82010-03-11 16:47:50 +00003227 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3228 nexus_info->region.x;
3229 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3230 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003231 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3232 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003233 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3234 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003235 {
3236 MagickBooleanType
3237 status;
3238
3239 /*
3240 Pixel request is inside cache extents.
3241 */
3242 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
3243 return(pixels);
3244 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3245 if (status == MagickFalse)
3246 return((const PixelPacket *) NULL);
3247 if ((cache_info->storage_class == PseudoClass) ||
3248 (cache_info->colorspace == CMYKColorspace))
3249 {
3250 status=ReadPixelCacheIndexes(cache_info,nexus_info,exception);
3251 if (status == MagickFalse)
3252 return((const PixelPacket *) NULL);
3253 }
3254 return(pixels);
3255 }
3256 /*
3257 Pixel request is outside cache extents.
3258 */
3259 q=pixels;
3260 indexes=GetPixelCacheNexusIndexes(cache_info,nexus_info);
3261 virtual_nexus=AcquirePixelCacheNexus(1);
3262 if (virtual_nexus == (NexusInfo **) NULL)
3263 {
3264 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3265 "UnableToGetCacheNexus","`%s'",image->filename);
3266 return((const PixelPacket *) NULL);
3267 }
3268 switch (virtual_pixel_method)
3269 {
3270 case BlackVirtualPixelMethod:
3271 {
cristy4789f0d2010-01-10 00:01:06 +00003272 SetRedPixelComponent(&virtual_pixel,0);
3273 SetGreenPixelComponent(&virtual_pixel,0);
3274 SetBluePixelComponent(&virtual_pixel,0);
3275 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003276 break;
3277 }
3278 case GrayVirtualPixelMethod:
3279 {
cristy4789f0d2010-01-10 00:01:06 +00003280 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3281 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3282 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3283 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003284 break;
3285 }
3286 case TransparentVirtualPixelMethod:
3287 {
cristy4789f0d2010-01-10 00:01:06 +00003288 SetRedPixelComponent(&virtual_pixel,0);
3289 SetGreenPixelComponent(&virtual_pixel,0);
3290 SetBluePixelComponent(&virtual_pixel,0);
3291 SetOpacityPixelComponent(&virtual_pixel,TransparentOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003292 break;
3293 }
3294 case MaskVirtualPixelMethod:
3295 case WhiteVirtualPixelMethod:
3296 {
cristy4789f0d2010-01-10 00:01:06 +00003297 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3298 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3299 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3300 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003301 break;
3302 }
3303 default:
3304 {
3305 virtual_pixel=image->background_color;
3306 break;
3307 }
3308 }
cristyc3ec0d42010-04-07 01:18:08 +00003309 virtual_index=0;
cristybb503372010-05-27 20:51:26 +00003310 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003311 {
cristybb503372010-05-27 20:51:26 +00003312 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003313 {
3314 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003315 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003316 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3317 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003318 {
3319 MagickModulo
3320 x_modulo,
3321 y_modulo;
3322
3323 /*
3324 Transfer a single pixel.
3325 */
3326 length=(MagickSizeType) 1;
3327 switch (virtual_pixel_method)
3328 {
3329 case BackgroundVirtualPixelMethod:
3330 case ConstantVirtualPixelMethod:
3331 case BlackVirtualPixelMethod:
3332 case GrayVirtualPixelMethod:
3333 case TransparentVirtualPixelMethod:
3334 case MaskVirtualPixelMethod:
3335 case WhiteVirtualPixelMethod:
3336 {
3337 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003338 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003339 break;
3340 }
3341 case EdgeVirtualPixelMethod:
3342 default:
3343 {
3344 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003345 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003346 1UL,1UL,*virtual_nexus,exception);
cristyc3ec0d42010-04-07 01:18:08 +00003347 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003348 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003349 break;
3350 }
3351 case RandomVirtualPixelMethod:
3352 {
3353 if (cache_info->random_info == (RandomInfo *) NULL)
3354 cache_info->random_info=AcquireRandomInfo();
3355 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003356 RandomX(cache_info->random_info,cache_info->columns),
3357 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003358 *virtual_nexus,exception);
cristyc3ec0d42010-04-07 01:18:08 +00003359 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003360 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003361 break;
3362 }
3363 case DitherVirtualPixelMethod:
3364 {
3365 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003366 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003367 1UL,1UL,*virtual_nexus,exception);
cristyc3ec0d42010-04-07 01:18:08 +00003368 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003369 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003370 break;
3371 }
3372 case TileVirtualPixelMethod:
3373 {
3374 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3375 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3376 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003377 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003378 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003379 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003380 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003381 break;
3382 }
3383 case MirrorVirtualPixelMethod:
3384 {
3385 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3386 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003387 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003388 x_modulo.remainder-1L;
3389 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3390 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003391 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003392 y_modulo.remainder-1L;
3393 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003394 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003395 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003396 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003397 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003398 break;
3399 }
3400 case CheckerTileVirtualPixelMethod:
3401 {
3402 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3403 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3404 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3405 {
3406 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003407 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003408 break;
3409 }
3410 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003411 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003412 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003413 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003414 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003415 break;
3416 }
3417 case HorizontalTileVirtualPixelMethod:
3418 {
cristybb503372010-05-27 20:51:26 +00003419 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003420 {
3421 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003422 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003423 break;
3424 }
3425 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3426 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3427 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003428 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003429 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003430 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003431 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003432 break;
3433 }
3434 case VerticalTileVirtualPixelMethod:
3435 {
cristybb503372010-05-27 20:51:26 +00003436 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
cristy3ed852e2009-09-05 21:47:34 +00003437 {
3438 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003439 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003440 break;
3441 }
3442 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3443 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3444 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003445 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003446 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003447 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003448 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003449 break;
3450 }
3451 case HorizontalTileEdgeVirtualPixelMethod:
3452 {
3453 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3454 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003455 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003456 *virtual_nexus,exception);
cristyc3ec0d42010-04-07 01:18:08 +00003457 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003458 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003459 break;
3460 }
3461 case VerticalTileEdgeVirtualPixelMethod:
3462 {
3463 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3464 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003465 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003466 *virtual_nexus,exception);
cristyc3ec0d42010-04-07 01:18:08 +00003467 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003468 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003469 break;
3470 }
3471 }
3472 if (p == (const PixelPacket *) NULL)
3473 break;
3474 *q++=(*p);
cristyc3ec0d42010-04-07 01:18:08 +00003475 if ((indexes != (IndexPacket *) NULL) &&
3476 (virtual_indexes != (const IndexPacket *) NULL))
3477 *indexes++=(*virtual_indexes);
cristy3ed852e2009-09-05 21:47:34 +00003478 continue;
3479 }
3480 /*
3481 Transfer a run of pixels.
3482 */
3483 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,
cristy0a36c742010-10-03 02:10:53 +00003484 (size_t) length,1UL,*virtual_nexus,exception);
cristy3ed852e2009-09-05 21:47:34 +00003485 if (p == (const PixelPacket *) NULL)
3486 break;
cristy0a36c742010-10-03 02:10:53 +00003487 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,*virtual_nexus);
cristy8f036fe2010-09-18 02:02:00 +00003488 (void) memcpy(q,p,(size_t) length*sizeof(*p));
cristy3ed852e2009-09-05 21:47:34 +00003489 q+=length;
cristyc3ec0d42010-04-07 01:18:08 +00003490 if ((indexes != (IndexPacket *) NULL) &&
3491 (virtual_indexes != (const IndexPacket *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003492 {
cristy8f036fe2010-09-18 02:02:00 +00003493 (void) memcpy(indexes,virtual_indexes,(size_t) length*
cristyc3ec0d42010-04-07 01:18:08 +00003494 sizeof(*virtual_indexes));
3495 indexes+=length;
cristy3ed852e2009-09-05 21:47:34 +00003496 }
3497 }
3498 }
3499 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3500 return(pixels);
3501}
3502
3503/*
3504%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3505% %
3506% %
3507% %
3508+ G e t V i r t u a l P i x e l C a c h e %
3509% %
3510% %
3511% %
3512%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3513%
3514% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3515% cache as defined by the geometry parameters. A pointer to the pixels
3516% is returned if the pixels are transferred, otherwise a NULL is returned.
3517%
3518% The format of the GetVirtualPixelCache() method is:
3519%
3520% const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003521% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3522% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003523% ExceptionInfo *exception)
3524%
3525% A description of each parameter follows:
3526%
3527% o image: the image.
3528%
3529% o virtual_pixel_method: the virtual pixel method.
3530%
3531% o x,y,columns,rows: These values define the perimeter of a region of
3532% pixels.
3533%
3534% o exception: return any errors or warnings in this structure.
3535%
3536*/
3537static const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003538 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3539 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003540{
3541 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003542 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003543
cristy5c9e6f22010-09-17 17:31:01 +00003544 const int
3545 id = GetOpenMPThreadId();
3546
cristye7cc7cf2010-09-21 13:26:47 +00003547 assert(image != (const Image *) NULL);
3548 assert(image->signature == MagickSignature);
3549 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003550 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003551 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003552 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003553 return(GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3554 cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00003555}
3556
3557/*
3558%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3559% %
3560% %
3561% %
3562% G e t V i r t u a l P i x e l Q u e u e %
3563% %
3564% %
3565% %
3566%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3567%
3568% GetVirtualPixelQueue() returns the virtual pixels associated with the
3569% last call to QueueAuthenticPixels() or GetVirtualPixels().
3570%
3571% The format of the GetVirtualPixelQueue() method is:
3572%
3573% const PixelPacket *GetVirtualPixelQueue(const Image image)
3574%
3575% A description of each parameter follows:
3576%
3577% o image: the image.
3578%
3579*/
3580MagickExport const PixelPacket *GetVirtualPixelQueue(const Image *image)
3581{
3582 CacheInfo
3583 *cache_info;
3584
cristy2036f5c2010-09-19 21:18:17 +00003585 const int
3586 id = GetOpenMPThreadId();
3587
cristy3ed852e2009-09-05 21:47:34 +00003588 assert(image != (const Image *) NULL);
3589 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003590 assert(image->cache != (Cache) NULL);
3591 cache_info=(CacheInfo *) image->cache;
3592 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003593 if (cache_info->methods.get_virtual_pixels_handler !=
3594 (GetVirtualPixelsHandler) NULL)
3595 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003596 assert(id < (int) cache_info->number_threads);
3597 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003598}
3599
3600/*
3601%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3602% %
3603% %
3604% %
3605% G e t V i r t u a l P i x e l s %
3606% %
3607% %
3608% %
3609%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3610%
3611% GetVirtualPixels() returns an immutable pixel region. If the
3612% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003613% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003614% copy of the pixels or it may point to the original pixels in memory.
3615% Performance is maximized if the selected region is part of one row, or one
3616% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003617% (without a copy) if the image is in memory, or in a memory-mapped file. The
3618% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003619%
3620% Pixels accessed via the returned pointer represent a simple array of type
3621% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
3622% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to access
3623% the black color component or to obtain the colormap indexes (of type
3624% IndexPacket) corresponding to the region.
3625%
3626% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3627%
3628% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3629% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3630% GetCacheViewAuthenticPixels() instead.
3631%
3632% The format of the GetVirtualPixels() method is:
3633%
cristybb503372010-05-27 20:51:26 +00003634% const PixelPacket *GetVirtualPixels(const Image *image,const ssize_t x,
3635% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003636% ExceptionInfo *exception)
3637%
3638% A description of each parameter follows:
3639%
3640% o image: the image.
3641%
3642% o x,y,columns,rows: These values define the perimeter of a region of
3643% pixels.
3644%
3645% o exception: return any errors or warnings in this structure.
3646%
3647*/
3648MagickExport const PixelPacket *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003649 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3650 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003651{
3652 CacheInfo
3653 *cache_info;
3654
cristy2036f5c2010-09-19 21:18:17 +00003655 const int
3656 id = GetOpenMPThreadId();
3657
cristy3ed852e2009-09-05 21:47:34 +00003658 assert(image != (const Image *) NULL);
3659 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003660 assert(image->cache != (Cache) NULL);
3661 cache_info=(CacheInfo *) image->cache;
3662 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003663 if (cache_info->methods.get_virtual_pixel_handler !=
3664 (GetVirtualPixelHandler) NULL)
3665 return(cache_info->methods.get_virtual_pixel_handler(image,
3666 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003667 assert(id < (int) cache_info->number_threads);
3668 return(GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3669 columns,rows,cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00003670}
3671
3672/*
3673%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3674% %
3675% %
3676% %
3677+ 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 %
3678% %
3679% %
3680% %
3681%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3682%
3683% GetVirtualPixelsCache() returns the pixels associated with the last call
3684% to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3685%
3686% The format of the GetVirtualPixelsCache() method is:
3687%
3688% PixelPacket *GetVirtualPixelsCache(const Image *image)
3689%
3690% A description of each parameter follows:
3691%
3692% o image: the image.
3693%
3694*/
3695static const PixelPacket *GetVirtualPixelsCache(const Image *image)
3696{
3697 CacheInfo
3698 *cache_info;
3699
cristy5c9e6f22010-09-17 17:31:01 +00003700 const int
3701 id = GetOpenMPThreadId();
3702
cristye7cc7cf2010-09-21 13:26:47 +00003703 assert(image != (const Image *) NULL);
3704 assert(image->signature == MagickSignature);
3705 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003706 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003707 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003708 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003709 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003710}
3711
3712/*
3713%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3714% %
3715% %
3716% %
3717+ G e t V i r t u a l P i x e l s N e x u s %
3718% %
3719% %
3720% %
3721%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3722%
3723% GetVirtualPixelsNexus() returns the pixels associated with the specified
3724% cache nexus.
3725%
3726% The format of the GetVirtualPixelsNexus() method is:
3727%
3728% const IndexPacket *GetVirtualPixelsNexus(const Cache cache,
3729% NexusInfo *nexus_info)
3730%
3731% A description of each parameter follows:
3732%
3733% o cache: the pixel cache.
3734%
3735% o nexus_info: the cache nexus to return the colormap pixels.
3736%
3737*/
3738MagickExport const PixelPacket *GetVirtualPixelsNexus(const Cache cache,
3739 NexusInfo *nexus_info)
3740{
3741 CacheInfo
3742 *cache_info;
3743
cristye7cc7cf2010-09-21 13:26:47 +00003744 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003745 cache_info=(CacheInfo *) cache;
3746 assert(cache_info->signature == MagickSignature);
3747 if (cache_info->storage_class == UndefinedClass)
3748 return((PixelPacket *) NULL);
3749 return((const PixelPacket *) nexus_info->pixels);
3750}
3751
3752/*
3753%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3754% %
3755% %
3756% %
3757+ M a s k P i x e l C a c h e N e x u s %
3758% %
3759% %
3760% %
3761%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3762%
3763% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3764% The method returns MagickTrue if the pixel region is masked, otherwise
3765% MagickFalse.
3766%
3767% The format of the MaskPixelCacheNexus() method is:
3768%
3769% MagickBooleanType MaskPixelCacheNexus(Image *image,
3770% NexusInfo *nexus_info,ExceptionInfo *exception)
3771%
3772% A description of each parameter follows:
3773%
3774% o image: the image.
3775%
3776% o nexus_info: the cache nexus to clip.
3777%
3778% o exception: return any errors or warnings in this structure.
3779%
3780*/
3781
3782static inline void MagickPixelCompositeMask(const MagickPixelPacket *p,
3783 const MagickRealType alpha,const MagickPixelPacket *q,
3784 const MagickRealType beta,MagickPixelPacket *composite)
3785{
3786 MagickRealType
3787 gamma;
3788
3789 if (alpha == TransparentOpacity)
3790 {
3791 *composite=(*q);
3792 return;
3793 }
3794 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3795 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3796 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3797 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3798 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3799 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3800 composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
3801}
3802
3803static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3804 ExceptionInfo *exception)
3805{
3806 CacheInfo
3807 *cache_info;
3808
3809 MagickPixelPacket
3810 alpha,
3811 beta;
3812
3813 MagickSizeType
3814 number_pixels;
3815
3816 NexusInfo
3817 **clip_nexus,
3818 **image_nexus;
3819
3820 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003821 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003822
3823 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003824 *restrict nexus_indexes,
3825 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003826
cristy3ed852e2009-09-05 21:47:34 +00003827 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003828 *restrict p,
3829 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003830
cristye076a6e2010-08-15 19:59:43 +00003831 register ssize_t
3832 i;
3833
cristy3ed852e2009-09-05 21:47:34 +00003834 /*
3835 Apply clip mask.
3836 */
3837 if (image->debug != MagickFalse)
3838 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3839 if (image->mask == (Image *) NULL)
3840 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +00003841 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00003842 if (cache_info == (Cache) NULL)
3843 return(MagickFalse);
3844 image_nexus=AcquirePixelCacheNexus(1);
3845 clip_nexus=AcquirePixelCacheNexus(1);
3846 if ((image_nexus == (NexusInfo **) NULL) ||
3847 (clip_nexus == (NexusInfo **) NULL))
3848 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy09449f72010-01-23 03:08:36 +00003849 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,
3850 nexus_info->region.y,nexus_info->region.width,nexus_info->region.height,
3851 image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003852 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
3853 q=nexus_info->pixels;
3854 nexus_indexes=nexus_info->indexes;
3855 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3856 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3857 nexus_info->region.height,clip_nexus[0],&image->exception);
3858 GetMagickPixelPacket(image,&alpha);
3859 GetMagickPixelPacket(image,&beta);
3860 number_pixels=(MagickSizeType) nexus_info->region.width*
3861 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +00003862 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +00003863 {
3864 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
3865 break;
3866 SetMagickPixelPacket(image,p,indexes+i,&alpha);
3867 SetMagickPixelPacket(image,q,nexus_indexes+i,&beta);
3868 MagickPixelCompositeMask(&beta,(MagickRealType) PixelIntensityToQuantum(r),
3869 &alpha,alpha.opacity,&beta);
cristyce70c172010-01-07 17:15:30 +00003870 q->red=ClampToQuantum(beta.red);
3871 q->green=ClampToQuantum(beta.green);
3872 q->blue=ClampToQuantum(beta.blue);
3873 q->opacity=ClampToQuantum(beta.opacity);
cristy3ed852e2009-09-05 21:47:34 +00003874 if (cache_info->active_index_channel != MagickFalse)
3875 nexus_indexes[i]=indexes[i];
3876 p++;
3877 q++;
3878 r++;
3879 }
3880 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3881 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +00003882 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003883 return(MagickFalse);
3884 return(MagickTrue);
3885}
3886
3887/*
3888%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3889% %
3890% %
3891% %
3892+ O p e n P i x e l C a c h e %
3893% %
3894% %
3895% %
3896%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3897%
3898% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3899% dimensions, allocating space for the image pixels and optionally the
3900% colormap indexes, and memory mapping the cache if it is disk based. The
3901% cache nexus array is initialized as well.
3902%
3903% The format of the OpenPixelCache() method is:
3904%
3905% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3906% ExceptionInfo *exception)
3907%
3908% A description of each parameter follows:
3909%
3910% o image: the image.
3911%
3912% o mode: ReadMode, WriteMode, or IOMode.
3913%
3914% o exception: return any errors or warnings in this structure.
3915%
3916*/
3917
cristyd43a46b2010-01-21 02:13:41 +00003918static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003919{
3920 cache_info->mapped=MagickFalse;
3921 cache_info->pixels=(PixelPacket *) AcquireMagickMemory((size_t)
3922 cache_info->length);
3923 if (cache_info->pixels == (PixelPacket *) NULL)
3924 {
3925 cache_info->mapped=MagickTrue;
3926 cache_info->pixels=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
3927 cache_info->length);
3928 }
3929}
3930
3931static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3932{
3933 CacheInfo
3934 *cache_info;
3935
3936 MagickOffsetType
3937 count,
3938 extent,
3939 offset;
3940
3941 cache_info=(CacheInfo *) image->cache;
3942 if (image->debug != MagickFalse)
3943 {
3944 char
3945 format[MaxTextExtent],
3946 message[MaxTextExtent];
3947
cristyb9080c92009-12-01 20:13:26 +00003948 (void) FormatMagickSize(length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00003949 (void) FormatMagickString(message,MaxTextExtent,
cristy2ce15c92010-03-12 14:03:41 +00003950 "extend %s (%s[%d], disk, %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003951 cache_info->cache_filename,cache_info->file,format);
3952 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3953 }
3954 if (length != (MagickSizeType) ((MagickOffsetType) length))
3955 return(MagickFalse);
cristy7f317702011-02-18 20:40:28 +00003956 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
cristy3ed852e2009-09-05 21:47:34 +00003957 if (extent < 0)
3958 return(MagickFalse);
3959 if ((MagickSizeType) extent >= length)
3960 return(MagickTrue);
3961 offset=(MagickOffsetType) length-1;
3962 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3963 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3964}
3965
3966static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3967 ExceptionInfo *exception)
3968{
cristy3ed852e2009-09-05 21:47:34 +00003969 CacheInfo
3970 *cache_info,
3971 source_info;
3972
cristyf3a6a9d2010-11-07 21:02:56 +00003973 char
3974 format[MaxTextExtent],
3975 message[MaxTextExtent];
3976
cristy3ed852e2009-09-05 21:47:34 +00003977 MagickSizeType
3978 length,
3979 number_pixels;
3980
3981 MagickStatusType
3982 status;
3983
3984 size_t
cristye076a6e2010-08-15 19:59:43 +00003985 columns,
cristy3ed852e2009-09-05 21:47:34 +00003986 packet_size;
3987
cristye7cc7cf2010-09-21 13:26:47 +00003988 assert(image != (const Image *) NULL);
3989 assert(image->signature == MagickSignature);
3990 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003991 if (image->debug != MagickFalse)
3992 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3993 if ((image->columns == 0) || (image->rows == 0))
3994 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3995 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003996 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003997 source_info=(*cache_info);
3998 source_info.file=(-1);
cristye8c25f92010-06-03 00:53:06 +00003999 (void) FormatMagickString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
4000 image->filename,(double) GetImageIndexInList(image));
cristy87528ea2009-09-10 14:53:56 +00004001 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +00004002 cache_info->rows=image->rows;
4003 cache_info->columns=image->columns;
4004 cache_info->active_index_channel=((image->storage_class == PseudoClass) ||
4005 (image->colorspace == CMYKColorspace)) ? MagickTrue : MagickFalse;
cristy73724512010-04-12 14:43:14 +00004006 if (image->ping != MagickFalse)
4007 {
4008 cache_info->storage_class=image->storage_class;
4009 cache_info->colorspace=image->colorspace;
4010 cache_info->type=PingCache;
4011 cache_info->pixels=(PixelPacket *) NULL;
4012 cache_info->indexes=(IndexPacket *) NULL;
4013 cache_info->length=0;
4014 return(MagickTrue);
4015 }
cristy3ed852e2009-09-05 21:47:34 +00004016 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4017 packet_size=sizeof(PixelPacket);
4018 if (cache_info->active_index_channel != MagickFalse)
4019 packet_size+=sizeof(IndexPacket);
4020 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00004021 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00004022 if (cache_info->columns != columns)
4023 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4024 image->filename);
4025 cache_info->length=length;
4026 status=AcquireMagickResource(AreaResource,cache_info->length);
4027 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4028 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4029 {
4030 status=AcquireMagickResource(MemoryResource,cache_info->length);
4031 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4032 (cache_info->type == MemoryCache))
4033 {
cristyd43a46b2010-01-21 02:13:41 +00004034 AllocatePixelCachePixels(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004035 if (cache_info->pixels == (PixelPacket *) NULL)
4036 cache_info->pixels=source_info.pixels;
4037 else
4038 {
4039 /*
4040 Create memory pixel cache.
4041 */
4042 if (image->debug != MagickFalse)
4043 {
cristy97e7a572009-12-05 15:07:53 +00004044 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004045 format);
cristy3ed852e2009-09-05 21:47:34 +00004046 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004047 "open %s (%s memory, %.20gx%.20g %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00004048 cache_info->mapped != MagickFalse ? "anonymous" : "heap",
cristye8c25f92010-06-03 00:53:06 +00004049 (double) cache_info->columns,(double) cache_info->rows,
4050 format);
cristy3ed852e2009-09-05 21:47:34 +00004051 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4052 message);
4053 }
4054 cache_info->storage_class=image->storage_class;
4055 cache_info->colorspace=image->colorspace;
4056 cache_info->type=MemoryCache;
4057 cache_info->indexes=(IndexPacket *) NULL;
4058 if (cache_info->active_index_channel != MagickFalse)
4059 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4060 number_pixels);
4061 if (source_info.storage_class != UndefinedClass)
4062 {
4063 status|=ClonePixelCachePixels(cache_info,&source_info,
4064 exception);
4065 RelinquishPixelCachePixels(&source_info);
4066 }
4067 return(MagickTrue);
4068 }
4069 }
4070 RelinquishMagickResource(MemoryResource,cache_info->length);
4071 }
4072 /*
4073 Create pixel cache on disk.
4074 */
4075 status=AcquireMagickResource(DiskResource,cache_info->length);
4076 if (status == MagickFalse)
4077 {
4078 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4079 "CacheResourcesExhausted","`%s'",image->filename);
4080 return(MagickFalse);
4081 }
4082 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4083 {
4084 RelinquishMagickResource(DiskResource,cache_info->length);
4085 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4086 image->filename);
4087 return(MagickFalse);
4088 }
4089 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4090 cache_info->length);
4091 if (status == MagickFalse)
4092 {
4093 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4094 image->filename);
4095 return(MagickFalse);
4096 }
4097 cache_info->storage_class=image->storage_class;
4098 cache_info->colorspace=image->colorspace;
4099 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4100 status=AcquireMagickResource(AreaResource,cache_info->length);
4101 if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4102 cache_info->type=DiskCache;
4103 else
4104 {
4105 status=AcquireMagickResource(MapResource,cache_info->length);
4106 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4107 (cache_info->type != MemoryCache))
4108 cache_info->type=DiskCache;
4109 else
4110 {
4111 cache_info->pixels=(PixelPacket *) MapBlob(cache_info->file,mode,
4112 cache_info->offset,(size_t) cache_info->length);
4113 if (cache_info->pixels == (PixelPacket *) NULL)
4114 {
4115 cache_info->pixels=source_info.pixels;
4116 cache_info->type=DiskCache;
4117 }
4118 else
4119 {
4120 /*
4121 Create file-backed memory-mapped pixel cache.
4122 */
4123 (void) ClosePixelCacheOnDisk(cache_info);
4124 cache_info->type=MapCache;
4125 cache_info->mapped=MagickTrue;
4126 cache_info->indexes=(IndexPacket *) NULL;
4127 if (cache_info->active_index_channel != MagickFalse)
4128 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4129 number_pixels);
4130 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4131 {
4132 status=ClonePixelCachePixels(cache_info,&source_info,
4133 exception);
4134 RelinquishPixelCachePixels(&source_info);
4135 }
4136 if (image->debug != MagickFalse)
4137 {
cristy97e7a572009-12-05 15:07:53 +00004138 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004139 format);
cristy3ed852e2009-09-05 21:47:34 +00004140 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004141 "open %s (%s[%d], memory-mapped, %.20gx%.20g %sB)",
cristy3ed852e2009-09-05 21:47:34 +00004142 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004143 cache_info->file,(double) cache_info->columns,(double)
4144 cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004145 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4146 message);
4147 }
4148 return(MagickTrue);
4149 }
4150 }
4151 RelinquishMagickResource(MapResource,cache_info->length);
4152 }
4153 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4154 {
4155 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4156 RelinquishPixelCachePixels(&source_info);
4157 }
4158 if (image->debug != MagickFalse)
4159 {
cristyb9080c92009-12-01 20:13:26 +00004160 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00004161 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004162 "open %s (%s[%d], disk, %.20gx%.20g %sB)",cache_info->filename,
4163 cache_info->cache_filename,cache_info->file,(double)
4164 cache_info->columns,(double) cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004165 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4166 }
4167 return(MagickTrue);
4168}
4169
4170/*
4171%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4172% %
4173% %
4174% %
4175+ P e r s i s t P i x e l C a c h e %
4176% %
4177% %
4178% %
4179%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4180%
4181% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4182% persistent pixel cache is one that resides on disk and is not destroyed
4183% when the program exits.
4184%
4185% The format of the PersistPixelCache() method is:
4186%
4187% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4188% const MagickBooleanType attach,MagickOffsetType *offset,
4189% ExceptionInfo *exception)
4190%
4191% A description of each parameter follows:
4192%
4193% o image: the image.
4194%
4195% o filename: the persistent pixel cache filename.
4196%
cristyf3a6a9d2010-11-07 21:02:56 +00004197% o attach: A value other than zero initializes the persistent pixel cache.
cristy01b7eb02009-09-10 23:10:14 +00004198%
cristy3ed852e2009-09-05 21:47:34 +00004199% o initialize: A value other than zero initializes the persistent pixel
4200% cache.
4201%
4202% o offset: the offset in the persistent cache to store pixels.
4203%
4204% o exception: return any errors or warnings in this structure.
4205%
4206*/
4207MagickExport MagickBooleanType PersistPixelCache(Image *image,
4208 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4209 ExceptionInfo *exception)
4210{
4211 CacheInfo
4212 *cache_info,
4213 *clone_info;
4214
4215 Image
4216 clone_image;
4217
cristy3ed852e2009-09-05 21:47:34 +00004218 MagickBooleanType
4219 status;
4220
cristye076a6e2010-08-15 19:59:43 +00004221 ssize_t
4222 page_size;
4223
cristy3ed852e2009-09-05 21:47:34 +00004224 assert(image != (Image *) NULL);
4225 assert(image->signature == MagickSignature);
4226 if (image->debug != MagickFalse)
4227 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4228 assert(image->cache != (void *) NULL);
4229 assert(filename != (const char *) NULL);
4230 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004231 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004232 cache_info=(CacheInfo *) image->cache;
4233 assert(cache_info->signature == MagickSignature);
4234 if (attach != MagickFalse)
4235 {
4236 /*
cristy01b7eb02009-09-10 23:10:14 +00004237 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004238 */
4239 if (image->debug != MagickFalse)
4240 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004241 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004242 (void) CopyMagickString(cache_info->cache_filename,filename,
4243 MaxTextExtent);
4244 cache_info->type=DiskCache;
4245 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004246 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004247 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004248 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004249 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004250 }
cristy01b7eb02009-09-10 23:10:14 +00004251 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4252 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004253 {
cristyf84a1932010-01-03 18:00:18 +00004254 LockSemaphoreInfo(cache_info->semaphore);
cristy09449f72010-01-23 03:08:36 +00004255 if ((cache_info->mode != ReadMode) &&
4256 (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004257 (cache_info->reference_count == 1))
4258 {
4259 int
4260 status;
4261
4262 /*
cristy01b7eb02009-09-10 23:10:14 +00004263 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004264 */
4265 status=rename(cache_info->cache_filename,filename);
4266 if (status == 0)
4267 {
4268 (void) CopyMagickString(cache_info->cache_filename,filename,
4269 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004270 *offset+=cache_info->length+page_size-(cache_info->length %
4271 page_size);
cristyf84a1932010-01-03 18:00:18 +00004272 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004273 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004274 if (image->debug != MagickFalse)
4275 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4276 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004277 return(MagickTrue);
4278 }
4279 }
cristyf84a1932010-01-03 18:00:18 +00004280 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004281 }
4282 /*
cristy01b7eb02009-09-10 23:10:14 +00004283 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004284 */
4285 clone_image=(*image);
4286 clone_info=(CacheInfo *) clone_image.cache;
4287 image->cache=ClonePixelCache(cache_info);
4288 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4289 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4290 cache_info->type=DiskCache;
4291 cache_info->offset=(*offset);
4292 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004293 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004294 if (status != MagickFalse)
cristycfae90a2010-10-04 14:43:33 +00004295 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
cristy688f07b2009-09-27 15:19:13 +00004296 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004297 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4298 return(status);
4299}
4300
4301/*
4302%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4303% %
4304% %
4305% %
4306+ Q u e u e A u t h e n t i c N e x u s %
4307% %
4308% %
4309% %
4310%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4311%
4312% QueueAuthenticNexus() allocates an region to store image pixels as defined
4313% by the region rectangle and returns a pointer to the region. This region is
4314% subsequently transferred from the pixel cache with
4315% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4316% pixels are transferred, otherwise a NULL is returned.
4317%
4318% The format of the QueueAuthenticNexus() method is:
4319%
cristy5f959472010-05-27 22:19:46 +00004320% PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
4321% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004322% NexusInfo *nexus_info,ExceptionInfo *exception)
4323%
4324% A description of each parameter follows:
4325%
4326% o image: the image.
4327%
4328% o x,y,columns,rows: These values define the perimeter of a region of
4329% pixels.
4330%
4331% o nexus_info: the cache nexus to set.
4332%
4333% o exception: return any errors or warnings in this structure.
4334%
4335*/
cristybb503372010-05-27 20:51:26 +00004336MagickExport PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy30097232010-07-01 02:16:30 +00004337 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
4338 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004339{
4340 CacheInfo
4341 *cache_info;
4342
4343 MagickOffsetType
4344 offset;
4345
4346 MagickSizeType
4347 number_pixels;
4348
4349 RectangleInfo
4350 region;
4351
4352 /*
4353 Validate pixel cache geometry.
4354 */
cristye7cc7cf2010-09-21 13:26:47 +00004355 assert(image != (const Image *) NULL);
4356 assert(image->signature == MagickSignature);
4357 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004358 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
cristye7cc7cf2010-09-21 13:26:47 +00004359 assert(cache_info->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00004360 if (cache_info == (Cache) NULL)
4361 return((PixelPacket *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004362 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4363 {
4364 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4365 "NoPixelsDefinedInCache","`%s'",image->filename);
4366 return((PixelPacket *) NULL);
4367 }
cristybb503372010-05-27 20:51:26 +00004368 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4369 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004370 {
4371 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4372 "PixelsAreNotAuthentic","`%s'",image->filename);
4373 return((PixelPacket *) NULL);
4374 }
4375 offset=(MagickOffsetType) y*cache_info->columns+x;
4376 if (offset < 0)
4377 return((PixelPacket *) NULL);
4378 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4379 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4380 if ((MagickSizeType) offset >= number_pixels)
4381 return((PixelPacket *) NULL);
4382 /*
4383 Return pixel cache.
4384 */
4385 region.x=x;
4386 region.y=y;
4387 region.width=columns;
4388 region.height=rows;
4389 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4390}
4391
4392/*
4393%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4394% %
4395% %
4396% %
4397+ 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 %
4398% %
4399% %
4400% %
4401%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4402%
4403% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4404% defined by the region rectangle and returns a pointer to the region. This
4405% region is subsequently transferred from the pixel cache with
4406% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4407% pixels are transferred, otherwise a NULL is returned.
4408%
4409% The format of the QueueAuthenticPixelsCache() method is:
4410%
cristybb503372010-05-27 20:51:26 +00004411% PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4412% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004413% ExceptionInfo *exception)
4414%
4415% A description of each parameter follows:
4416%
4417% o image: the image.
4418%
4419% o x,y,columns,rows: These values define the perimeter of a region of
4420% pixels.
4421%
4422% o exception: return any errors or warnings in this structure.
4423%
4424*/
cristybb503372010-05-27 20:51:26 +00004425static PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4426 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004427 ExceptionInfo *exception)
4428{
4429 CacheInfo
4430 *cache_info;
4431
cristy5c9e6f22010-09-17 17:31:01 +00004432 const int
4433 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004434
cristye7cc7cf2010-09-21 13:26:47 +00004435 assert(image != (const Image *) NULL);
4436 assert(image->signature == MagickSignature);
4437 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004438 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004439 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004440 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00004441 return(QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4442 exception));
cristy3ed852e2009-09-05 21:47:34 +00004443}
4444
4445/*
4446%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4447% %
4448% %
4449% %
4450% Q u e u e A u t h e n t i c P i x e l s %
4451% %
4452% %
4453% %
4454%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4455%
4456% QueueAuthenticPixels() queues a mutable pixel region. If the region is
4457% successfully intialized a pointer to a PixelPacket array representing the
4458% region is returned, otherwise NULL is returned. The returned pointer may
4459% point to a temporary working buffer for the pixels or it may point to the
4460% final location of the pixels in memory.
4461%
4462% Write-only access means that any existing pixel values corresponding to
4463% the region are ignored. This is useful if the initial image is being
4464% created from scratch, or if the existing pixel values are to be
4465% completely replaced without need to refer to their pre-existing values.
4466% The application is free to read and write the pixel buffer returned by
4467% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4468% initialize the pixel array values. Initializing pixel array values is the
4469% application's responsibility.
4470%
4471% Performance is maximized if the selected region is part of one row, or
4472% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004473% pixels in-place (without a copy) if the image is in memory, or in a
4474% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004475% by the user.
4476%
4477% Pixels accessed via the returned pointer represent a simple array of type
4478% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
4479% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
4480% the black color component or the colormap indexes (of type IndexPacket)
4481% corresponding to the region. Once the PixelPacket (and/or IndexPacket)
4482% array has been updated, the changes must be saved back to the underlying
4483% image using SyncAuthenticPixels() or they may be lost.
4484%
4485% The format of the QueueAuthenticPixels() method is:
4486%
cristy5f959472010-05-27 22:19:46 +00004487% PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4488% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004489% ExceptionInfo *exception)
4490%
4491% A description of each parameter follows:
4492%
4493% o image: the image.
4494%
4495% o x,y,columns,rows: These values define the perimeter of a region of
4496% pixels.
4497%
4498% o exception: return any errors or warnings in this structure.
4499%
4500*/
cristybb503372010-05-27 20:51:26 +00004501MagickExport PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4502 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004503 ExceptionInfo *exception)
4504{
4505 CacheInfo
4506 *cache_info;
4507
cristy2036f5c2010-09-19 21:18:17 +00004508 const int
4509 id = GetOpenMPThreadId();
4510
cristy3ed852e2009-09-05 21:47:34 +00004511 assert(image != (Image *) NULL);
4512 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004513 assert(image->cache != (Cache) NULL);
4514 cache_info=(CacheInfo *) image->cache;
4515 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004516 if (cache_info->methods.queue_authentic_pixels_handler !=
4517 (QueueAuthenticPixelsHandler) NULL)
4518 return(cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4519 rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00004520 assert(id < (int) cache_info->number_threads);
4521 return(QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4522 exception));
cristy3ed852e2009-09-05 21:47:34 +00004523}
4524
4525/*
4526%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4527% %
4528% %
4529% %
4530+ R e a d P i x e l C a c h e I n d e x e s %
4531% %
4532% %
4533% %
4534%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4535%
4536% ReadPixelCacheIndexes() reads colormap indexes from the specified region of
4537% the pixel cache.
4538%
4539% The format of the ReadPixelCacheIndexes() method is:
4540%
4541% MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4542% NexusInfo *nexus_info,ExceptionInfo *exception)
4543%
4544% A description of each parameter follows:
4545%
4546% o cache_info: the pixel cache.
4547%
4548% o nexus_info: the cache nexus to read the colormap indexes.
4549%
4550% o exception: return any errors or warnings in this structure.
4551%
4552*/
4553static MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4554 NexusInfo *nexus_info,ExceptionInfo *exception)
4555{
4556 MagickOffsetType
4557 count,
4558 offset;
4559
4560 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004561 extent,
4562 length;
cristy3ed852e2009-09-05 21:47:34 +00004563
4564 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004565 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004566
cristybb503372010-05-27 20:51:26 +00004567 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004568 y;
4569
cristybb503372010-05-27 20:51:26 +00004570 size_t
cristy3ed852e2009-09-05 21:47:34 +00004571 rows;
4572
cristy3ed852e2009-09-05 21:47:34 +00004573 if (cache_info->active_index_channel == MagickFalse)
4574 return(MagickFalse);
4575 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4576 return(MagickTrue);
4577 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4578 nexus_info->region.x;
4579 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
4580 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004581 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004582 q=nexus_info->indexes;
4583 switch (cache_info->type)
4584 {
4585 case MemoryCache:
4586 case MapCache:
4587 {
4588 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004589 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004590
4591 /*
4592 Read indexes from memory.
4593 */
cristydd341db2010-03-04 19:06:38 +00004594 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004595 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004596 {
cristy48078b12010-09-23 17:11:01 +00004597 length=extent;
cristydd341db2010-03-04 19:06:38 +00004598 rows=1UL;
4599 }
cristy3ed852e2009-09-05 21:47:34 +00004600 p=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00004601 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004602 {
cristy8f036fe2010-09-18 02:02:00 +00004603 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00004604 p+=cache_info->columns;
4605 q+=nexus_info->region.width;
4606 }
4607 break;
4608 }
4609 case DiskCache:
4610 {
4611 /*
4612 Read indexes from disk.
4613 */
4614 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4615 {
4616 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4617 cache_info->cache_filename);
4618 return(MagickFalse);
4619 }
cristydd341db2010-03-04 19:06:38 +00004620 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004621 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004622 {
cristy48078b12010-09-23 17:11:01 +00004623 length=extent;
cristydd341db2010-03-04 19:06:38 +00004624 rows=1UL;
4625 }
cristy48078b12010-09-23 17:11:01 +00004626 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004627 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004628 {
cristy48078b12010-09-23 17:11:01 +00004629 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristy3ed852e2009-09-05 21:47:34 +00004630 sizeof(PixelPacket)+offset*sizeof(*q),length,(unsigned char *) q);
4631 if ((MagickSizeType) count < length)
4632 break;
4633 offset+=cache_info->columns;
4634 q+=nexus_info->region.width;
4635 }
cristybb503372010-05-27 20:51:26 +00004636 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004637 {
4638 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4639 cache_info->cache_filename);
4640 return(MagickFalse);
4641 }
4642 break;
4643 }
4644 default:
4645 break;
4646 }
4647 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004648 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004649 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004650 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004651 nexus_info->region.width,(double) nexus_info->region.height,(double)
4652 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004653 return(MagickTrue);
4654}
4655
4656/*
4657%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4658% %
4659% %
4660% %
4661+ R e a d P i x e l C a c h e P i x e l s %
4662% %
4663% %
4664% %
4665%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4666%
4667% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4668% cache.
4669%
4670% The format of the ReadPixelCachePixels() method is:
4671%
4672% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4673% NexusInfo *nexus_info,ExceptionInfo *exception)
4674%
4675% A description of each parameter follows:
4676%
4677% o cache_info: the pixel cache.
4678%
4679% o nexus_info: the cache nexus to read the pixels.
4680%
4681% o exception: return any errors or warnings in this structure.
4682%
4683*/
4684static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4685 NexusInfo *nexus_info,ExceptionInfo *exception)
4686{
4687 MagickOffsetType
4688 count,
4689 offset;
4690
4691 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004692 extent,
4693 length;
cristy3ed852e2009-09-05 21:47:34 +00004694
cristy3ed852e2009-09-05 21:47:34 +00004695 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004696 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004697
cristye076a6e2010-08-15 19:59:43 +00004698 register ssize_t
4699 y;
4700
cristybb503372010-05-27 20:51:26 +00004701 size_t
cristy3ed852e2009-09-05 21:47:34 +00004702 rows;
4703
cristy3ed852e2009-09-05 21:47:34 +00004704 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4705 return(MagickTrue);
4706 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4707 nexus_info->region.x;
4708 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
4709 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004710 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004711 q=nexus_info->pixels;
4712 switch (cache_info->type)
4713 {
4714 case MemoryCache:
4715 case MapCache:
4716 {
4717 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004718 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004719
4720 /*
4721 Read pixels from memory.
4722 */
cristydd341db2010-03-04 19:06:38 +00004723 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004724 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004725 {
cristy48078b12010-09-23 17:11:01 +00004726 length=extent;
cristydd341db2010-03-04 19:06:38 +00004727 rows=1UL;
4728 }
cristy3ed852e2009-09-05 21:47:34 +00004729 p=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00004730 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004731 {
cristy8f036fe2010-09-18 02:02:00 +00004732 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00004733 p+=cache_info->columns;
4734 q+=nexus_info->region.width;
4735 }
4736 break;
4737 }
4738 case DiskCache:
4739 {
4740 /*
4741 Read pixels from disk.
4742 */
4743 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4744 {
4745 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4746 cache_info->cache_filename);
4747 return(MagickFalse);
4748 }
cristydd341db2010-03-04 19:06:38 +00004749 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004750 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004751 {
cristy48078b12010-09-23 17:11:01 +00004752 length=extent;
cristydd341db2010-03-04 19:06:38 +00004753 rows=1UL;
4754 }
cristybb503372010-05-27 20:51:26 +00004755 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004756 {
4757 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4758 sizeof(*q),length,(unsigned char *) q);
4759 if ((MagickSizeType) count < length)
4760 break;
4761 offset+=cache_info->columns;
4762 q+=nexus_info->region.width;
4763 }
cristybb503372010-05-27 20:51:26 +00004764 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004765 {
4766 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4767 cache_info->cache_filename);
4768 return(MagickFalse);
4769 }
4770 break;
4771 }
4772 default:
4773 break;
4774 }
4775 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004776 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004777 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004778 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004779 nexus_info->region.width,(double) nexus_info->region.height,(double)
4780 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004781 return(MagickTrue);
4782}
4783
4784/*
4785%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4786% %
4787% %
4788% %
4789+ R e f e r e n c e P i x e l C a c h e %
4790% %
4791% %
4792% %
4793%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4794%
4795% ReferencePixelCache() increments the reference count associated with the
4796% pixel cache returning a pointer to the cache.
4797%
4798% The format of the ReferencePixelCache method is:
4799%
4800% Cache ReferencePixelCache(Cache cache_info)
4801%
4802% A description of each parameter follows:
4803%
4804% o cache_info: the pixel cache.
4805%
4806*/
4807MagickExport Cache ReferencePixelCache(Cache cache)
4808{
4809 CacheInfo
4810 *cache_info;
4811
4812 assert(cache != (Cache *) NULL);
4813 cache_info=(CacheInfo *) cache;
4814 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004815 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004816 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004817 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004818 return(cache_info);
4819}
4820
4821/*
4822%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4823% %
4824% %
4825% %
4826+ S e t P i x e l C a c h e M e t h o d s %
4827% %
4828% %
4829% %
4830%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4831%
4832% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4833%
4834% The format of the SetPixelCacheMethods() method is:
4835%
4836% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4837%
4838% A description of each parameter follows:
4839%
4840% o cache: the pixel cache.
4841%
4842% o cache_methods: Specifies a pointer to a CacheMethods structure.
4843%
4844*/
4845MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4846{
4847 CacheInfo
4848 *cache_info;
4849
4850 GetOneAuthenticPixelFromHandler
4851 get_one_authentic_pixel_from_handler;
4852
4853 GetOneVirtualPixelFromHandler
4854 get_one_virtual_pixel_from_handler;
4855
4856 /*
4857 Set cache pixel methods.
4858 */
4859 assert(cache != (Cache) NULL);
4860 assert(cache_methods != (CacheMethods *) NULL);
4861 cache_info=(CacheInfo *) cache;
4862 assert(cache_info->signature == MagickSignature);
4863 if (cache_info->debug != MagickFalse)
4864 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4865 cache_info->filename);
4866 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4867 cache_info->methods.get_virtual_pixel_handler=
4868 cache_methods->get_virtual_pixel_handler;
4869 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4870 cache_info->methods.destroy_pixel_handler=
4871 cache_methods->destroy_pixel_handler;
4872 if (cache_methods->get_virtual_indexes_from_handler !=
4873 (GetVirtualIndexesFromHandler) NULL)
4874 cache_info->methods.get_virtual_indexes_from_handler=
4875 cache_methods->get_virtual_indexes_from_handler;
4876 if (cache_methods->get_authentic_pixels_handler !=
4877 (GetAuthenticPixelsHandler) NULL)
4878 cache_info->methods.get_authentic_pixels_handler=
4879 cache_methods->get_authentic_pixels_handler;
4880 if (cache_methods->queue_authentic_pixels_handler !=
4881 (QueueAuthenticPixelsHandler) NULL)
4882 cache_info->methods.queue_authentic_pixels_handler=
4883 cache_methods->queue_authentic_pixels_handler;
4884 if (cache_methods->sync_authentic_pixels_handler !=
4885 (SyncAuthenticPixelsHandler) NULL)
4886 cache_info->methods.sync_authentic_pixels_handler=
4887 cache_methods->sync_authentic_pixels_handler;
4888 if (cache_methods->get_authentic_pixels_from_handler !=
4889 (GetAuthenticPixelsFromHandler) NULL)
4890 cache_info->methods.get_authentic_pixels_from_handler=
4891 cache_methods->get_authentic_pixels_from_handler;
4892 if (cache_methods->get_authentic_indexes_from_handler !=
4893 (GetAuthenticIndexesFromHandler) NULL)
4894 cache_info->methods.get_authentic_indexes_from_handler=
4895 cache_methods->get_authentic_indexes_from_handler;
4896 get_one_virtual_pixel_from_handler=
4897 cache_info->methods.get_one_virtual_pixel_from_handler;
4898 if (get_one_virtual_pixel_from_handler !=
4899 (GetOneVirtualPixelFromHandler) NULL)
4900 cache_info->methods.get_one_virtual_pixel_from_handler=
4901 cache_methods->get_one_virtual_pixel_from_handler;
4902 get_one_authentic_pixel_from_handler=
4903 cache_methods->get_one_authentic_pixel_from_handler;
4904 if (get_one_authentic_pixel_from_handler !=
4905 (GetOneAuthenticPixelFromHandler) NULL)
4906 cache_info->methods.get_one_authentic_pixel_from_handler=
4907 cache_methods->get_one_authentic_pixel_from_handler;
4908}
4909
4910/*
4911%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4912% %
4913% %
4914% %
4915+ S e t P i x e l C a c h e N e x u s P i x e l s %
4916% %
4917% %
4918% %
4919%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4920%
4921% SetPixelCacheNexusPixels() defines the region of the cache for the
4922% specified cache nexus.
4923%
4924% The format of the SetPixelCacheNexusPixels() method is:
4925%
4926% PixelPacket SetPixelCacheNexusPixels(const Image *image,
4927% const RectangleInfo *region,NexusInfo *nexus_info,
4928% ExceptionInfo *exception)
4929%
4930% A description of each parameter follows:
4931%
4932% o image: the image.
4933%
4934% o region: A pointer to the RectangleInfo structure that defines the
4935% region of this particular cache nexus.
4936%
4937% o nexus_info: the cache nexus to set.
4938%
4939% o exception: return any errors or warnings in this structure.
4940%
4941*/
cristyabd6e372010-09-15 19:11:26 +00004942
4943static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4944 NexusInfo *nexus_info,ExceptionInfo *exception)
4945{
4946 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4947 return(MagickFalse);
4948 nexus_info->mapped=MagickFalse;
4949 nexus_info->cache=(PixelPacket *) AcquireMagickMemory((size_t)
4950 nexus_info->length);
4951 if (nexus_info->cache == (PixelPacket *) NULL)
4952 {
4953 nexus_info->mapped=MagickTrue;
4954 nexus_info->cache=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
4955 nexus_info->length);
4956 }
4957 if (nexus_info->cache == (PixelPacket *) NULL)
4958 {
4959 (void) ThrowMagickException(exception,GetMagickModule(),
4960 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4961 cache_info->filename);
4962 return(MagickFalse);
4963 }
4964 return(MagickTrue);
4965}
4966
cristy3ed852e2009-09-05 21:47:34 +00004967static PixelPacket *SetPixelCacheNexusPixels(const Image *image,
4968 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4969{
4970 CacheInfo
4971 *cache_info;
4972
4973 MagickBooleanType
4974 status;
4975
cristy3ed852e2009-09-05 21:47:34 +00004976 MagickSizeType
4977 length,
4978 number_pixels;
4979
cristy3ed852e2009-09-05 21:47:34 +00004980 cache_info=(CacheInfo *) image->cache;
4981 assert(cache_info->signature == MagickSignature);
4982 if (cache_info->type == UndefinedCache)
4983 return((PixelPacket *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00004984 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00004985 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
4986 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00004987 {
cristybb503372010-05-27 20:51:26 +00004988 ssize_t
cristybad067a2010-02-15 17:20:55 +00004989 x,
4990 y;
cristy3ed852e2009-09-05 21:47:34 +00004991
cristyeaedf062010-05-29 22:36:02 +00004992 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4993 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00004994 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4995 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00004996 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00004997 ((nexus_info->region.width == cache_info->columns) ||
4998 ((nexus_info->region.width % cache_info->columns) == 0)))))
4999 {
5000 MagickOffsetType
5001 offset;
5002
5003 /*
5004 Pixels are accessed directly from memory.
5005 */
5006 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5007 nexus_info->region.x;
5008 nexus_info->pixels=cache_info->pixels+offset;
5009 nexus_info->indexes=(IndexPacket *) NULL;
5010 if (cache_info->active_index_channel != MagickFalse)
5011 nexus_info->indexes=cache_info->indexes+offset;
5012 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00005013 }
5014 }
5015 /*
5016 Pixels are stored in a cache region until they are synced to the cache.
5017 */
5018 number_pixels=(MagickSizeType) nexus_info->region.width*
5019 nexus_info->region.height;
5020 length=number_pixels*sizeof(PixelPacket);
5021 if (cache_info->active_index_channel != MagickFalse)
5022 length+=number_pixels*sizeof(IndexPacket);
5023 if (nexus_info->cache == (PixelPacket *) NULL)
5024 {
5025 nexus_info->length=length;
5026 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5027 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005028 {
5029 nexus_info->length=0;
5030 return((PixelPacket *) NULL);
5031 }
cristy3ed852e2009-09-05 21:47:34 +00005032 }
5033 else
5034 if (nexus_info->length != length)
5035 {
5036 RelinquishCacheNexusPixels(nexus_info);
5037 nexus_info->length=length;
5038 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5039 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005040 {
5041 nexus_info->length=0;
5042 return((PixelPacket *) NULL);
5043 }
cristy3ed852e2009-09-05 21:47:34 +00005044 }
5045 nexus_info->pixels=nexus_info->cache;
5046 nexus_info->indexes=(IndexPacket *) NULL;
5047 if (cache_info->active_index_channel != MagickFalse)
5048 nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
5049 return(nexus_info->pixels);
5050}
5051
5052/*
5053%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5054% %
5055% %
5056% %
5057% 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 %
5058% %
5059% %
5060% %
5061%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5062%
5063% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5064% pixel cache and returns the previous setting. A virtual pixel is any pixel
5065% access that is outside the boundaries of the image cache.
5066%
5067% The format of the SetPixelCacheVirtualMethod() method is:
5068%
5069% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5070% const VirtualPixelMethod virtual_pixel_method)
5071%
5072% A description of each parameter follows:
5073%
5074% o image: the image.
5075%
5076% o virtual_pixel_method: choose the type of virtual pixel.
5077%
5078*/
5079MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5080 const VirtualPixelMethod virtual_pixel_method)
5081{
5082 CacheInfo
5083 *cache_info;
5084
5085 VirtualPixelMethod
5086 method;
5087
5088 assert(image != (Image *) NULL);
5089 assert(image->signature == MagickSignature);
5090 if (image->debug != MagickFalse)
5091 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5092 assert(image->cache != (Cache) NULL);
5093 cache_info=(CacheInfo *) image->cache;
5094 assert(cache_info->signature == MagickSignature);
5095 method=cache_info->virtual_pixel_method;
5096 cache_info->virtual_pixel_method=virtual_pixel_method;
5097 return(method);
5098}
5099
5100/*
5101%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5102% %
5103% %
5104% %
5105+ 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 %
5106% %
5107% %
5108% %
5109%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5110%
5111% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5112% in-memory or disk cache. The method returns MagickTrue if the pixel region
5113% is synced, otherwise MagickFalse.
5114%
5115% The format of the SyncAuthenticPixelCacheNexus() method is:
5116%
5117% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5118% NexusInfo *nexus_info,ExceptionInfo *exception)
5119%
5120% A description of each parameter follows:
5121%
5122% o image: the image.
5123%
5124% o nexus_info: the cache nexus to sync.
5125%
5126% o exception: return any errors or warnings in this structure.
5127%
5128*/
5129MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5130 NexusInfo *nexus_info,ExceptionInfo *exception)
5131{
5132 CacheInfo
5133 *cache_info;
5134
5135 MagickBooleanType
5136 status;
5137
5138 /*
5139 Transfer pixels to the cache.
5140 */
5141 assert(image != (Image *) NULL);
5142 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005143 if (image->cache == (Cache) NULL)
5144 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5145 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005146 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005147 if (cache_info->type == UndefinedCache)
5148 return(MagickFalse);
5149 if ((image->clip_mask != (Image *) NULL) &&
5150 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5151 return(MagickFalse);
5152 if ((image->mask != (Image *) NULL) &&
5153 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5154 return(MagickFalse);
5155 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5156 return(MagickTrue);
5157 assert(cache_info->signature == MagickSignature);
5158 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5159 if ((cache_info->active_index_channel != MagickFalse) &&
5160 (WritePixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse))
5161 return(MagickFalse);
5162 return(status);
5163}
5164
5165/*
5166%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5167% %
5168% %
5169% %
5170+ S y n c A u t h e n t i c P i x e l C a c h e %
5171% %
5172% %
5173% %
5174%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5175%
5176% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5177% or disk cache. The method returns MagickTrue if the pixel region is synced,
5178% otherwise MagickFalse.
5179%
5180% The format of the SyncAuthenticPixelsCache() method is:
5181%
5182% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5183% ExceptionInfo *exception)
5184%
5185% A description of each parameter follows:
5186%
5187% o image: the image.
5188%
5189% o exception: return any errors or warnings in this structure.
5190%
5191*/
5192static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5193 ExceptionInfo *exception)
5194{
5195 CacheInfo
5196 *cache_info;
5197
cristy5c9e6f22010-09-17 17:31:01 +00005198 const int
5199 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005200
cristye7cc7cf2010-09-21 13:26:47 +00005201 assert(image != (Image *) NULL);
5202 assert(image->signature == MagickSignature);
5203 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005204 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005205 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005206 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00005207 return(SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5208 exception));
cristy3ed852e2009-09-05 21:47:34 +00005209}
5210
5211/*
5212%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5213% %
5214% %
5215% %
5216% S y n c A u t h e n t i c P i x e l s %
5217% %
5218% %
5219% %
5220%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5221%
5222% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5223% The method returns MagickTrue if the pixel region is flushed, otherwise
5224% MagickFalse.
5225%
5226% The format of the SyncAuthenticPixels() method is:
5227%
5228% MagickBooleanType SyncAuthenticPixels(Image *image,
5229% ExceptionInfo *exception)
5230%
5231% A description of each parameter follows:
5232%
5233% o image: the image.
5234%
5235% o exception: return any errors or warnings in this structure.
5236%
5237*/
5238MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5239 ExceptionInfo *exception)
5240{
5241 CacheInfo
5242 *cache_info;
5243
cristy2036f5c2010-09-19 21:18:17 +00005244 const int
5245 id = GetOpenMPThreadId();
5246
cristy3ed852e2009-09-05 21:47:34 +00005247 assert(image != (Image *) NULL);
5248 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005249 assert(image->cache != (Cache) NULL);
5250 cache_info=(CacheInfo *) image->cache;
5251 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005252 if (cache_info->methods.sync_authentic_pixels_handler !=
5253 (SyncAuthenticPixelsHandler) NULL)
5254 return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
cristy2036f5c2010-09-19 21:18:17 +00005255 assert(id < (int) cache_info->number_threads);
5256 return(SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5257 exception));
cristy3ed852e2009-09-05 21:47:34 +00005258}
5259
5260/*
5261%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5262% %
5263% %
5264% %
5265+ W r i t e P i x e l C a c h e I n d e x e s %
5266% %
5267% %
5268% %
5269%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5270%
5271% WritePixelCacheIndexes() writes the colormap indexes to the specified
5272% region of the pixel cache.
5273%
5274% The format of the WritePixelCacheIndexes() method is:
5275%
5276% MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5277% NexusInfo *nexus_info,ExceptionInfo *exception)
5278%
5279% A description of each parameter follows:
5280%
5281% o cache_info: the pixel cache.
5282%
5283% o nexus_info: the cache nexus to write the colormap indexes.
5284%
5285% o exception: return any errors or warnings in this structure.
5286%
5287*/
5288static MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5289 NexusInfo *nexus_info,ExceptionInfo *exception)
5290{
5291 MagickOffsetType
5292 count,
5293 offset;
5294
5295 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005296 extent,
5297 length;
cristy3ed852e2009-09-05 21:47:34 +00005298
5299 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005300 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005301
cristybb503372010-05-27 20:51:26 +00005302 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005303 y;
5304
cristybb503372010-05-27 20:51:26 +00005305 size_t
cristy3ed852e2009-09-05 21:47:34 +00005306 rows;
5307
cristy3ed852e2009-09-05 21:47:34 +00005308 if (cache_info->active_index_channel == MagickFalse)
5309 return(MagickFalse);
5310 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5311 return(MagickTrue);
5312 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5313 nexus_info->region.x;
5314 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
5315 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005316 extent=(MagickSizeType) length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005317 p=nexus_info->indexes;
5318 switch (cache_info->type)
5319 {
5320 case MemoryCache:
5321 case MapCache:
5322 {
5323 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005324 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005325
5326 /*
5327 Write indexes to memory.
5328 */
cristydd341db2010-03-04 19:06:38 +00005329 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005330 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005331 {
cristy48078b12010-09-23 17:11:01 +00005332 length=extent;
cristydd341db2010-03-04 19:06:38 +00005333 rows=1UL;
5334 }
cristy3ed852e2009-09-05 21:47:34 +00005335 q=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00005336 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005337 {
cristy8f036fe2010-09-18 02:02:00 +00005338 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00005339 p+=nexus_info->region.width;
5340 q+=cache_info->columns;
5341 }
5342 break;
5343 }
5344 case DiskCache:
5345 {
5346 /*
5347 Write indexes to disk.
5348 */
5349 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5350 {
5351 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5352 cache_info->cache_filename);
5353 return(MagickFalse);
5354 }
cristydd341db2010-03-04 19:06:38 +00005355 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005356 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005357 {
cristy48078b12010-09-23 17:11:01 +00005358 length=extent;
cristydd341db2010-03-04 19:06:38 +00005359 rows=1UL;
5360 }
cristy48078b12010-09-23 17:11:01 +00005361 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005362 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005363 {
cristy48078b12010-09-23 17:11:01 +00005364 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5365 sizeof(PixelPacket)+offset*sizeof(*p),length,(const unsigned char *)
5366 p);
cristy3ed852e2009-09-05 21:47:34 +00005367 if ((MagickSizeType) count < length)
5368 break;
5369 p+=nexus_info->region.width;
5370 offset+=cache_info->columns;
5371 }
cristybb503372010-05-27 20:51:26 +00005372 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005373 {
5374 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5375 cache_info->cache_filename);
5376 return(MagickFalse);
5377 }
5378 break;
5379 }
5380 default:
5381 break;
5382 }
5383 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005384 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005385 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005386 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005387 nexus_info->region.width,(double) nexus_info->region.height,(double)
5388 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005389 return(MagickTrue);
5390}
5391
5392/*
5393%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5394% %
5395% %
5396% %
5397+ W r i t e C a c h e P i x e l s %
5398% %
5399% %
5400% %
5401%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5402%
5403% WritePixelCachePixels() writes image pixels to the specified region of the
5404% pixel cache.
5405%
5406% The format of the WritePixelCachePixels() method is:
5407%
5408% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5409% NexusInfo *nexus_info,ExceptionInfo *exception)
5410%
5411% A description of each parameter follows:
5412%
5413% o cache_info: the pixel cache.
5414%
5415% o nexus_info: the cache nexus to write the pixels.
5416%
5417% o exception: return any errors or warnings in this structure.
5418%
5419*/
5420static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5421 NexusInfo *nexus_info,ExceptionInfo *exception)
5422{
5423 MagickOffsetType
5424 count,
5425 offset;
5426
5427 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005428 extent,
5429 length;
cristy3ed852e2009-09-05 21:47:34 +00005430
cristy3ed852e2009-09-05 21:47:34 +00005431 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005432 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005433
cristybb503372010-05-27 20:51:26 +00005434 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005435 y;
5436
cristybb503372010-05-27 20:51:26 +00005437 size_t
cristy3ed852e2009-09-05 21:47:34 +00005438 rows;
5439
cristy3ed852e2009-09-05 21:47:34 +00005440 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5441 return(MagickTrue);
5442 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5443 nexus_info->region.x;
5444 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
5445 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005446 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005447 p=nexus_info->pixels;
5448 switch (cache_info->type)
5449 {
5450 case MemoryCache:
5451 case MapCache:
5452 {
5453 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005454 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005455
5456 /*
5457 Write pixels to memory.
5458 */
cristydd341db2010-03-04 19:06:38 +00005459 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005460 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005461 {
cristy48078b12010-09-23 17:11:01 +00005462 length=extent;
cristydd341db2010-03-04 19:06:38 +00005463 rows=1UL;
5464 }
cristy3ed852e2009-09-05 21:47:34 +00005465 q=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00005466 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005467 {
cristy8f036fe2010-09-18 02:02:00 +00005468 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00005469 p+=nexus_info->region.width;
5470 q+=cache_info->columns;
5471 }
5472 break;
5473 }
5474 case DiskCache:
5475 {
5476 /*
5477 Write pixels to disk.
5478 */
5479 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5480 {
5481 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5482 cache_info->cache_filename);
5483 return(MagickFalse);
5484 }
cristydd341db2010-03-04 19:06:38 +00005485 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005486 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005487 {
cristy48078b12010-09-23 17:11:01 +00005488 length=extent;
cristydd341db2010-03-04 19:06:38 +00005489 rows=1UL;
5490 }
cristybb503372010-05-27 20:51:26 +00005491 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005492 {
5493 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5494 sizeof(*p),length,(const unsigned char *) p);
5495 if ((MagickSizeType) count < length)
5496 break;
5497 p+=nexus_info->region.width;
5498 offset+=cache_info->columns;
5499 }
cristybb503372010-05-27 20:51:26 +00005500 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005501 {
5502 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5503 cache_info->cache_filename);
5504 return(MagickFalse);
5505 }
5506 break;
5507 }
5508 default:
5509 break;
5510 }
5511 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005512 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005513 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005514 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005515 nexus_info->region.width,(double) nexus_info->region.height,(double)
5516 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005517 return(MagickTrue);
5518}