blob: cabba26e47b4fd08f8b17304c9432947ff4e0a49 [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,
cristy94fc8fa2011-02-19 15:27:47 +0000708 (MagickSizeType) SSIZE_MAX),(off_t) (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,
cristy94fc8fa2011-02-19 15:27:47 +0000752 (MagickSizeType) SSIZE_MAX),(off_t) (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);
cristy654fdaf2011-02-24 15:24:33 +00002758 assert(length != (MagickSizeType *) NULL);
2759 assert(exception != (ExceptionInfo *) NULL);
2760 assert(exception->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00002761 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002762 assert(cache_info->signature == MagickSignature);
2763 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002764 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002765 return((void *) NULL);
2766 *length=cache_info->length;
2767 return((void *) cache_info->pixels);
2768}
2769
2770/*
2771%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2772% %
2773% %
2774% %
cristyb32b90a2009-09-07 21:45:48 +00002775+ G e t P i x e l C a c h e S t o r a g e C l a s s %
cristy3ed852e2009-09-05 21:47:34 +00002776% %
2777% %
2778% %
2779%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2780%
2781% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2782%
2783% The format of the GetPixelCacheStorageClass() method is:
2784%
2785% ClassType GetPixelCacheStorageClass(Cache cache)
2786%
2787% A description of each parameter follows:
2788%
2789% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2790%
2791% o cache: the pixel cache.
2792%
2793*/
2794MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
2795{
2796 CacheInfo
2797 *cache_info;
2798
2799 assert(cache != (Cache) NULL);
2800 cache_info=(CacheInfo *) cache;
2801 assert(cache_info->signature == MagickSignature);
2802 if (cache_info->debug != MagickFalse)
2803 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2804 cache_info->filename);
2805 return(cache_info->storage_class);
2806}
2807
2808/*
2809%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2810% %
2811% %
2812% %
cristyb32b90a2009-09-07 21:45:48 +00002813+ G e t P i x e l C a c h e T i l e S i z e %
2814% %
2815% %
2816% %
2817%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2818%
2819% GetPixelCacheTileSize() returns the pixel cache tile size.
2820%
2821% The format of the GetPixelCacheTileSize() method is:
2822%
cristybb503372010-05-27 20:51:26 +00002823% void GetPixelCacheTileSize(const Image *image,size_t *width,
2824% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002825%
2826% A description of each parameter follows:
2827%
2828% o image: the image.
2829%
2830% o width: the optimize cache tile width in pixels.
2831%
2832% o height: the optimize cache tile height in pixels.
2833%
2834*/
cristybb503372010-05-27 20:51:26 +00002835MagickExport void GetPixelCacheTileSize(const Image *image,size_t *width,
2836 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002837{
cristyb32b90a2009-09-07 21:45:48 +00002838 assert(image != (Image *) NULL);
2839 assert(image->signature == MagickSignature);
2840 if (image->debug != MagickFalse)
2841 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristyb32b90a2009-09-07 21:45:48 +00002842 *width=2048UL/sizeof(PixelPacket);
2843 if (GetPixelCacheType(image) == DiskCache)
cristydaa97692009-09-13 02:10:35 +00002844 *width=8192UL/sizeof(PixelPacket);
cristyb32b90a2009-09-07 21:45:48 +00002845 *height=(*width);
2846}
2847
2848/*
2849%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2850% %
2851% %
2852% %
2853+ G e t P i x e l C a c h e T y p e %
2854% %
2855% %
2856% %
2857%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2858%
2859% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2860%
2861% The format of the GetPixelCacheType() method is:
2862%
2863% CacheType GetPixelCacheType(const Image *image)
2864%
2865% A description of each parameter follows:
2866%
2867% o image: the image.
2868%
2869*/
2870MagickExport CacheType GetPixelCacheType(const Image *image)
2871{
2872 CacheInfo
2873 *cache_info;
2874
2875 assert(image != (Image *) NULL);
2876 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002877 assert(image->cache != (Cache) NULL);
2878 cache_info=(CacheInfo *) image->cache;
2879 assert(cache_info->signature == MagickSignature);
2880 return(cache_info->type);
2881}
2882
2883/*
2884%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2885% %
2886% %
2887% %
cristy3ed852e2009-09-05 21:47:34 +00002888+ G e t P i x e l C a c h e V i r t u a l M e t h o d %
2889% %
2890% %
2891% %
2892%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2893%
2894% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2895% pixel cache. A virtual pixel is any pixel access that is outside the
2896% boundaries of the image cache.
2897%
2898% The format of the GetPixelCacheVirtualMethod() method is:
2899%
2900% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2901%
2902% A description of each parameter follows:
2903%
2904% o image: the image.
2905%
2906*/
2907MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2908{
2909 CacheInfo
2910 *cache_info;
2911
2912 assert(image != (Image *) NULL);
2913 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002914 assert(image->cache != (Cache) NULL);
2915 cache_info=(CacheInfo *) image->cache;
2916 assert(cache_info->signature == MagickSignature);
2917 return(cache_info->virtual_pixel_method);
2918}
2919
2920/*
2921%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2922% %
2923% %
2924% %
2925+ G e t V i r t u a l I n d e x e s F r o m C a c h e %
2926% %
2927% %
2928% %
2929%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2930%
2931% GetVirtualIndexesFromCache() returns the indexes associated with the last
2932% call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2933%
2934% The format of the GetVirtualIndexesFromCache() method is:
2935%
2936% IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2937%
2938% A description of each parameter follows:
2939%
2940% o image: the image.
2941%
2942*/
2943static const IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2944{
2945 CacheInfo
2946 *cache_info;
2947
cristy5c9e6f22010-09-17 17:31:01 +00002948 const int
2949 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002950
cristye7cc7cf2010-09-21 13:26:47 +00002951 assert(image != (const Image *) NULL);
2952 assert(image->signature == MagickSignature);
2953 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002954 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002955 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002956 assert(id < (int) cache_info->number_threads);
cristye7cc7cf2010-09-21 13:26:47 +00002957 return(GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00002958}
2959
2960/*
2961%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2962% %
2963% %
2964% %
2965+ G e t V i r t u a l I n d e x e s F r o m N e x u s %
2966% %
2967% %
2968% %
2969%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2970%
2971% GetVirtualIndexesFromNexus() returns the indexes associated with the
2972% specified cache nexus.
2973%
2974% The format of the GetVirtualIndexesFromNexus() method is:
2975%
2976% const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2977% NexusInfo *nexus_info)
2978%
2979% A description of each parameter follows:
2980%
2981% o cache: the pixel cache.
2982%
2983% o nexus_info: the cache nexus to return the colormap indexes.
2984%
2985*/
2986MagickExport const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2987 NexusInfo *nexus_info)
2988{
2989 CacheInfo
2990 *cache_info;
2991
cristye7cc7cf2010-09-21 13:26:47 +00002992 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002993 cache_info=(CacheInfo *) cache;
2994 assert(cache_info->signature == MagickSignature);
2995 if (cache_info->storage_class == UndefinedClass)
2996 return((IndexPacket *) NULL);
2997 return(nexus_info->indexes);
2998}
2999
3000/*
3001%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3002% %
3003% %
3004% %
3005% G e t V i r t u a l I n d e x Q u e u e %
3006% %
3007% %
3008% %
3009%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3010%
3011% GetVirtualIndexQueue() returns the virtual black channel or the
3012% colormap indexes associated with the last call to QueueAuthenticPixels() or
3013% GetVirtualPixels(). NULL is returned if the black channel or colormap
3014% indexes are not available.
3015%
3016% The format of the GetVirtualIndexQueue() method is:
3017%
3018% const IndexPacket *GetVirtualIndexQueue(const Image *image)
3019%
3020% A description of each parameter follows:
3021%
3022% o image: the image.
3023%
3024*/
3025MagickExport const IndexPacket *GetVirtualIndexQueue(const Image *image)
3026{
3027 CacheInfo
3028 *cache_info;
3029
cristy2036f5c2010-09-19 21:18:17 +00003030 const int
3031 id = GetOpenMPThreadId();
3032
cristy3ed852e2009-09-05 21:47:34 +00003033 assert(image != (const Image *) NULL);
3034 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003035 assert(image->cache != (Cache) NULL);
3036 cache_info=(CacheInfo *) image->cache;
3037 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003038 if (cache_info->methods.get_virtual_indexes_from_handler !=
3039 (GetVirtualIndexesFromHandler) NULL)
3040 return(cache_info->methods.get_virtual_indexes_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003041 assert(id < (int) cache_info->number_threads);
3042 return(GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003043}
3044
3045/*
3046%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3047% %
3048% %
3049% %
3050+ G e t V i r t u a l P i x e l s F r o m N e x u s %
3051% %
3052% %
3053% %
3054%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3055%
3056% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3057% pixel cache as defined by the geometry parameters. A pointer to the pixels
3058% is returned if the pixels are transferred, otherwise a NULL is returned.
3059%
3060% The format of the GetVirtualPixelsFromNexus() method is:
3061%
3062% PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003063% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00003064% const size_t columns,const size_t rows,NexusInfo *nexus_info,
3065% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003066%
3067% A description of each parameter follows:
3068%
3069% o image: the image.
3070%
3071% o virtual_pixel_method: the virtual pixel method.
3072%
3073% o x,y,columns,rows: These values define the perimeter of a region of
3074% pixels.
3075%
3076% o nexus_info: the cache nexus to acquire.
3077%
3078% o exception: return any errors or warnings in this structure.
3079%
3080*/
3081
cristybb503372010-05-27 20:51:26 +00003082static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003083 DitherMatrix[64] =
3084 {
3085 0, 48, 12, 60, 3, 51, 15, 63,
3086 32, 16, 44, 28, 35, 19, 47, 31,
3087 8, 56, 4, 52, 11, 59, 7, 55,
3088 40, 24, 36, 20, 43, 27, 39, 23,
3089 2, 50, 14, 62, 1, 49, 13, 61,
3090 34, 18, 46, 30, 33, 17, 45, 29,
3091 10, 58, 6, 54, 9, 57, 5, 53,
3092 42, 26, 38, 22, 41, 25, 37, 21
3093 };
3094
cristybb503372010-05-27 20:51:26 +00003095static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003096{
cristybb503372010-05-27 20:51:26 +00003097 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003098 index;
3099
3100 index=x+DitherMatrix[x & 0x07]-32L;
3101 if (index < 0L)
3102 return(0L);
cristybb503372010-05-27 20:51:26 +00003103 if (index >= (ssize_t) columns)
3104 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00003105 return(index);
3106}
3107
cristybb503372010-05-27 20:51:26 +00003108static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003109{
cristybb503372010-05-27 20:51:26 +00003110 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003111 index;
3112
3113 index=y+DitherMatrix[y & 0x07]-32L;
3114 if (index < 0L)
3115 return(0L);
cristybb503372010-05-27 20:51:26 +00003116 if (index >= (ssize_t) rows)
3117 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00003118 return(index);
3119}
3120
cristybb503372010-05-27 20:51:26 +00003121static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003122{
3123 if (x < 0L)
3124 return(0L);
cristybb503372010-05-27 20:51:26 +00003125 if (x >= (ssize_t) columns)
3126 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003127 return(x);
3128}
3129
cristybb503372010-05-27 20:51:26 +00003130static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003131{
3132 if (y < 0L)
3133 return(0L);
cristybb503372010-05-27 20:51:26 +00003134 if (y >= (ssize_t) rows)
3135 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003136 return(y);
3137}
3138
cristybb503372010-05-27 20:51:26 +00003139static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003140{
cristybb503372010-05-27 20:51:26 +00003141 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003142}
3143
cristybb503372010-05-27 20:51:26 +00003144static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003145{
cristybb503372010-05-27 20:51:26 +00003146 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003147}
3148
3149/*
3150 VirtualPixelModulo() computes the remainder of dividing offset by extent. It
3151 returns not only the quotient (tile the offset falls in) but also the positive
3152 remainer within that tile such that 0 <= remainder < extent. This method is
3153 essentially a ldiv() using a floored modulo division rather than the normal
3154 default truncated modulo division.
3155*/
cristybb503372010-05-27 20:51:26 +00003156static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3157 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003158{
3159 MagickModulo
3160 modulo;
3161
cristybb503372010-05-27 20:51:26 +00003162 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003163 if (offset < 0L)
3164 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003165 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003166 return(modulo);
3167}
3168
3169MagickExport const PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003170 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3171 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003172 ExceptionInfo *exception)
3173{
3174 CacheInfo
3175 *cache_info;
3176
cristyc3ec0d42010-04-07 01:18:08 +00003177 IndexPacket
3178 virtual_index;
3179
cristy3ed852e2009-09-05 21:47:34 +00003180 MagickOffsetType
3181 offset;
3182
3183 MagickSizeType
3184 length,
3185 number_pixels;
3186
3187 NexusInfo
3188 **virtual_nexus;
3189
3190 PixelPacket
3191 *pixels,
3192 virtual_pixel;
3193
3194 RectangleInfo
3195 region;
3196
3197 register const IndexPacket
cristyc3ec0d42010-04-07 01:18:08 +00003198 *restrict virtual_indexes;
cristy3ed852e2009-09-05 21:47:34 +00003199
3200 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003201 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003202
3203 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003204 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003205
cristye076a6e2010-08-15 19:59:43 +00003206 register PixelPacket
3207 *restrict q;
3208
cristybb503372010-05-27 20:51:26 +00003209 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003210 u,
3211 v;
3212
cristy3ed852e2009-09-05 21:47:34 +00003213 /*
3214 Acquire pixels.
3215 */
cristye7cc7cf2010-09-21 13:26:47 +00003216 assert(image != (const Image *) NULL);
3217 assert(image->signature == MagickSignature);
3218 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003219 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003220 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003221 if (cache_info->type == UndefinedCache)
cristy3ed852e2009-09-05 21:47:34 +00003222 return((const PixelPacket *) NULL);
3223 region.x=x;
3224 region.y=y;
3225 region.width=columns;
3226 region.height=rows;
3227 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
3228 if (pixels == (PixelPacket *) NULL)
3229 return((const PixelPacket *) NULL);
cristydf415c82010-03-11 16:47:50 +00003230 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3231 nexus_info->region.x;
3232 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3233 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003234 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3235 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003236 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3237 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003238 {
3239 MagickBooleanType
3240 status;
3241
3242 /*
3243 Pixel request is inside cache extents.
3244 */
3245 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
3246 return(pixels);
3247 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3248 if (status == MagickFalse)
3249 return((const PixelPacket *) NULL);
3250 if ((cache_info->storage_class == PseudoClass) ||
3251 (cache_info->colorspace == CMYKColorspace))
3252 {
3253 status=ReadPixelCacheIndexes(cache_info,nexus_info,exception);
3254 if (status == MagickFalse)
3255 return((const PixelPacket *) NULL);
3256 }
3257 return(pixels);
3258 }
3259 /*
3260 Pixel request is outside cache extents.
3261 */
3262 q=pixels;
3263 indexes=GetPixelCacheNexusIndexes(cache_info,nexus_info);
3264 virtual_nexus=AcquirePixelCacheNexus(1);
3265 if (virtual_nexus == (NexusInfo **) NULL)
3266 {
3267 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3268 "UnableToGetCacheNexus","`%s'",image->filename);
3269 return((const PixelPacket *) NULL);
3270 }
3271 switch (virtual_pixel_method)
3272 {
3273 case BlackVirtualPixelMethod:
3274 {
cristy4789f0d2010-01-10 00:01:06 +00003275 SetRedPixelComponent(&virtual_pixel,0);
3276 SetGreenPixelComponent(&virtual_pixel,0);
3277 SetBluePixelComponent(&virtual_pixel,0);
3278 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003279 break;
3280 }
3281 case GrayVirtualPixelMethod:
3282 {
cristy4789f0d2010-01-10 00:01:06 +00003283 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3284 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3285 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3286 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003287 break;
3288 }
3289 case TransparentVirtualPixelMethod:
3290 {
cristy4789f0d2010-01-10 00:01:06 +00003291 SetRedPixelComponent(&virtual_pixel,0);
3292 SetGreenPixelComponent(&virtual_pixel,0);
3293 SetBluePixelComponent(&virtual_pixel,0);
3294 SetOpacityPixelComponent(&virtual_pixel,TransparentOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003295 break;
3296 }
3297 case MaskVirtualPixelMethod:
3298 case WhiteVirtualPixelMethod:
3299 {
cristy4789f0d2010-01-10 00:01:06 +00003300 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3301 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3302 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3303 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003304 break;
3305 }
3306 default:
3307 {
3308 virtual_pixel=image->background_color;
3309 break;
3310 }
3311 }
cristyc3ec0d42010-04-07 01:18:08 +00003312 virtual_index=0;
cristybb503372010-05-27 20:51:26 +00003313 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003314 {
cristybb503372010-05-27 20:51:26 +00003315 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003316 {
3317 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003318 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003319 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3320 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003321 {
3322 MagickModulo
3323 x_modulo,
3324 y_modulo;
3325
3326 /*
3327 Transfer a single pixel.
3328 */
3329 length=(MagickSizeType) 1;
3330 switch (virtual_pixel_method)
3331 {
3332 case BackgroundVirtualPixelMethod:
3333 case ConstantVirtualPixelMethod:
3334 case BlackVirtualPixelMethod:
3335 case GrayVirtualPixelMethod:
3336 case TransparentVirtualPixelMethod:
3337 case MaskVirtualPixelMethod:
3338 case WhiteVirtualPixelMethod:
3339 {
3340 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003341 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003342 break;
3343 }
3344 case EdgeVirtualPixelMethod:
3345 default:
3346 {
3347 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003348 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003349 1UL,1UL,*virtual_nexus,exception);
cristyc3ec0d42010-04-07 01:18:08 +00003350 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003351 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003352 break;
3353 }
3354 case RandomVirtualPixelMethod:
3355 {
3356 if (cache_info->random_info == (RandomInfo *) NULL)
3357 cache_info->random_info=AcquireRandomInfo();
3358 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003359 RandomX(cache_info->random_info,cache_info->columns),
3360 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003361 *virtual_nexus,exception);
cristyc3ec0d42010-04-07 01:18:08 +00003362 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003363 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003364 break;
3365 }
3366 case DitherVirtualPixelMethod:
3367 {
3368 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003369 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003370 1UL,1UL,*virtual_nexus,exception);
cristyc3ec0d42010-04-07 01:18:08 +00003371 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003372 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003373 break;
3374 }
3375 case TileVirtualPixelMethod:
3376 {
3377 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3378 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3379 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003380 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003381 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003382 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003383 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003384 break;
3385 }
3386 case MirrorVirtualPixelMethod:
3387 {
3388 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3389 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003390 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003391 x_modulo.remainder-1L;
3392 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3393 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003394 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003395 y_modulo.remainder-1L;
3396 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003397 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003398 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003399 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003400 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003401 break;
3402 }
3403 case CheckerTileVirtualPixelMethod:
3404 {
3405 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3406 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3407 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3408 {
3409 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003410 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003411 break;
3412 }
3413 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003414 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003415 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003416 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003417 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003418 break;
3419 }
3420 case HorizontalTileVirtualPixelMethod:
3421 {
cristybb503372010-05-27 20:51:26 +00003422 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003423 {
3424 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003425 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003426 break;
3427 }
3428 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3429 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3430 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003431 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003432 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003433 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003434 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003435 break;
3436 }
3437 case VerticalTileVirtualPixelMethod:
3438 {
cristybb503372010-05-27 20:51:26 +00003439 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
cristy3ed852e2009-09-05 21:47:34 +00003440 {
3441 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003442 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003443 break;
3444 }
3445 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3446 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3447 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003448 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003449 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003450 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003451 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003452 break;
3453 }
3454 case HorizontalTileEdgeVirtualPixelMethod:
3455 {
3456 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3457 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003458 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003459 *virtual_nexus,exception);
cristyc3ec0d42010-04-07 01:18:08 +00003460 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003461 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003462 break;
3463 }
3464 case VerticalTileEdgeVirtualPixelMethod:
3465 {
3466 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3467 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003468 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003469 *virtual_nexus,exception);
cristyc3ec0d42010-04-07 01:18:08 +00003470 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003471 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003472 break;
3473 }
3474 }
3475 if (p == (const PixelPacket *) NULL)
3476 break;
3477 *q++=(*p);
cristyc3ec0d42010-04-07 01:18:08 +00003478 if ((indexes != (IndexPacket *) NULL) &&
3479 (virtual_indexes != (const IndexPacket *) NULL))
3480 *indexes++=(*virtual_indexes);
cristy3ed852e2009-09-05 21:47:34 +00003481 continue;
3482 }
3483 /*
3484 Transfer a run of pixels.
3485 */
3486 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,
cristy0a36c742010-10-03 02:10:53 +00003487 (size_t) length,1UL,*virtual_nexus,exception);
cristy3ed852e2009-09-05 21:47:34 +00003488 if (p == (const PixelPacket *) NULL)
3489 break;
cristy0a36c742010-10-03 02:10:53 +00003490 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,*virtual_nexus);
cristy8f036fe2010-09-18 02:02:00 +00003491 (void) memcpy(q,p,(size_t) length*sizeof(*p));
cristy3ed852e2009-09-05 21:47:34 +00003492 q+=length;
cristyc3ec0d42010-04-07 01:18:08 +00003493 if ((indexes != (IndexPacket *) NULL) &&
3494 (virtual_indexes != (const IndexPacket *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003495 {
cristy8f036fe2010-09-18 02:02:00 +00003496 (void) memcpy(indexes,virtual_indexes,(size_t) length*
cristyc3ec0d42010-04-07 01:18:08 +00003497 sizeof(*virtual_indexes));
3498 indexes+=length;
cristy3ed852e2009-09-05 21:47:34 +00003499 }
3500 }
3501 }
3502 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3503 return(pixels);
3504}
3505
3506/*
3507%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3508% %
3509% %
3510% %
3511+ G e t V i r t u a l P i x e l C a c h e %
3512% %
3513% %
3514% %
3515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3516%
3517% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3518% cache as defined by the geometry parameters. A pointer to the pixels
3519% is returned if the pixels are transferred, otherwise a NULL is returned.
3520%
3521% The format of the GetVirtualPixelCache() method is:
3522%
3523% const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003524% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3525% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003526% ExceptionInfo *exception)
3527%
3528% A description of each parameter follows:
3529%
3530% o image: the image.
3531%
3532% o virtual_pixel_method: the virtual pixel method.
3533%
3534% o x,y,columns,rows: These values define the perimeter of a region of
3535% pixels.
3536%
3537% o exception: return any errors or warnings in this structure.
3538%
3539*/
3540static const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003541 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3542 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003543{
3544 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003545 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003546
cristy5c9e6f22010-09-17 17:31:01 +00003547 const int
3548 id = GetOpenMPThreadId();
3549
cristye7cc7cf2010-09-21 13:26:47 +00003550 assert(image != (const Image *) NULL);
3551 assert(image->signature == MagickSignature);
3552 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003553 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003554 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003555 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003556 return(GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3557 cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00003558}
3559
3560/*
3561%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3562% %
3563% %
3564% %
3565% G e t V i r t u a l P i x e l Q u e u e %
3566% %
3567% %
3568% %
3569%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3570%
3571% GetVirtualPixelQueue() returns the virtual pixels associated with the
3572% last call to QueueAuthenticPixels() or GetVirtualPixels().
3573%
3574% The format of the GetVirtualPixelQueue() method is:
3575%
3576% const PixelPacket *GetVirtualPixelQueue(const Image image)
3577%
3578% A description of each parameter follows:
3579%
3580% o image: the image.
3581%
3582*/
3583MagickExport const PixelPacket *GetVirtualPixelQueue(const Image *image)
3584{
3585 CacheInfo
3586 *cache_info;
3587
cristy2036f5c2010-09-19 21:18:17 +00003588 const int
3589 id = GetOpenMPThreadId();
3590
cristy3ed852e2009-09-05 21:47:34 +00003591 assert(image != (const Image *) NULL);
3592 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003593 assert(image->cache != (Cache) NULL);
3594 cache_info=(CacheInfo *) image->cache;
3595 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003596 if (cache_info->methods.get_virtual_pixels_handler !=
3597 (GetVirtualPixelsHandler) NULL)
3598 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003599 assert(id < (int) cache_info->number_threads);
3600 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003601}
3602
3603/*
3604%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3605% %
3606% %
3607% %
3608% G e t V i r t u a l P i x e l s %
3609% %
3610% %
3611% %
3612%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3613%
3614% GetVirtualPixels() returns an immutable pixel region. If the
3615% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003616% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003617% copy of the pixels or it may point to the original pixels in memory.
3618% Performance is maximized if the selected region is part of one row, or one
3619% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003620% (without a copy) if the image is in memory, or in a memory-mapped file. The
3621% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003622%
3623% Pixels accessed via the returned pointer represent a simple array of type
3624% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
3625% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to access
3626% the black color component or to obtain the colormap indexes (of type
3627% IndexPacket) corresponding to the region.
3628%
3629% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3630%
3631% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3632% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3633% GetCacheViewAuthenticPixels() instead.
3634%
3635% The format of the GetVirtualPixels() method is:
3636%
cristybb503372010-05-27 20:51:26 +00003637% const PixelPacket *GetVirtualPixels(const Image *image,const ssize_t x,
3638% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003639% ExceptionInfo *exception)
3640%
3641% A description of each parameter follows:
3642%
3643% o image: the image.
3644%
3645% o x,y,columns,rows: These values define the perimeter of a region of
3646% pixels.
3647%
3648% o exception: return any errors or warnings in this structure.
3649%
3650*/
3651MagickExport const PixelPacket *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003652 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3653 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003654{
3655 CacheInfo
3656 *cache_info;
3657
cristy2036f5c2010-09-19 21:18:17 +00003658 const int
3659 id = GetOpenMPThreadId();
3660
cristy3ed852e2009-09-05 21:47:34 +00003661 assert(image != (const Image *) NULL);
3662 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003663 assert(image->cache != (Cache) NULL);
3664 cache_info=(CacheInfo *) image->cache;
3665 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003666 if (cache_info->methods.get_virtual_pixel_handler !=
3667 (GetVirtualPixelHandler) NULL)
3668 return(cache_info->methods.get_virtual_pixel_handler(image,
3669 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003670 assert(id < (int) cache_info->number_threads);
3671 return(GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3672 columns,rows,cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00003673}
3674
3675/*
3676%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3677% %
3678% %
3679% %
3680+ G e t V i r t u a l P i x e l s F r o m C a c h e %
3681% %
3682% %
3683% %
3684%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3685%
3686% GetVirtualPixelsCache() returns the pixels associated with the last call
3687% to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3688%
3689% The format of the GetVirtualPixelsCache() method is:
3690%
3691% PixelPacket *GetVirtualPixelsCache(const Image *image)
3692%
3693% A description of each parameter follows:
3694%
3695% o image: the image.
3696%
3697*/
3698static const PixelPacket *GetVirtualPixelsCache(const Image *image)
3699{
3700 CacheInfo
3701 *cache_info;
3702
cristy5c9e6f22010-09-17 17:31:01 +00003703 const int
3704 id = GetOpenMPThreadId();
3705
cristye7cc7cf2010-09-21 13:26:47 +00003706 assert(image != (const Image *) NULL);
3707 assert(image->signature == MagickSignature);
3708 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003709 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003710 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003711 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003712 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003713}
3714
3715/*
3716%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3717% %
3718% %
3719% %
3720+ G e t V i r t u a l P i x e l s N e x u s %
3721% %
3722% %
3723% %
3724%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3725%
3726% GetVirtualPixelsNexus() returns the pixels associated with the specified
3727% cache nexus.
3728%
3729% The format of the GetVirtualPixelsNexus() method is:
3730%
3731% const IndexPacket *GetVirtualPixelsNexus(const Cache cache,
3732% NexusInfo *nexus_info)
3733%
3734% A description of each parameter follows:
3735%
3736% o cache: the pixel cache.
3737%
3738% o nexus_info: the cache nexus to return the colormap pixels.
3739%
3740*/
3741MagickExport const PixelPacket *GetVirtualPixelsNexus(const Cache cache,
3742 NexusInfo *nexus_info)
3743{
3744 CacheInfo
3745 *cache_info;
3746
cristye7cc7cf2010-09-21 13:26:47 +00003747 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003748 cache_info=(CacheInfo *) cache;
3749 assert(cache_info->signature == MagickSignature);
3750 if (cache_info->storage_class == UndefinedClass)
3751 return((PixelPacket *) NULL);
3752 return((const PixelPacket *) nexus_info->pixels);
3753}
3754
3755/*
3756%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3757% %
3758% %
3759% %
3760+ M a s k P i x e l C a c h e N e x u s %
3761% %
3762% %
3763% %
3764%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3765%
3766% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3767% The method returns MagickTrue if the pixel region is masked, otherwise
3768% MagickFalse.
3769%
3770% The format of the MaskPixelCacheNexus() method is:
3771%
3772% MagickBooleanType MaskPixelCacheNexus(Image *image,
3773% NexusInfo *nexus_info,ExceptionInfo *exception)
3774%
3775% A description of each parameter follows:
3776%
3777% o image: the image.
3778%
3779% o nexus_info: the cache nexus to clip.
3780%
3781% o exception: return any errors or warnings in this structure.
3782%
3783*/
3784
3785static inline void MagickPixelCompositeMask(const MagickPixelPacket *p,
3786 const MagickRealType alpha,const MagickPixelPacket *q,
3787 const MagickRealType beta,MagickPixelPacket *composite)
3788{
3789 MagickRealType
3790 gamma;
3791
3792 if (alpha == TransparentOpacity)
3793 {
3794 *composite=(*q);
3795 return;
3796 }
3797 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3798 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
cristyb40bd892011-04-23 00:52:38 +00003799 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3800 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3801 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
cristy3ed852e2009-09-05 21:47:34 +00003802 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3803 composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
3804}
3805
3806static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3807 ExceptionInfo *exception)
3808{
3809 CacheInfo
3810 *cache_info;
3811
3812 MagickPixelPacket
3813 alpha,
3814 beta;
3815
3816 MagickSizeType
3817 number_pixels;
3818
3819 NexusInfo
3820 **clip_nexus,
3821 **image_nexus;
3822
3823 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003824 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003825
3826 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003827 *restrict nexus_indexes,
3828 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003829
cristy3ed852e2009-09-05 21:47:34 +00003830 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003831 *restrict p,
3832 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003833
cristye076a6e2010-08-15 19:59:43 +00003834 register ssize_t
3835 i;
3836
cristy3ed852e2009-09-05 21:47:34 +00003837 /*
3838 Apply clip mask.
3839 */
3840 if (image->debug != MagickFalse)
3841 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3842 if (image->mask == (Image *) NULL)
3843 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +00003844 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00003845 if (cache_info == (Cache) NULL)
3846 return(MagickFalse);
3847 image_nexus=AcquirePixelCacheNexus(1);
3848 clip_nexus=AcquirePixelCacheNexus(1);
3849 if ((image_nexus == (NexusInfo **) NULL) ||
3850 (clip_nexus == (NexusInfo **) NULL))
3851 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy09449f72010-01-23 03:08:36 +00003852 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,
3853 nexus_info->region.y,nexus_info->region.width,nexus_info->region.height,
3854 image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003855 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
3856 q=nexus_info->pixels;
3857 nexus_indexes=nexus_info->indexes;
3858 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3859 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3860 nexus_info->region.height,clip_nexus[0],&image->exception);
3861 GetMagickPixelPacket(image,&alpha);
3862 GetMagickPixelPacket(image,&beta);
3863 number_pixels=(MagickSizeType) nexus_info->region.width*
3864 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +00003865 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +00003866 {
3867 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
3868 break;
3869 SetMagickPixelPacket(image,p,indexes+i,&alpha);
3870 SetMagickPixelPacket(image,q,nexus_indexes+i,&beta);
3871 MagickPixelCompositeMask(&beta,(MagickRealType) PixelIntensityToQuantum(r),
3872 &alpha,alpha.opacity,&beta);
cristyb40bd892011-04-23 00:52:38 +00003873 SetRedPixelComponent(q,ClampToQuantum(beta.red));
3874 SetGreenPixelComponent(q,ClampToQuantum(beta.green));
3875 SetBluePixelComponent(q,ClampToQuantum(beta.blue));
3876 SetOpacityPixelComponent(q,ClampToQuantum(beta.opacity));
cristy3ed852e2009-09-05 21:47:34 +00003877 if (cache_info->active_index_channel != MagickFalse)
cristyb40bd892011-04-23 00:52:38 +00003878 SetIndexPixelComponent(nexus_indexes+i,indexes[i]);
cristy3ed852e2009-09-05 21:47:34 +00003879 p++;
3880 q++;
3881 r++;
3882 }
3883 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3884 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +00003885 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003886 return(MagickFalse);
3887 return(MagickTrue);
3888}
3889
3890/*
3891%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3892% %
3893% %
3894% %
3895+ O p e n P i x e l C a c h e %
3896% %
3897% %
3898% %
3899%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3900%
3901% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3902% dimensions, allocating space for the image pixels and optionally the
3903% colormap indexes, and memory mapping the cache if it is disk based. The
3904% cache nexus array is initialized as well.
3905%
3906% The format of the OpenPixelCache() method is:
3907%
3908% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3909% ExceptionInfo *exception)
3910%
3911% A description of each parameter follows:
3912%
3913% o image: the image.
3914%
3915% o mode: ReadMode, WriteMode, or IOMode.
3916%
3917% o exception: return any errors or warnings in this structure.
3918%
3919*/
3920
cristyd43a46b2010-01-21 02:13:41 +00003921static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003922{
3923 cache_info->mapped=MagickFalse;
3924 cache_info->pixels=(PixelPacket *) AcquireMagickMemory((size_t)
3925 cache_info->length);
3926 if (cache_info->pixels == (PixelPacket *) NULL)
3927 {
3928 cache_info->mapped=MagickTrue;
3929 cache_info->pixels=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
3930 cache_info->length);
3931 }
3932}
3933
3934static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3935{
3936 CacheInfo
3937 *cache_info;
3938
3939 MagickOffsetType
3940 count,
3941 extent,
3942 offset;
3943
3944 cache_info=(CacheInfo *) image->cache;
3945 if (image->debug != MagickFalse)
3946 {
3947 char
3948 format[MaxTextExtent],
3949 message[MaxTextExtent];
3950
cristyb9080c92009-12-01 20:13:26 +00003951 (void) FormatMagickSize(length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00003952 (void) FormatMagickString(message,MaxTextExtent,
cristy2ce15c92010-03-12 14:03:41 +00003953 "extend %s (%s[%d], disk, %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003954 cache_info->cache_filename,cache_info->file,format);
3955 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3956 }
3957 if (length != (MagickSizeType) ((MagickOffsetType) length))
3958 return(MagickFalse);
cristy7f317702011-02-18 20:40:28 +00003959 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
cristy3ed852e2009-09-05 21:47:34 +00003960 if (extent < 0)
3961 return(MagickFalse);
3962 if ((MagickSizeType) extent >= length)
3963 return(MagickTrue);
3964 offset=(MagickOffsetType) length-1;
3965 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3966 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3967}
3968
3969static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3970 ExceptionInfo *exception)
3971{
cristy3ed852e2009-09-05 21:47:34 +00003972 CacheInfo
3973 *cache_info,
3974 source_info;
3975
cristyf3a6a9d2010-11-07 21:02:56 +00003976 char
3977 format[MaxTextExtent],
3978 message[MaxTextExtent];
3979
cristy3ed852e2009-09-05 21:47:34 +00003980 MagickSizeType
3981 length,
3982 number_pixels;
3983
3984 MagickStatusType
3985 status;
3986
3987 size_t
cristye076a6e2010-08-15 19:59:43 +00003988 columns,
cristy3ed852e2009-09-05 21:47:34 +00003989 packet_size;
3990
cristye7cc7cf2010-09-21 13:26:47 +00003991 assert(image != (const Image *) NULL);
3992 assert(image->signature == MagickSignature);
3993 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003994 if (image->debug != MagickFalse)
3995 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3996 if ((image->columns == 0) || (image->rows == 0))
3997 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3998 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003999 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004000 source_info=(*cache_info);
4001 source_info.file=(-1);
cristye8c25f92010-06-03 00:53:06 +00004002 (void) FormatMagickString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
4003 image->filename,(double) GetImageIndexInList(image));
cristy87528ea2009-09-10 14:53:56 +00004004 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +00004005 cache_info->rows=image->rows;
4006 cache_info->columns=image->columns;
4007 cache_info->active_index_channel=((image->storage_class == PseudoClass) ||
4008 (image->colorspace == CMYKColorspace)) ? MagickTrue : MagickFalse;
cristy73724512010-04-12 14:43:14 +00004009 if (image->ping != MagickFalse)
4010 {
4011 cache_info->storage_class=image->storage_class;
4012 cache_info->colorspace=image->colorspace;
4013 cache_info->type=PingCache;
4014 cache_info->pixels=(PixelPacket *) NULL;
4015 cache_info->indexes=(IndexPacket *) NULL;
4016 cache_info->length=0;
4017 return(MagickTrue);
4018 }
cristy3ed852e2009-09-05 21:47:34 +00004019 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4020 packet_size=sizeof(PixelPacket);
4021 if (cache_info->active_index_channel != MagickFalse)
4022 packet_size+=sizeof(IndexPacket);
4023 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00004024 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00004025 if (cache_info->columns != columns)
4026 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4027 image->filename);
4028 cache_info->length=length;
4029 status=AcquireMagickResource(AreaResource,cache_info->length);
4030 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4031 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4032 {
4033 status=AcquireMagickResource(MemoryResource,cache_info->length);
4034 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4035 (cache_info->type == MemoryCache))
4036 {
cristyd43a46b2010-01-21 02:13:41 +00004037 AllocatePixelCachePixels(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004038 if (cache_info->pixels == (PixelPacket *) NULL)
4039 cache_info->pixels=source_info.pixels;
4040 else
4041 {
4042 /*
4043 Create memory pixel cache.
4044 */
4045 if (image->debug != MagickFalse)
4046 {
cristy97e7a572009-12-05 15:07:53 +00004047 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004048 format);
cristy3ed852e2009-09-05 21:47:34 +00004049 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004050 "open %s (%s memory, %.20gx%.20g %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00004051 cache_info->mapped != MagickFalse ? "anonymous" : "heap",
cristye8c25f92010-06-03 00:53:06 +00004052 (double) cache_info->columns,(double) cache_info->rows,
4053 format);
cristy3ed852e2009-09-05 21:47:34 +00004054 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4055 message);
4056 }
4057 cache_info->storage_class=image->storage_class;
4058 cache_info->colorspace=image->colorspace;
4059 cache_info->type=MemoryCache;
4060 cache_info->indexes=(IndexPacket *) NULL;
4061 if (cache_info->active_index_channel != MagickFalse)
4062 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4063 number_pixels);
4064 if (source_info.storage_class != UndefinedClass)
4065 {
4066 status|=ClonePixelCachePixels(cache_info,&source_info,
4067 exception);
4068 RelinquishPixelCachePixels(&source_info);
4069 }
4070 return(MagickTrue);
4071 }
4072 }
4073 RelinquishMagickResource(MemoryResource,cache_info->length);
4074 }
4075 /*
4076 Create pixel cache on disk.
4077 */
4078 status=AcquireMagickResource(DiskResource,cache_info->length);
4079 if (status == MagickFalse)
4080 {
4081 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4082 "CacheResourcesExhausted","`%s'",image->filename);
4083 return(MagickFalse);
4084 }
4085 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4086 {
4087 RelinquishMagickResource(DiskResource,cache_info->length);
4088 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4089 image->filename);
4090 return(MagickFalse);
4091 }
4092 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4093 cache_info->length);
4094 if (status == MagickFalse)
4095 {
4096 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4097 image->filename);
4098 return(MagickFalse);
4099 }
4100 cache_info->storage_class=image->storage_class;
4101 cache_info->colorspace=image->colorspace;
4102 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4103 status=AcquireMagickResource(AreaResource,cache_info->length);
4104 if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4105 cache_info->type=DiskCache;
4106 else
4107 {
4108 status=AcquireMagickResource(MapResource,cache_info->length);
4109 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4110 (cache_info->type != MemoryCache))
4111 cache_info->type=DiskCache;
4112 else
4113 {
4114 cache_info->pixels=(PixelPacket *) MapBlob(cache_info->file,mode,
4115 cache_info->offset,(size_t) cache_info->length);
4116 if (cache_info->pixels == (PixelPacket *) NULL)
4117 {
4118 cache_info->pixels=source_info.pixels;
4119 cache_info->type=DiskCache;
4120 }
4121 else
4122 {
4123 /*
4124 Create file-backed memory-mapped pixel cache.
4125 */
4126 (void) ClosePixelCacheOnDisk(cache_info);
4127 cache_info->type=MapCache;
4128 cache_info->mapped=MagickTrue;
4129 cache_info->indexes=(IndexPacket *) NULL;
4130 if (cache_info->active_index_channel != MagickFalse)
4131 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4132 number_pixels);
4133 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4134 {
4135 status=ClonePixelCachePixels(cache_info,&source_info,
4136 exception);
4137 RelinquishPixelCachePixels(&source_info);
4138 }
4139 if (image->debug != MagickFalse)
4140 {
cristy97e7a572009-12-05 15:07:53 +00004141 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004142 format);
cristy3ed852e2009-09-05 21:47:34 +00004143 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004144 "open %s (%s[%d], memory-mapped, %.20gx%.20g %sB)",
cristy3ed852e2009-09-05 21:47:34 +00004145 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004146 cache_info->file,(double) cache_info->columns,(double)
4147 cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004148 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4149 message);
4150 }
4151 return(MagickTrue);
4152 }
4153 }
4154 RelinquishMagickResource(MapResource,cache_info->length);
4155 }
4156 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4157 {
4158 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4159 RelinquishPixelCachePixels(&source_info);
4160 }
4161 if (image->debug != MagickFalse)
4162 {
cristyb9080c92009-12-01 20:13:26 +00004163 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00004164 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004165 "open %s (%s[%d], disk, %.20gx%.20g %sB)",cache_info->filename,
4166 cache_info->cache_filename,cache_info->file,(double)
4167 cache_info->columns,(double) cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004168 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4169 }
4170 return(MagickTrue);
4171}
4172
4173/*
4174%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4175% %
4176% %
4177% %
4178+ P e r s i s t P i x e l C a c h e %
4179% %
4180% %
4181% %
4182%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4183%
4184% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4185% persistent pixel cache is one that resides on disk and is not destroyed
4186% when the program exits.
4187%
4188% The format of the PersistPixelCache() method is:
4189%
4190% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4191% const MagickBooleanType attach,MagickOffsetType *offset,
4192% ExceptionInfo *exception)
4193%
4194% A description of each parameter follows:
4195%
4196% o image: the image.
4197%
4198% o filename: the persistent pixel cache filename.
4199%
cristyf3a6a9d2010-11-07 21:02:56 +00004200% o attach: A value other than zero initializes the persistent pixel cache.
cristy01b7eb02009-09-10 23:10:14 +00004201%
cristy3ed852e2009-09-05 21:47:34 +00004202% o initialize: A value other than zero initializes the persistent pixel
4203% cache.
4204%
4205% o offset: the offset in the persistent cache to store pixels.
4206%
4207% o exception: return any errors or warnings in this structure.
4208%
4209*/
4210MagickExport MagickBooleanType PersistPixelCache(Image *image,
4211 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4212 ExceptionInfo *exception)
4213{
4214 CacheInfo
4215 *cache_info,
4216 *clone_info;
4217
4218 Image
4219 clone_image;
4220
cristy3ed852e2009-09-05 21:47:34 +00004221 MagickBooleanType
4222 status;
4223
cristye076a6e2010-08-15 19:59:43 +00004224 ssize_t
4225 page_size;
4226
cristy3ed852e2009-09-05 21:47:34 +00004227 assert(image != (Image *) NULL);
4228 assert(image->signature == MagickSignature);
4229 if (image->debug != MagickFalse)
4230 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4231 assert(image->cache != (void *) NULL);
4232 assert(filename != (const char *) NULL);
4233 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004234 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004235 cache_info=(CacheInfo *) image->cache;
4236 assert(cache_info->signature == MagickSignature);
4237 if (attach != MagickFalse)
4238 {
4239 /*
cristy01b7eb02009-09-10 23:10:14 +00004240 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004241 */
4242 if (image->debug != MagickFalse)
4243 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004244 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004245 (void) CopyMagickString(cache_info->cache_filename,filename,
4246 MaxTextExtent);
4247 cache_info->type=DiskCache;
4248 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004249 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004250 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004251 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004252 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004253 }
cristy01b7eb02009-09-10 23:10:14 +00004254 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4255 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004256 {
cristyf84a1932010-01-03 18:00:18 +00004257 LockSemaphoreInfo(cache_info->semaphore);
cristy09449f72010-01-23 03:08:36 +00004258 if ((cache_info->mode != ReadMode) &&
4259 (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004260 (cache_info->reference_count == 1))
4261 {
4262 int
4263 status;
4264
4265 /*
cristy01b7eb02009-09-10 23:10:14 +00004266 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004267 */
4268 status=rename(cache_info->cache_filename,filename);
4269 if (status == 0)
4270 {
4271 (void) CopyMagickString(cache_info->cache_filename,filename,
4272 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004273 *offset+=cache_info->length+page_size-(cache_info->length %
4274 page_size);
cristyf84a1932010-01-03 18:00:18 +00004275 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004276 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004277 if (image->debug != MagickFalse)
4278 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4279 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004280 return(MagickTrue);
4281 }
4282 }
cristyf84a1932010-01-03 18:00:18 +00004283 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004284 }
4285 /*
cristy01b7eb02009-09-10 23:10:14 +00004286 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004287 */
4288 clone_image=(*image);
4289 clone_info=(CacheInfo *) clone_image.cache;
4290 image->cache=ClonePixelCache(cache_info);
4291 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4292 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4293 cache_info->type=DiskCache;
4294 cache_info->offset=(*offset);
4295 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004296 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004297 if (status != MagickFalse)
cristycfae90a2010-10-04 14:43:33 +00004298 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
cristy688f07b2009-09-27 15:19:13 +00004299 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004300 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4301 return(status);
4302}
4303
4304/*
4305%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4306% %
4307% %
4308% %
4309+ Q u e u e A u t h e n t i c N e x u s %
4310% %
4311% %
4312% %
4313%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4314%
4315% QueueAuthenticNexus() allocates an region to store image pixels as defined
4316% by the region rectangle and returns a pointer to the region. This region is
4317% subsequently transferred from the pixel cache with
4318% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4319% pixels are transferred, otherwise a NULL is returned.
4320%
4321% The format of the QueueAuthenticNexus() method is:
4322%
cristy5f959472010-05-27 22:19:46 +00004323% PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
4324% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004325% NexusInfo *nexus_info,ExceptionInfo *exception)
4326%
4327% A description of each parameter follows:
4328%
4329% o image: the image.
4330%
4331% o x,y,columns,rows: These values define the perimeter of a region of
4332% pixels.
4333%
4334% o nexus_info: the cache nexus to set.
4335%
4336% o exception: return any errors or warnings in this structure.
4337%
4338*/
cristybb503372010-05-27 20:51:26 +00004339MagickExport PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy30097232010-07-01 02:16:30 +00004340 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
4341 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004342{
4343 CacheInfo
4344 *cache_info;
4345
4346 MagickOffsetType
4347 offset;
4348
4349 MagickSizeType
4350 number_pixels;
4351
4352 RectangleInfo
4353 region;
4354
4355 /*
4356 Validate pixel cache geometry.
4357 */
cristye7cc7cf2010-09-21 13:26:47 +00004358 assert(image != (const Image *) NULL);
4359 assert(image->signature == MagickSignature);
4360 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004361 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
cristye7cc7cf2010-09-21 13:26:47 +00004362 assert(cache_info->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00004363 if (cache_info == (Cache) NULL)
4364 return((PixelPacket *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004365 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4366 {
4367 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4368 "NoPixelsDefinedInCache","`%s'",image->filename);
4369 return((PixelPacket *) NULL);
4370 }
cristybb503372010-05-27 20:51:26 +00004371 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4372 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004373 {
4374 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4375 "PixelsAreNotAuthentic","`%s'",image->filename);
4376 return((PixelPacket *) NULL);
4377 }
4378 offset=(MagickOffsetType) y*cache_info->columns+x;
4379 if (offset < 0)
4380 return((PixelPacket *) NULL);
4381 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4382 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4383 if ((MagickSizeType) offset >= number_pixels)
4384 return((PixelPacket *) NULL);
4385 /*
4386 Return pixel cache.
4387 */
4388 region.x=x;
4389 region.y=y;
4390 region.width=columns;
4391 region.height=rows;
4392 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4393}
4394
4395/*
4396%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4397% %
4398% %
4399% %
4400+ 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 %
4401% %
4402% %
4403% %
4404%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4405%
4406% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4407% defined by the region rectangle and returns a pointer to the region. This
4408% region is subsequently transferred from the pixel cache with
4409% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4410% pixels are transferred, otherwise a NULL is returned.
4411%
4412% The format of the QueueAuthenticPixelsCache() method is:
4413%
cristybb503372010-05-27 20:51:26 +00004414% PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4415% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004416% ExceptionInfo *exception)
4417%
4418% A description of each parameter follows:
4419%
4420% o image: the image.
4421%
4422% o x,y,columns,rows: These values define the perimeter of a region of
4423% pixels.
4424%
4425% o exception: return any errors or warnings in this structure.
4426%
4427*/
cristybb503372010-05-27 20:51:26 +00004428static PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4429 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004430 ExceptionInfo *exception)
4431{
4432 CacheInfo
4433 *cache_info;
4434
cristy5c9e6f22010-09-17 17:31:01 +00004435 const int
4436 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004437
cristye7cc7cf2010-09-21 13:26:47 +00004438 assert(image != (const Image *) NULL);
4439 assert(image->signature == MagickSignature);
4440 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004441 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004442 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004443 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00004444 return(QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4445 exception));
cristy3ed852e2009-09-05 21:47:34 +00004446}
4447
4448/*
4449%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4450% %
4451% %
4452% %
4453% Q u e u e A u t h e n t i c P i x e l s %
4454% %
4455% %
4456% %
4457%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4458%
4459% QueueAuthenticPixels() queues a mutable pixel region. If the region is
4460% successfully intialized a pointer to a PixelPacket array representing the
4461% region is returned, otherwise NULL is returned. The returned pointer may
4462% point to a temporary working buffer for the pixels or it may point to the
4463% final location of the pixels in memory.
4464%
4465% Write-only access means that any existing pixel values corresponding to
4466% the region are ignored. This is useful if the initial image is being
4467% created from scratch, or if the existing pixel values are to be
4468% completely replaced without need to refer to their pre-existing values.
4469% The application is free to read and write the pixel buffer returned by
4470% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4471% initialize the pixel array values. Initializing pixel array values is the
4472% application's responsibility.
4473%
4474% Performance is maximized if the selected region is part of one row, or
4475% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004476% pixels in-place (without a copy) if the image is in memory, or in a
4477% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004478% by the user.
4479%
4480% Pixels accessed via the returned pointer represent a simple array of type
4481% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
4482% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
4483% the black color component or the colormap indexes (of type IndexPacket)
4484% corresponding to the region. Once the PixelPacket (and/or IndexPacket)
4485% array has been updated, the changes must be saved back to the underlying
4486% image using SyncAuthenticPixels() or they may be lost.
4487%
4488% The format of the QueueAuthenticPixels() method is:
4489%
cristy5f959472010-05-27 22:19:46 +00004490% PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4491% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004492% ExceptionInfo *exception)
4493%
4494% A description of each parameter follows:
4495%
4496% o image: the image.
4497%
4498% o x,y,columns,rows: These values define the perimeter of a region of
4499% pixels.
4500%
4501% o exception: return any errors or warnings in this structure.
4502%
4503*/
cristybb503372010-05-27 20:51:26 +00004504MagickExport PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4505 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004506 ExceptionInfo *exception)
4507{
4508 CacheInfo
4509 *cache_info;
4510
cristy2036f5c2010-09-19 21:18:17 +00004511 const int
4512 id = GetOpenMPThreadId();
4513
cristy3ed852e2009-09-05 21:47:34 +00004514 assert(image != (Image *) NULL);
4515 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004516 assert(image->cache != (Cache) NULL);
4517 cache_info=(CacheInfo *) image->cache;
4518 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004519 if (cache_info->methods.queue_authentic_pixels_handler !=
4520 (QueueAuthenticPixelsHandler) NULL)
4521 return(cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4522 rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00004523 assert(id < (int) cache_info->number_threads);
4524 return(QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4525 exception));
cristy3ed852e2009-09-05 21:47:34 +00004526}
4527
4528/*
4529%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4530% %
4531% %
4532% %
4533+ R e a d P i x e l C a c h e I n d e x e s %
4534% %
4535% %
4536% %
4537%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4538%
4539% ReadPixelCacheIndexes() reads colormap indexes from the specified region of
4540% the pixel cache.
4541%
4542% The format of the ReadPixelCacheIndexes() method is:
4543%
4544% MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4545% NexusInfo *nexus_info,ExceptionInfo *exception)
4546%
4547% A description of each parameter follows:
4548%
4549% o cache_info: the pixel cache.
4550%
4551% o nexus_info: the cache nexus to read the colormap indexes.
4552%
4553% o exception: return any errors or warnings in this structure.
4554%
4555*/
4556static MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4557 NexusInfo *nexus_info,ExceptionInfo *exception)
4558{
4559 MagickOffsetType
4560 count,
4561 offset;
4562
4563 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004564 extent,
4565 length;
cristy3ed852e2009-09-05 21:47:34 +00004566
4567 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004568 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004569
cristybb503372010-05-27 20:51:26 +00004570 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004571 y;
4572
cristybb503372010-05-27 20:51:26 +00004573 size_t
cristy3ed852e2009-09-05 21:47:34 +00004574 rows;
4575
cristy3ed852e2009-09-05 21:47:34 +00004576 if (cache_info->active_index_channel == MagickFalse)
4577 return(MagickFalse);
4578 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4579 return(MagickTrue);
4580 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4581 nexus_info->region.x;
4582 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
4583 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004584 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004585 q=nexus_info->indexes;
4586 switch (cache_info->type)
4587 {
4588 case MemoryCache:
4589 case MapCache:
4590 {
4591 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004592 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004593
4594 /*
4595 Read indexes from memory.
4596 */
cristydd341db2010-03-04 19:06:38 +00004597 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004598 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004599 {
cristy48078b12010-09-23 17:11:01 +00004600 length=extent;
cristydd341db2010-03-04 19:06:38 +00004601 rows=1UL;
4602 }
cristy3ed852e2009-09-05 21:47:34 +00004603 p=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00004604 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004605 {
cristy8f036fe2010-09-18 02:02:00 +00004606 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00004607 p+=cache_info->columns;
4608 q+=nexus_info->region.width;
4609 }
4610 break;
4611 }
4612 case DiskCache:
4613 {
4614 /*
4615 Read indexes from disk.
4616 */
4617 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4618 {
4619 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4620 cache_info->cache_filename);
4621 return(MagickFalse);
4622 }
cristydd341db2010-03-04 19:06:38 +00004623 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004624 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004625 {
cristy48078b12010-09-23 17:11:01 +00004626 length=extent;
cristydd341db2010-03-04 19:06:38 +00004627 rows=1UL;
4628 }
cristy48078b12010-09-23 17:11:01 +00004629 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004630 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004631 {
cristy48078b12010-09-23 17:11:01 +00004632 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristy3ed852e2009-09-05 21:47:34 +00004633 sizeof(PixelPacket)+offset*sizeof(*q),length,(unsigned char *) q);
4634 if ((MagickSizeType) count < length)
4635 break;
4636 offset+=cache_info->columns;
4637 q+=nexus_info->region.width;
4638 }
cristybb503372010-05-27 20:51:26 +00004639 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004640 {
4641 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4642 cache_info->cache_filename);
4643 return(MagickFalse);
4644 }
4645 break;
4646 }
4647 default:
4648 break;
4649 }
4650 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004651 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004652 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004653 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004654 nexus_info->region.width,(double) nexus_info->region.height,(double)
4655 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004656 return(MagickTrue);
4657}
4658
4659/*
4660%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4661% %
4662% %
4663% %
4664+ R e a d P i x e l C a c h e P i x e l s %
4665% %
4666% %
4667% %
4668%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4669%
4670% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4671% cache.
4672%
4673% The format of the ReadPixelCachePixels() method is:
4674%
4675% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4676% NexusInfo *nexus_info,ExceptionInfo *exception)
4677%
4678% A description of each parameter follows:
4679%
4680% o cache_info: the pixel cache.
4681%
4682% o nexus_info: the cache nexus to read the pixels.
4683%
4684% o exception: return any errors or warnings in this structure.
4685%
4686*/
4687static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4688 NexusInfo *nexus_info,ExceptionInfo *exception)
4689{
4690 MagickOffsetType
4691 count,
4692 offset;
4693
4694 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004695 extent,
4696 length;
cristy3ed852e2009-09-05 21:47:34 +00004697
cristy3ed852e2009-09-05 21:47:34 +00004698 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004699 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004700
cristye076a6e2010-08-15 19:59:43 +00004701 register ssize_t
4702 y;
4703
cristybb503372010-05-27 20:51:26 +00004704 size_t
cristy3ed852e2009-09-05 21:47:34 +00004705 rows;
4706
cristy3ed852e2009-09-05 21:47:34 +00004707 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4708 return(MagickTrue);
4709 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4710 nexus_info->region.x;
4711 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
4712 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004713 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004714 q=nexus_info->pixels;
4715 switch (cache_info->type)
4716 {
4717 case MemoryCache:
4718 case MapCache:
4719 {
4720 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004721 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004722
4723 /*
4724 Read pixels from memory.
4725 */
cristydd341db2010-03-04 19:06:38 +00004726 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004727 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004728 {
cristy48078b12010-09-23 17:11:01 +00004729 length=extent;
cristydd341db2010-03-04 19:06:38 +00004730 rows=1UL;
4731 }
cristy3ed852e2009-09-05 21:47:34 +00004732 p=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00004733 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004734 {
cristy8f036fe2010-09-18 02:02:00 +00004735 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00004736 p+=cache_info->columns;
4737 q+=nexus_info->region.width;
4738 }
4739 break;
4740 }
4741 case DiskCache:
4742 {
4743 /*
4744 Read pixels from disk.
4745 */
4746 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4747 {
4748 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4749 cache_info->cache_filename);
4750 return(MagickFalse);
4751 }
cristydd341db2010-03-04 19:06:38 +00004752 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004753 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004754 {
cristy48078b12010-09-23 17:11:01 +00004755 length=extent;
cristydd341db2010-03-04 19:06:38 +00004756 rows=1UL;
4757 }
cristybb503372010-05-27 20:51:26 +00004758 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004759 {
4760 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4761 sizeof(*q),length,(unsigned char *) q);
4762 if ((MagickSizeType) count < length)
4763 break;
4764 offset+=cache_info->columns;
4765 q+=nexus_info->region.width;
4766 }
cristybb503372010-05-27 20:51:26 +00004767 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004768 {
4769 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4770 cache_info->cache_filename);
4771 return(MagickFalse);
4772 }
4773 break;
4774 }
4775 default:
4776 break;
4777 }
4778 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004779 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004780 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004781 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004782 nexus_info->region.width,(double) nexus_info->region.height,(double)
4783 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004784 return(MagickTrue);
4785}
4786
4787/*
4788%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4789% %
4790% %
4791% %
4792+ R e f e r e n c e P i x e l C a c h e %
4793% %
4794% %
4795% %
4796%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4797%
4798% ReferencePixelCache() increments the reference count associated with the
4799% pixel cache returning a pointer to the cache.
4800%
4801% The format of the ReferencePixelCache method is:
4802%
4803% Cache ReferencePixelCache(Cache cache_info)
4804%
4805% A description of each parameter follows:
4806%
4807% o cache_info: the pixel cache.
4808%
4809*/
4810MagickExport Cache ReferencePixelCache(Cache cache)
4811{
4812 CacheInfo
4813 *cache_info;
4814
4815 assert(cache != (Cache *) NULL);
4816 cache_info=(CacheInfo *) cache;
4817 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004818 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004819 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004820 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004821 return(cache_info);
4822}
4823
4824/*
4825%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4826% %
4827% %
4828% %
4829+ S e t P i x e l C a c h e M e t h o d s %
4830% %
4831% %
4832% %
4833%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4834%
4835% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4836%
4837% The format of the SetPixelCacheMethods() method is:
4838%
4839% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4840%
4841% A description of each parameter follows:
4842%
4843% o cache: the pixel cache.
4844%
4845% o cache_methods: Specifies a pointer to a CacheMethods structure.
4846%
4847*/
4848MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4849{
4850 CacheInfo
4851 *cache_info;
4852
4853 GetOneAuthenticPixelFromHandler
4854 get_one_authentic_pixel_from_handler;
4855
4856 GetOneVirtualPixelFromHandler
4857 get_one_virtual_pixel_from_handler;
4858
4859 /*
4860 Set cache pixel methods.
4861 */
4862 assert(cache != (Cache) NULL);
4863 assert(cache_methods != (CacheMethods *) NULL);
4864 cache_info=(CacheInfo *) cache;
4865 assert(cache_info->signature == MagickSignature);
4866 if (cache_info->debug != MagickFalse)
4867 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4868 cache_info->filename);
4869 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4870 cache_info->methods.get_virtual_pixel_handler=
4871 cache_methods->get_virtual_pixel_handler;
4872 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4873 cache_info->methods.destroy_pixel_handler=
4874 cache_methods->destroy_pixel_handler;
4875 if (cache_methods->get_virtual_indexes_from_handler !=
4876 (GetVirtualIndexesFromHandler) NULL)
4877 cache_info->methods.get_virtual_indexes_from_handler=
4878 cache_methods->get_virtual_indexes_from_handler;
4879 if (cache_methods->get_authentic_pixels_handler !=
4880 (GetAuthenticPixelsHandler) NULL)
4881 cache_info->methods.get_authentic_pixels_handler=
4882 cache_methods->get_authentic_pixels_handler;
4883 if (cache_methods->queue_authentic_pixels_handler !=
4884 (QueueAuthenticPixelsHandler) NULL)
4885 cache_info->methods.queue_authentic_pixels_handler=
4886 cache_methods->queue_authentic_pixels_handler;
4887 if (cache_methods->sync_authentic_pixels_handler !=
4888 (SyncAuthenticPixelsHandler) NULL)
4889 cache_info->methods.sync_authentic_pixels_handler=
4890 cache_methods->sync_authentic_pixels_handler;
4891 if (cache_methods->get_authentic_pixels_from_handler !=
4892 (GetAuthenticPixelsFromHandler) NULL)
4893 cache_info->methods.get_authentic_pixels_from_handler=
4894 cache_methods->get_authentic_pixels_from_handler;
4895 if (cache_methods->get_authentic_indexes_from_handler !=
4896 (GetAuthenticIndexesFromHandler) NULL)
4897 cache_info->methods.get_authentic_indexes_from_handler=
4898 cache_methods->get_authentic_indexes_from_handler;
4899 get_one_virtual_pixel_from_handler=
4900 cache_info->methods.get_one_virtual_pixel_from_handler;
4901 if (get_one_virtual_pixel_from_handler !=
4902 (GetOneVirtualPixelFromHandler) NULL)
4903 cache_info->methods.get_one_virtual_pixel_from_handler=
4904 cache_methods->get_one_virtual_pixel_from_handler;
4905 get_one_authentic_pixel_from_handler=
4906 cache_methods->get_one_authentic_pixel_from_handler;
4907 if (get_one_authentic_pixel_from_handler !=
4908 (GetOneAuthenticPixelFromHandler) NULL)
4909 cache_info->methods.get_one_authentic_pixel_from_handler=
4910 cache_methods->get_one_authentic_pixel_from_handler;
4911}
4912
4913/*
4914%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4915% %
4916% %
4917% %
4918+ S e t P i x e l C a c h e N e x u s P i x e l s %
4919% %
4920% %
4921% %
4922%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4923%
4924% SetPixelCacheNexusPixels() defines the region of the cache for the
4925% specified cache nexus.
4926%
4927% The format of the SetPixelCacheNexusPixels() method is:
4928%
4929% PixelPacket SetPixelCacheNexusPixels(const Image *image,
4930% const RectangleInfo *region,NexusInfo *nexus_info,
4931% ExceptionInfo *exception)
4932%
4933% A description of each parameter follows:
4934%
4935% o image: the image.
4936%
4937% o region: A pointer to the RectangleInfo structure that defines the
4938% region of this particular cache nexus.
4939%
4940% o nexus_info: the cache nexus to set.
4941%
4942% o exception: return any errors or warnings in this structure.
4943%
4944*/
cristyabd6e372010-09-15 19:11:26 +00004945
4946static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4947 NexusInfo *nexus_info,ExceptionInfo *exception)
4948{
4949 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4950 return(MagickFalse);
4951 nexus_info->mapped=MagickFalse;
4952 nexus_info->cache=(PixelPacket *) AcquireMagickMemory((size_t)
4953 nexus_info->length);
4954 if (nexus_info->cache == (PixelPacket *) NULL)
4955 {
4956 nexus_info->mapped=MagickTrue;
4957 nexus_info->cache=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
4958 nexus_info->length);
4959 }
4960 if (nexus_info->cache == (PixelPacket *) NULL)
4961 {
4962 (void) ThrowMagickException(exception,GetMagickModule(),
4963 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4964 cache_info->filename);
4965 return(MagickFalse);
4966 }
4967 return(MagickTrue);
4968}
4969
cristy3ed852e2009-09-05 21:47:34 +00004970static PixelPacket *SetPixelCacheNexusPixels(const Image *image,
4971 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4972{
4973 CacheInfo
4974 *cache_info;
4975
4976 MagickBooleanType
4977 status;
4978
cristy3ed852e2009-09-05 21:47:34 +00004979 MagickSizeType
4980 length,
4981 number_pixels;
4982
cristy3ed852e2009-09-05 21:47:34 +00004983 cache_info=(CacheInfo *) image->cache;
4984 assert(cache_info->signature == MagickSignature);
4985 if (cache_info->type == UndefinedCache)
4986 return((PixelPacket *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00004987 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00004988 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
4989 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00004990 {
cristybb503372010-05-27 20:51:26 +00004991 ssize_t
cristybad067a2010-02-15 17:20:55 +00004992 x,
4993 y;
cristy3ed852e2009-09-05 21:47:34 +00004994
cristyeaedf062010-05-29 22:36:02 +00004995 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4996 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00004997 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4998 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00004999 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00005000 ((nexus_info->region.width == cache_info->columns) ||
5001 ((nexus_info->region.width % cache_info->columns) == 0)))))
5002 {
5003 MagickOffsetType
5004 offset;
5005
5006 /*
5007 Pixels are accessed directly from memory.
5008 */
5009 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5010 nexus_info->region.x;
5011 nexus_info->pixels=cache_info->pixels+offset;
5012 nexus_info->indexes=(IndexPacket *) NULL;
5013 if (cache_info->active_index_channel != MagickFalse)
5014 nexus_info->indexes=cache_info->indexes+offset;
5015 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00005016 }
5017 }
5018 /*
5019 Pixels are stored in a cache region until they are synced to the cache.
5020 */
5021 number_pixels=(MagickSizeType) nexus_info->region.width*
5022 nexus_info->region.height;
5023 length=number_pixels*sizeof(PixelPacket);
5024 if (cache_info->active_index_channel != MagickFalse)
5025 length+=number_pixels*sizeof(IndexPacket);
5026 if (nexus_info->cache == (PixelPacket *) NULL)
5027 {
5028 nexus_info->length=length;
5029 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5030 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005031 {
5032 nexus_info->length=0;
5033 return((PixelPacket *) NULL);
5034 }
cristy3ed852e2009-09-05 21:47:34 +00005035 }
5036 else
5037 if (nexus_info->length != length)
5038 {
5039 RelinquishCacheNexusPixels(nexus_info);
5040 nexus_info->length=length;
5041 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5042 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005043 {
5044 nexus_info->length=0;
5045 return((PixelPacket *) NULL);
5046 }
cristy3ed852e2009-09-05 21:47:34 +00005047 }
5048 nexus_info->pixels=nexus_info->cache;
5049 nexus_info->indexes=(IndexPacket *) NULL;
5050 if (cache_info->active_index_channel != MagickFalse)
5051 nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
5052 return(nexus_info->pixels);
5053}
5054
5055/*
5056%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5057% %
5058% %
5059% %
5060% 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 %
5061% %
5062% %
5063% %
5064%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5065%
5066% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5067% pixel cache and returns the previous setting. A virtual pixel is any pixel
5068% access that is outside the boundaries of the image cache.
5069%
5070% The format of the SetPixelCacheVirtualMethod() method is:
5071%
5072% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5073% const VirtualPixelMethod virtual_pixel_method)
5074%
5075% A description of each parameter follows:
5076%
5077% o image: the image.
5078%
5079% o virtual_pixel_method: choose the type of virtual pixel.
5080%
5081*/
5082MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5083 const VirtualPixelMethod virtual_pixel_method)
5084{
5085 CacheInfo
5086 *cache_info;
5087
5088 VirtualPixelMethod
5089 method;
5090
5091 assert(image != (Image *) NULL);
5092 assert(image->signature == MagickSignature);
5093 if (image->debug != MagickFalse)
5094 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5095 assert(image->cache != (Cache) NULL);
5096 cache_info=(CacheInfo *) image->cache;
5097 assert(cache_info->signature == MagickSignature);
5098 method=cache_info->virtual_pixel_method;
5099 cache_info->virtual_pixel_method=virtual_pixel_method;
5100 return(method);
5101}
5102
5103/*
5104%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5105% %
5106% %
5107% %
5108+ 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 %
5109% %
5110% %
5111% %
5112%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5113%
5114% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5115% in-memory or disk cache. The method returns MagickTrue if the pixel region
5116% is synced, otherwise MagickFalse.
5117%
5118% The format of the SyncAuthenticPixelCacheNexus() method is:
5119%
5120% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5121% NexusInfo *nexus_info,ExceptionInfo *exception)
5122%
5123% A description of each parameter follows:
5124%
5125% o image: the image.
5126%
5127% o nexus_info: the cache nexus to sync.
5128%
5129% o exception: return any errors or warnings in this structure.
5130%
5131*/
5132MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5133 NexusInfo *nexus_info,ExceptionInfo *exception)
5134{
5135 CacheInfo
5136 *cache_info;
5137
5138 MagickBooleanType
5139 status;
5140
5141 /*
5142 Transfer pixels to the cache.
5143 */
5144 assert(image != (Image *) NULL);
5145 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005146 if (image->cache == (Cache) NULL)
5147 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5148 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005149 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005150 if (cache_info->type == UndefinedCache)
5151 return(MagickFalse);
5152 if ((image->clip_mask != (Image *) NULL) &&
5153 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5154 return(MagickFalse);
5155 if ((image->mask != (Image *) NULL) &&
5156 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5157 return(MagickFalse);
5158 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5159 return(MagickTrue);
5160 assert(cache_info->signature == MagickSignature);
5161 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5162 if ((cache_info->active_index_channel != MagickFalse) &&
5163 (WritePixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse))
5164 return(MagickFalse);
5165 return(status);
5166}
5167
5168/*
5169%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5170% %
5171% %
5172% %
5173+ S y n c A u t h e n t i c P i x e l C a c h e %
5174% %
5175% %
5176% %
5177%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5178%
5179% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5180% or disk cache. The method returns MagickTrue if the pixel region is synced,
5181% otherwise MagickFalse.
5182%
5183% The format of the SyncAuthenticPixelsCache() method is:
5184%
5185% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5186% ExceptionInfo *exception)
5187%
5188% A description of each parameter follows:
5189%
5190% o image: the image.
5191%
5192% o exception: return any errors or warnings in this structure.
5193%
5194*/
5195static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5196 ExceptionInfo *exception)
5197{
5198 CacheInfo
5199 *cache_info;
5200
cristy5c9e6f22010-09-17 17:31:01 +00005201 const int
5202 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005203
cristye7cc7cf2010-09-21 13:26:47 +00005204 assert(image != (Image *) NULL);
5205 assert(image->signature == MagickSignature);
5206 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005207 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005208 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005209 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00005210 return(SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5211 exception));
cristy3ed852e2009-09-05 21:47:34 +00005212}
5213
5214/*
5215%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5216% %
5217% %
5218% %
5219% S y n c A u t h e n t i c P i x e l s %
5220% %
5221% %
5222% %
5223%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5224%
5225% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5226% The method returns MagickTrue if the pixel region is flushed, otherwise
5227% MagickFalse.
5228%
5229% The format of the SyncAuthenticPixels() method is:
5230%
5231% MagickBooleanType SyncAuthenticPixels(Image *image,
5232% ExceptionInfo *exception)
5233%
5234% A description of each parameter follows:
5235%
5236% o image: the image.
5237%
5238% o exception: return any errors or warnings in this structure.
5239%
5240*/
5241MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5242 ExceptionInfo *exception)
5243{
5244 CacheInfo
5245 *cache_info;
5246
cristy2036f5c2010-09-19 21:18:17 +00005247 const int
5248 id = GetOpenMPThreadId();
5249
cristy3ed852e2009-09-05 21:47:34 +00005250 assert(image != (Image *) NULL);
5251 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005252 assert(image->cache != (Cache) NULL);
5253 cache_info=(CacheInfo *) image->cache;
5254 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005255 if (cache_info->methods.sync_authentic_pixels_handler !=
5256 (SyncAuthenticPixelsHandler) NULL)
5257 return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
cristy2036f5c2010-09-19 21:18:17 +00005258 assert(id < (int) cache_info->number_threads);
5259 return(SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5260 exception));
cristy3ed852e2009-09-05 21:47:34 +00005261}
5262
5263/*
5264%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5265% %
5266% %
5267% %
5268+ W r i t e P i x e l C a c h e I n d e x e s %
5269% %
5270% %
5271% %
5272%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5273%
5274% WritePixelCacheIndexes() writes the colormap indexes to the specified
5275% region of the pixel cache.
5276%
5277% The format of the WritePixelCacheIndexes() method is:
5278%
5279% MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5280% NexusInfo *nexus_info,ExceptionInfo *exception)
5281%
5282% A description of each parameter follows:
5283%
5284% o cache_info: the pixel cache.
5285%
5286% o nexus_info: the cache nexus to write the colormap indexes.
5287%
5288% o exception: return any errors or warnings in this structure.
5289%
5290*/
5291static MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5292 NexusInfo *nexus_info,ExceptionInfo *exception)
5293{
5294 MagickOffsetType
5295 count,
5296 offset;
5297
5298 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005299 extent,
5300 length;
cristy3ed852e2009-09-05 21:47:34 +00005301
5302 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005303 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005304
cristybb503372010-05-27 20:51:26 +00005305 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005306 y;
5307
cristybb503372010-05-27 20:51:26 +00005308 size_t
cristy3ed852e2009-09-05 21:47:34 +00005309 rows;
5310
cristy3ed852e2009-09-05 21:47:34 +00005311 if (cache_info->active_index_channel == MagickFalse)
5312 return(MagickFalse);
5313 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5314 return(MagickTrue);
5315 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5316 nexus_info->region.x;
5317 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
5318 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005319 extent=(MagickSizeType) length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005320 p=nexus_info->indexes;
5321 switch (cache_info->type)
5322 {
5323 case MemoryCache:
5324 case MapCache:
5325 {
5326 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005327 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005328
5329 /*
5330 Write indexes to memory.
5331 */
cristydd341db2010-03-04 19:06:38 +00005332 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005333 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005334 {
cristy48078b12010-09-23 17:11:01 +00005335 length=extent;
cristydd341db2010-03-04 19:06:38 +00005336 rows=1UL;
5337 }
cristy3ed852e2009-09-05 21:47:34 +00005338 q=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00005339 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005340 {
cristy8f036fe2010-09-18 02:02:00 +00005341 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00005342 p+=nexus_info->region.width;
5343 q+=cache_info->columns;
5344 }
5345 break;
5346 }
5347 case DiskCache:
5348 {
5349 /*
5350 Write indexes to disk.
5351 */
5352 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5353 {
5354 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5355 cache_info->cache_filename);
5356 return(MagickFalse);
5357 }
cristydd341db2010-03-04 19:06:38 +00005358 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005359 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005360 {
cristy48078b12010-09-23 17:11:01 +00005361 length=extent;
cristydd341db2010-03-04 19:06:38 +00005362 rows=1UL;
5363 }
cristy48078b12010-09-23 17:11:01 +00005364 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005365 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005366 {
cristy48078b12010-09-23 17:11:01 +00005367 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5368 sizeof(PixelPacket)+offset*sizeof(*p),length,(const unsigned char *)
5369 p);
cristy3ed852e2009-09-05 21:47:34 +00005370 if ((MagickSizeType) count < length)
5371 break;
5372 p+=nexus_info->region.width;
5373 offset+=cache_info->columns;
5374 }
cristybb503372010-05-27 20:51:26 +00005375 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005376 {
5377 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5378 cache_info->cache_filename);
5379 return(MagickFalse);
5380 }
5381 break;
5382 }
5383 default:
5384 break;
5385 }
5386 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005387 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005388 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005389 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005390 nexus_info->region.width,(double) nexus_info->region.height,(double)
5391 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005392 return(MagickTrue);
5393}
5394
5395/*
5396%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5397% %
5398% %
5399% %
5400+ W r i t e C a c h e P i x e l s %
5401% %
5402% %
5403% %
5404%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5405%
5406% WritePixelCachePixels() writes image pixels to the specified region of the
5407% pixel cache.
5408%
5409% The format of the WritePixelCachePixels() method is:
5410%
5411% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5412% NexusInfo *nexus_info,ExceptionInfo *exception)
5413%
5414% A description of each parameter follows:
5415%
5416% o cache_info: the pixel cache.
5417%
5418% o nexus_info: the cache nexus to write the pixels.
5419%
5420% o exception: return any errors or warnings in this structure.
5421%
5422*/
5423static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5424 NexusInfo *nexus_info,ExceptionInfo *exception)
5425{
5426 MagickOffsetType
5427 count,
5428 offset;
5429
5430 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005431 extent,
5432 length;
cristy3ed852e2009-09-05 21:47:34 +00005433
cristy3ed852e2009-09-05 21:47:34 +00005434 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005435 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005436
cristybb503372010-05-27 20:51:26 +00005437 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005438 y;
5439
cristybb503372010-05-27 20:51:26 +00005440 size_t
cristy3ed852e2009-09-05 21:47:34 +00005441 rows;
5442
cristy3ed852e2009-09-05 21:47:34 +00005443 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5444 return(MagickTrue);
5445 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5446 nexus_info->region.x;
5447 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
5448 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005449 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005450 p=nexus_info->pixels;
5451 switch (cache_info->type)
5452 {
5453 case MemoryCache:
5454 case MapCache:
5455 {
5456 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005457 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005458
5459 /*
5460 Write pixels to memory.
5461 */
cristydd341db2010-03-04 19:06:38 +00005462 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005463 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005464 {
cristy48078b12010-09-23 17:11:01 +00005465 length=extent;
cristydd341db2010-03-04 19:06:38 +00005466 rows=1UL;
5467 }
cristy3ed852e2009-09-05 21:47:34 +00005468 q=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00005469 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005470 {
cristy8f036fe2010-09-18 02:02:00 +00005471 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00005472 p+=nexus_info->region.width;
5473 q+=cache_info->columns;
5474 }
5475 break;
5476 }
5477 case DiskCache:
5478 {
5479 /*
5480 Write pixels to disk.
5481 */
5482 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5483 {
5484 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5485 cache_info->cache_filename);
5486 return(MagickFalse);
5487 }
cristydd341db2010-03-04 19:06:38 +00005488 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005489 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005490 {
cristy48078b12010-09-23 17:11:01 +00005491 length=extent;
cristydd341db2010-03-04 19:06:38 +00005492 rows=1UL;
5493 }
cristybb503372010-05-27 20:51:26 +00005494 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005495 {
5496 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5497 sizeof(*p),length,(const unsigned char *) p);
5498 if ((MagickSizeType) count < length)
5499 break;
5500 p+=nexus_info->region.width;
5501 offset+=cache_info->columns;
5502 }
cristybb503372010-05-27 20:51:26 +00005503 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005504 {
5505 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5506 cache_info->cache_filename);
5507 return(MagickFalse);
5508 }
5509 break;
5510 }
5511 default:
5512 break;
5513 }
5514 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005515 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005516 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005517 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005518 nexus_info->region.width,(double) nexus_info->region.height,(double)
5519 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005520 return(MagickTrue);
5521}