blob: 66790ac5e62fb32f345ea732271865ee1d1a6c6f [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% CCCC AAA CCCC H H EEEEE %
7% C A A C H H E %
8% C AAAAA C HHHHH EEE %
9% C A A C H H E %
10% CCCC A A CCCC H H EEEEE %
11% %
12% %
13% MagickCore Pixel Cache Methods %
14% %
15% Software Design %
16% John Cristy %
17% July 1999 %
18% %
19% %
cristy16af1cb2009-12-11 21:38:29 +000020% Copyright 1999-2010 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
26% http://www.imagemagick.org/script/license.php %
27% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37%
38*/
39
40/*
41 Include declarations.
42*/
43#include "magick/studio.h"
44#include "magick/blob.h"
45#include "magick/blob-private.h"
46#include "magick/cache.h"
47#include "magick/cache-private.h"
48#include "magick/color-private.h"
49#include "magick/composite-private.h"
50#include "magick/exception.h"
51#include "magick/exception-private.h"
cristy365e58f2010-02-15 02:00:01 +000052#include "magick/geometry.h"
cristy3ed852e2009-09-05 21:47:34 +000053#include "magick/list.h"
54#include "magick/log.h"
55#include "magick/magick.h"
56#include "magick/memory_.h"
cristy4789f0d2010-01-10 00:01:06 +000057#include "magick/pixel.h"
cristy3ed852e2009-09-05 21:47:34 +000058#include "magick/pixel-private.h"
cristya21afde2010-07-02 00:45:40 +000059#include "magick/policy.h"
cristy3ed852e2009-09-05 21:47:34 +000060#include "magick/quantum.h"
61#include "magick/random_.h"
62#include "magick/resource_.h"
63#include "magick/semaphore.h"
64#include "magick/splay-tree.h"
65#include "magick/string_.h"
cristya21afde2010-07-02 00:45:40 +000066#include "magick/string-private.h"
cristy3ed852e2009-09-05 21:47:34 +000067#include "magick/thread-private.h"
68#include "magick/utility.h"
69#if defined(MAGICKCORE_ZLIB_DELEGATE)
70#include "zlib.h"
71#endif
72
73/*
cristy30097232010-07-01 02:16:30 +000074 Define declarations.
75*/
76#define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
77
78/*
cristy3ed852e2009-09-05 21:47:34 +000079 Typedef declarations.
80*/
81typedef struct _MagickModulo
82{
cristybb503372010-05-27 20:51:26 +000083 ssize_t
cristy3ed852e2009-09-05 21:47:34 +000084 quotient,
85 remainder;
86} MagickModulo;
87
88struct _NexusInfo
89{
90 MagickBooleanType
91 mapped;
92
93 RectangleInfo
94 region;
95
96 MagickSizeType
97 length;
98
99 PixelPacket
100 *cache,
101 *pixels;
102
103 IndexPacket
104 *indexes;
105
cristybb503372010-05-27 20:51:26 +0000106 size_t
cristy3ed852e2009-09-05 21:47:34 +0000107 signature;
108};
109
110/*
111 Forward declarations.
112*/
113#if defined(__cplusplus) || defined(c_plusplus)
114extern "C" {
115#endif
116
117static const IndexPacket
118 *GetVirtualIndexesFromCache(const Image *);
119
120static const PixelPacket
cristybb503372010-05-27 20:51:26 +0000121 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
122 const ssize_t,const size_t,const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000123 *GetVirtualPixelsCache(const Image *);
124
125static MagickBooleanType
cristy09c1c4d2010-06-30 18:23:16 +0000126 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,
127 PixelPacket *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000128 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
cristybb503372010-05-27 20:51:26 +0000129 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
cristybb503372010-05-27 20:51:26 +0000138 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
139 const size_t,ExceptionInfo *),
140 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
141 const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000142 *SetPixelCacheNexusPixels(const Image *,const RectangleInfo *,NexusInfo *,
cristya4af2e32010-03-08 00:51:56 +0000143 ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +0000144
145#if defined(__cplusplus) || defined(c_plusplus)
146}
147#endif
148
149/*
150 Global declarations.
151*/
152static volatile MagickBooleanType
153 instantiate_cache = MagickFalse;
154
155static SemaphoreInfo
156 *cache_semaphore = (SemaphoreInfo *) NULL;
157
158static SplayTreeInfo
159 *cache_resources = (SplayTreeInfo *) NULL;
cristy3ed852e2009-09-05 21:47:34 +0000160
161/*
162%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
163% %
164% %
165% %
166+ A c q u i r e P i x e l C a c h e %
167% %
168% %
169% %
170%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
171%
172% AcquirePixelCache() acquires a pixel cache.
173%
174% The format of the AcquirePixelCache() method is:
175%
cristybb503372010-05-27 20:51:26 +0000176% Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000177%
178% A description of each parameter follows:
179%
180% o number_threads: the number of nexus threads.
181%
182*/
cristybb503372010-05-27 20:51:26 +0000183MagickExport Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000184{
185 CacheInfo
186 *cache_info;
187
188 cache_info=(CacheInfo *) AcquireAlignedMemory(1,sizeof(*cache_info));
189 if (cache_info == (CacheInfo *) NULL)
190 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
191 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
192 cache_info->type=UndefinedCache;
cristy87528ea2009-09-10 14:53:56 +0000193 cache_info->mode=IOMode;
cristy3ed852e2009-09-05 21:47:34 +0000194 cache_info->colorspace=RGBColorspace;
195 cache_info->file=(-1);
196 cache_info->id=GetMagickThreadId();
197 cache_info->number_threads=number_threads;
198 if (number_threads == 0)
199 cache_info->number_threads=GetOpenMPMaximumThreads();
200 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
201 if (cache_info->nexus_info == (NexusInfo **) NULL)
202 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristy3ed852e2009-09-05 21:47:34 +0000203 cache_info->semaphore=AllocateSemaphoreInfo();
cristy93505cf2010-08-10 21:37:49 +0000204 cache_info->reference_count=1;
cristy3ed852e2009-09-05 21:47:34 +0000205 cache_info->disk_semaphore=AllocateSemaphoreInfo();
206 cache_info->debug=IsEventLogging();
207 cache_info->signature=MagickSignature;
208 if ((cache_resources == (SplayTreeInfo *) NULL) &&
209 (instantiate_cache == MagickFalse))
210 {
cristy4e1dff62009-10-25 20:36:03 +0000211 if (cache_semaphore == (SemaphoreInfo *) NULL)
212 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000213 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000214 if ((cache_resources == (SplayTreeInfo *) NULL) &&
215 (instantiate_cache == MagickFalse))
216 {
217 cache_resources=NewSplayTree((int (*)(const void *,const void *))
218 NULL,(void *(*)(void *)) NULL,(void *(*)(void *)) NULL);
219 instantiate_cache=MagickTrue;
220 }
cristyf84a1932010-01-03 18:00:18 +0000221 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000222 }
223 (void) AddValueToSplayTree(cache_resources,cache_info,cache_info);
224 return((Cache ) cache_info);
225}
226
227/*
228%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
229% %
230% %
231% %
232% A c q u i r e P i x e l C a c h e N e x u s %
233% %
234% %
235% %
236%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
237%
238% AcquirePixelCacheNexus() allocates the NexusInfo structure.
239%
240% The format of the AcquirePixelCacheNexus method is:
241%
cristybb503372010-05-27 20:51:26 +0000242% NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000243%
244% A description of each parameter follows:
245%
246% o number_threads: the number of nexus threads.
247%
248*/
cristy2cd7a752010-08-23 00:48:54 +0000249MagickExport NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000250{
cristy3ed852e2009-09-05 21:47:34 +0000251 NexusInfo
252 **nexus_info;
253
cristye076a6e2010-08-15 19:59:43 +0000254 register ssize_t
255 i;
256
cristy3ed852e2009-09-05 21:47:34 +0000257 nexus_info=(NexusInfo **) AcquireAlignedMemory(number_threads,
258 sizeof(*nexus_info));
259 if (nexus_info == (NexusInfo **) NULL)
260 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristybb503372010-05-27 20:51:26 +0000261 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000262 {
263 nexus_info[i]=(NexusInfo *) AcquireAlignedMemory(1,sizeof(**nexus_info));
264 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);
448 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
449 q=nexus_info->pixels;
450 nexus_indexes=nexus_info->indexes;
451 r=GetVirtualPixelsFromNexus(image->clip_mask,MaskVirtualPixelMethod,
452 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
453 nexus_info->region.height,clip_nexus[0],exception);
454 number_pixels=(MagickSizeType) nexus_info->region.width*
455 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +0000456 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000457 {
458 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
459 break;
460 if (PixelIntensityToQuantum(r) > ((Quantum) QuantumRange/2))
461 {
cristyce70c172010-01-07 17:15:30 +0000462 SetRedPixelComponent(q,GetRedPixelComponent(p));
463 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
464 SetBluePixelComponent(q,GetBluePixelComponent(p));
465 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
cristy3ed852e2009-09-05 21:47:34 +0000466 if (cache_info->active_index_channel != MagickFalse)
467 nexus_indexes[i]=indexes[i];
468 }
469 p++;
470 q++;
471 r++;
472 }
473 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
474 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +0000475 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +0000476 return(MagickFalse);
477 return(MagickTrue);
478}
479
480/*
481%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
482% %
483% %
484% %
485+ C l o n e P i x e l C a c h e %
486% %
487% %
488% %
489%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
490%
491% ClonePixelCache() clones a pixel cache.
492%
493% The format of the ClonePixelCache() method is:
494%
495% Cache ClonePixelCache(const Cache cache)
496%
497% A description of each parameter follows:
498%
499% o cache: the pixel cache.
500%
501*/
502MagickExport Cache ClonePixelCache(const Cache cache)
503{
504 CacheInfo
505 *clone_info;
506
507 const CacheInfo
508 *cache_info;
509
510 assert(cache != (const Cache) NULL);
511 cache_info=(const CacheInfo *) cache;
512 assert(cache_info->signature == MagickSignature);
513 if (cache_info->debug != MagickFalse)
514 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
515 cache_info->filename);
516 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
517 if (clone_info == (Cache) NULL)
518 return((Cache) NULL);
519 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
520 return((Cache ) clone_info);
521}
522
523/*
524%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
525% %
526% %
527% %
cristy60c44a82009-10-07 00:58:49 +0000528+ C l o n e P i x e l C a c h e P i x e l s %
cristy3ed852e2009-09-05 21:47:34 +0000529% %
530% %
531% %
532%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
533% ClonePixelCachePixels() clones the source pixel cache to the destination
534% cache.
535%
536% The format of the ClonePixelCachePixels() method is:
537%
538% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
539% CacheInfo *source_info,ExceptionInfo *exception)
540%
541% A description of each parameter follows:
542%
543% o cache_info: the pixel cache.
544%
545% o source_info: the source pixel cache.
546%
547% o exception: return any errors or warnings in this structure.
548%
549*/
550
551static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
552{
553 int
554 status;
555
cristy5ee247a2010-02-12 15:42:34 +0000556 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000557 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000558 if (cache_info->file != -1)
559 status=close(cache_info->file);
cristy3ed852e2009-09-05 21:47:34 +0000560 cache_info->file=(-1);
561 RelinquishMagickResource(FileResource,1);
cristyf84a1932010-01-03 18:00:18 +0000562 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000563 return(status == -1 ? MagickFalse : MagickTrue);
564}
565
566static void LimitPixelCacheDescriptors(void)
567{
568 register CacheInfo
569 *p,
570 *q;
571
572 /*
573 Limit # of open file descriptors.
574 */
575 if (GetMagickResource(FileResource) < GetMagickResourceLimit(FileResource))
576 return;
cristyf84a1932010-01-03 18:00:18 +0000577 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000578 if (cache_resources == (SplayTreeInfo *) NULL)
579 {
cristyf84a1932010-01-03 18:00:18 +0000580 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000581 return;
582 }
583 ResetSplayTreeIterator(cache_resources);
584 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
585 while (p != (CacheInfo *) NULL)
586 {
587 if ((p->type == DiskCache) && (p->file != -1))
cristy508d9312010-02-10 21:10:30 +0000588 break;
cristy3ed852e2009-09-05 21:47:34 +0000589 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
590 }
591 for (q=p; p != (CacheInfo *) NULL; )
592 {
593 if ((p->type == DiskCache) && (p->file != -1) &&
594 (p->timestamp < q->timestamp))
cristy508d9312010-02-10 21:10:30 +0000595 q=p;
cristy3ed852e2009-09-05 21:47:34 +0000596 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
597 }
598 if (q != (CacheInfo *) NULL)
cristy9e116922010-02-12 20:58:13 +0000599 {
600 /*
601 Close least recently used cache.
602 */
603 (void) close(q->file);
604 q->file=(-1);
605 }
cristyf84a1932010-01-03 18:00:18 +0000606 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000607}
608
609static inline MagickSizeType MagickMax(const MagickSizeType x,
610 const MagickSizeType y)
611{
612 if (x > y)
613 return(x);
614 return(y);
615}
616
617static inline MagickSizeType MagickMin(const MagickSizeType x,
618 const MagickSizeType y)
619{
620 if (x < y)
621 return(x);
622 return(y);
623}
624
625static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
626 const MapMode mode)
627{
628 int
629 file;
630
631 /*
632 Open pixel cache on disk.
633 */
cristyf84a1932010-01-03 18:00:18 +0000634 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000635 if (cache_info->file != -1)
636 {
cristyf84a1932010-01-03 18:00:18 +0000637 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000638 return(MagickTrue); /* cache already open */
639 }
640 LimitPixelCacheDescriptors();
641 if (*cache_info->cache_filename == '\0')
642 file=AcquireUniqueFileResource(cache_info->cache_filename);
643 else
644 switch (mode)
645 {
646 case ReadMode:
647 {
648 file=open(cache_info->cache_filename,O_RDONLY | O_BINARY);
649 break;
650 }
651 case WriteMode:
652 {
653 file=open(cache_info->cache_filename,O_WRONLY | O_CREAT | O_BINARY |
654 O_EXCL,S_MODE);
655 if (file == -1)
656 file=open(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
657 break;
658 }
659 case IOMode:
660 default:
661 {
662 file=open(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
663 O_EXCL,S_MODE);
664 if (file == -1)
665 file=open(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
666 break;
667 }
668 }
669 if (file == -1)
670 {
cristyf84a1932010-01-03 18:00:18 +0000671 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000672 return(MagickFalse);
673 }
674 (void) AcquireMagickResource(FileResource,1);
675 cache_info->file=file;
676 cache_info->timestamp=time(0);
cristyf84a1932010-01-03 18:00:18 +0000677 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000678 return(MagickTrue);
679}
680
681static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
682 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000683 unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000684{
685 register MagickOffsetType
686 i;
687
688 ssize_t
689 count;
690
cristy08a88202010-03-04 19:18:05 +0000691 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000692#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000693 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000694 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
695 {
cristyf84a1932010-01-03 18:00:18 +0000696 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000697 return((MagickOffsetType) -1);
698 }
699#endif
700 count=0;
701 for (i=0; i < (MagickOffsetType) length; i+=count)
702 {
703#if !defined(MAGICKCORE_HAVE_PREAD)
704 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
705 (MagickSizeType) SSIZE_MAX));
706#else
707 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
708 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
709#endif
710 if (count > 0)
711 continue;
712 count=0;
713 if (errno != EINTR)
714 {
715 i=(-1);
716 break;
717 }
718 }
719#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000720 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000721#endif
722 return(i);
723}
724
725static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
726 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000727 const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000728{
729 register MagickOffsetType
730 i;
731
732 ssize_t
733 count;
734
cristy08a88202010-03-04 19:18:05 +0000735 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000736#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000737 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000738 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
739 {
cristyf84a1932010-01-03 18:00:18 +0000740 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000741 return((MagickOffsetType) -1);
742 }
743#endif
744 count=0;
745 for (i=0; i < (MagickOffsetType) length; i+=count)
746 {
747#if !defined(MAGICKCORE_HAVE_PWRITE)
748 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
749 (MagickSizeType) SSIZE_MAX));
750#else
751 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
752 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
753#endif
754 if (count > 0)
755 continue;
756 count=0;
757 if (errno != EINTR)
758 {
759 i=(-1);
760 break;
761 }
762 }
763#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000764 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000765#endif
766 return(i);
767}
768
769static MagickBooleanType CloneDiskToDiskPixelCache(CacheInfo *clone_info,
770 CacheInfo *cache_info,ExceptionInfo *exception)
771{
772 MagickOffsetType
773 count,
774 offset,
775 source_offset;
776
777 MagickSizeType
778 length;
779
cristy3ed852e2009-09-05 21:47:34 +0000780 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000781 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +0000782
cristye076a6e2010-08-15 19:59:43 +0000783 register ssize_t
784 y;
785
cristybb503372010-05-27 20:51:26 +0000786 size_t
cristy3ed852e2009-09-05 21:47:34 +0000787 columns,
788 rows;
789
790 if (cache_info->debug != MagickFalse)
791 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
792 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
793 {
794 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
795 clone_info->cache_filename);
796 return(MagickFalse);
797 }
798 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
799 {
800 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
801 cache_info->cache_filename);
802 return(MagickFalse);
803 }
cristybb503372010-05-27 20:51:26 +0000804 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
805 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +0000806 if ((clone_info->active_index_channel != MagickFalse) &&
807 (cache_info->active_index_channel != MagickFalse))
808 {
809 register IndexPacket
810 *indexes;
811
812 /*
813 Clone cache indexes.
814 */
815 length=MagickMax(clone_info->columns,cache_info->columns)*
816 sizeof(*indexes);
817 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
818 if (indexes == (IndexPacket *) NULL)
819 {
820 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
821 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
822 return(MagickFalse);
823 }
824 (void) ResetMagickMemory(indexes,0,(size_t) length);
825 length=columns*sizeof(*indexes);
826 source_offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
827 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
828 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
829 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +0000830 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000831 {
832 source_offset-=cache_info->columns*sizeof(*indexes);
833 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
834 length,(unsigned char *) indexes);
835 if ((MagickSizeType) count != length)
836 break;
837 offset-=clone_info->columns*sizeof(*indexes);
838 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
839 (unsigned char *) indexes);
840 if ((MagickSizeType) count != length)
841 break;
842 }
cristybb503372010-05-27 20:51:26 +0000843 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000844 {
845 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
846 ThrowFileException(exception,CacheError,"UnableToCloneCache",
847 cache_info->cache_filename);
848 return(MagickFalse);
849 }
850 if (clone_info->columns > cache_info->columns)
851 {
852 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
853 (void) ResetMagickMemory(indexes,0,(size_t) length);
854 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
855 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +0000856 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000857 {
858 offset-=clone_info->columns*sizeof(*indexes);
859 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
860 length,(unsigned char *) indexes);
861 if ((MagickSizeType) count != length)
862 break;
863 }
cristybb503372010-05-27 20:51:26 +0000864 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000865 {
866 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
867 ThrowFileException(exception,CacheError,"UnableToCloneCache",
868 cache_info->cache_filename);
869 return(MagickFalse);
870 }
871 }
872 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
873 }
874 /*
875 Clone cache pixels.
876 */
877 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
878 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
879 if (pixels == (PixelPacket *) NULL)
880 {
881 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
882 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
883 return(MagickFalse);
884 }
885 (void) ResetMagickMemory(pixels,0,(size_t) length);
886 length=columns*sizeof(*pixels);
887 source_offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
888 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +0000889 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000890 {
891 source_offset-=cache_info->columns*sizeof(*pixels);
892 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
893 length,(unsigned char *) pixels);
894 if ((MagickSizeType) count != length)
895 break;
896 offset-=clone_info->columns*sizeof(*pixels);
897 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
898 (unsigned char *) pixels);
899 if ((MagickSizeType) count != length)
900 break;
901 }
cristybb503372010-05-27 20:51:26 +0000902 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000903 {
904 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
905 ThrowFileException(exception,CacheError,"UnableToCloneCache",
906 cache_info->cache_filename);
907 return(MagickFalse);
908 }
909 if (clone_info->columns > cache_info->columns)
910 {
911 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
912 sizeof(*pixels);
913 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
914 (void) ResetMagickMemory(pixels,0,(size_t) length);
cristybb503372010-05-27 20:51:26 +0000915 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000916 {
917 offset-=clone_info->columns*sizeof(*pixels);
918 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
919 (unsigned char *) pixels);
920 if ((MagickSizeType) count != length)
921 break;
922 }
cristybb503372010-05-27 20:51:26 +0000923 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000924 {
925 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
926 ThrowFileException(exception,CacheError,"UnableToCloneCache",
927 cache_info->cache_filename);
928 return(MagickFalse);
929 }
930 }
931 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
932 return(MagickTrue);
933}
934
935static MagickBooleanType CloneDiskToMemoryPixelCache(CacheInfo *clone_info,
936 CacheInfo *cache_info,ExceptionInfo *exception)
937{
938 MagickOffsetType
939 count,
940 offset;
941
942 MagickSizeType
943 length;
944
cristy3ed852e2009-09-05 21:47:34 +0000945 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000946 *restrict pixels,
947 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000948
cristye076a6e2010-08-15 19:59:43 +0000949 register ssize_t
950 y;
951
cristybb503372010-05-27 20:51:26 +0000952 size_t
cristy3ed852e2009-09-05 21:47:34 +0000953 columns,
954 rows;
955
956 if (cache_info->debug != MagickFalse)
957 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
958 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
959 {
960 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
961 cache_info->cache_filename);
962 return(MagickFalse);
963 }
cristybb503372010-05-27 20:51:26 +0000964 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
965 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +0000966 if ((clone_info->active_index_channel != MagickFalse) &&
967 (cache_info->active_index_channel != MagickFalse))
968 {
969 register IndexPacket
970 *indexes,
971 *q;
972
973 /*
974 Clone cache indexes.
975 */
976 length=MagickMax(clone_info->columns,cache_info->columns)*
977 sizeof(*indexes);
978 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
979 if (indexes == (IndexPacket *) NULL)
980 {
981 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
982 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
983 return(MagickFalse);
984 }
985 (void) ResetMagickMemory(indexes,0,(size_t) length);
986 length=columns*sizeof(IndexPacket);
987 offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
988 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
989 q=clone_info->indexes+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +0000990 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000991 {
992 offset-=cache_info->columns*sizeof(IndexPacket);
993 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,
994 length,(unsigned char *) indexes);
995 if ((MagickSizeType) count != length)
996 break;
997 q-=clone_info->columns;
998 (void) CopyMagickMemory(q,indexes,(size_t) length);
999 if ((MagickSizeType) count != length)
1000 break;
1001 }
cristybb503372010-05-27 20:51:26 +00001002 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001003 {
1004 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1005 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1006 cache_info->cache_filename);
1007 return(MagickFalse);
1008 }
1009 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1010 }
1011 /*
1012 Clone cache pixels.
1013 */
1014 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1015 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1016 if (pixels == (PixelPacket *) NULL)
1017 {
1018 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1019 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1020 return(MagickFalse);
1021 }
1022 (void) ResetMagickMemory(pixels,0,(size_t) length);
1023 length=columns*sizeof(*pixels);
1024 offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
1025 q=clone_info->pixels+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001026 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001027 {
1028 offset-=cache_info->columns*sizeof(*pixels);
1029 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,length,
1030 (unsigned char *) pixels);
1031 if ((MagickSizeType) count != length)
1032 break;
1033 q-=clone_info->columns;
1034 (void) CopyMagickMemory(q,pixels,(size_t) length);
1035 }
cristybb503372010-05-27 20:51:26 +00001036 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001037 {
1038 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1039 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1040 cache_info->cache_filename);
1041 return(MagickFalse);
1042 }
1043 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1044 return(MagickTrue);
1045}
1046
1047static MagickBooleanType CloneMemoryToDiskPixelCache(CacheInfo *clone_info,
1048 CacheInfo *cache_info,ExceptionInfo *exception)
1049{
1050 MagickOffsetType
1051 count,
1052 offset;
1053
1054 MagickSizeType
1055 length;
1056
cristy3ed852e2009-09-05 21:47:34 +00001057 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001058 *restrict p,
1059 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +00001060
cristye076a6e2010-08-15 19:59:43 +00001061 register ssize_t
1062 y;
1063
cristybb503372010-05-27 20:51:26 +00001064 size_t
cristy3ed852e2009-09-05 21:47:34 +00001065 columns,
1066 rows;
1067
1068 if (cache_info->debug != MagickFalse)
1069 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
1070 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
1071 {
1072 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1073 clone_info->cache_filename);
1074 return(MagickFalse);
1075 }
cristybb503372010-05-27 20:51:26 +00001076 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1077 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001078 if ((clone_info->active_index_channel != MagickFalse) &&
1079 (cache_info->active_index_channel != MagickFalse))
1080 {
1081 register IndexPacket
1082 *p,
1083 *indexes;
1084
1085 /*
1086 Clone cache indexes.
1087 */
1088 length=MagickMax(clone_info->columns,cache_info->columns)*
1089 sizeof(*indexes);
1090 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
1091 if (indexes == (IndexPacket *) NULL)
1092 {
1093 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1094 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1095 return(MagickFalse);
1096 }
1097 (void) ResetMagickMemory(indexes,0,(size_t) length);
1098 length=columns*sizeof(*indexes);
1099 p=cache_info->indexes+cache_info->columns*rows;
1100 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1101 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +00001102 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001103 {
1104 p-=cache_info->columns;
1105 (void) CopyMagickMemory(indexes,p,(size_t) length);
1106 offset-=clone_info->columns*sizeof(*indexes);
1107 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1108 (unsigned char *) indexes);
1109 if ((MagickSizeType) count != length)
1110 break;
1111 }
cristybb503372010-05-27 20:51:26 +00001112 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001113 {
1114 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1115 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1116 cache_info->cache_filename);
1117 return(MagickFalse);
1118 }
1119 if (clone_info->columns > cache_info->columns)
1120 {
1121 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
1122 (void) ResetMagickMemory(indexes,0,(size_t) length);
1123 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1124 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +00001125 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001126 {
1127 offset-=clone_info->columns*sizeof(*indexes);
1128 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
1129 length,(unsigned char *) indexes);
1130 if ((MagickSizeType) count != length)
1131 break;
1132 }
cristybb503372010-05-27 20:51:26 +00001133 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001134 {
1135 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1136 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1137 cache_info->cache_filename);
1138 return(MagickFalse);
1139 }
1140 }
1141 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1142 }
1143 /*
1144 Clone cache pixels.
1145 */
1146 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1147 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1148 if (pixels == (PixelPacket *) NULL)
1149 {
1150 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1151 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1152 return(MagickFalse);
1153 }
1154 (void) ResetMagickMemory(pixels,0,(size_t) length);
1155 length=columns*sizeof(*pixels);
1156 p=cache_info->pixels+cache_info->columns*rows;
1157 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +00001158 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001159 {
1160 p-=cache_info->columns;
1161 (void) CopyMagickMemory(pixels,p,(size_t) length);
1162 offset-=clone_info->columns*sizeof(*pixels);
1163 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1164 (unsigned char *) pixels);
1165 if ((MagickSizeType) count != length)
1166 break;
1167 }
cristybb503372010-05-27 20:51:26 +00001168 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001169 {
1170 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1171 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1172 cache_info->cache_filename);
1173 return(MagickFalse);
1174 }
1175 if (clone_info->columns > cache_info->columns)
1176 {
1177 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
1178 sizeof(*pixels);
1179 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1180 (void) ResetMagickMemory(pixels,0,(size_t) length);
cristybb503372010-05-27 20:51:26 +00001181 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001182 {
1183 offset-=clone_info->columns*sizeof(*pixels);
1184 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1185 (unsigned char *) pixels);
1186 if ((MagickSizeType) count != length)
1187 break;
1188 }
cristybb503372010-05-27 20:51:26 +00001189 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001190 {
1191 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1192 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1193 cache_info->cache_filename);
1194 return(MagickFalse);
1195 }
1196 }
1197 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1198 return(MagickTrue);
1199}
1200
1201static MagickBooleanType CloneMemoryToMemoryPixelCache(CacheInfo *clone_info,
1202 CacheInfo *cache_info,ExceptionInfo *magick_unused(exception))
1203{
cristy3ed852e2009-09-05 21:47:34 +00001204 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001205 *restrict pixels,
1206 *restrict source_pixels;
cristy3ed852e2009-09-05 21:47:34 +00001207
cristye076a6e2010-08-15 19:59:43 +00001208 register ssize_t
1209 y;
cristy3ed852e2009-09-05 21:47:34 +00001210
cristybb503372010-05-27 20:51:26 +00001211 size_t
cristy3ed852e2009-09-05 21:47:34 +00001212 columns,
cristye076a6e2010-08-15 19:59:43 +00001213 length,
cristy3ed852e2009-09-05 21:47:34 +00001214 rows;
1215
1216 if (cache_info->debug != MagickFalse)
1217 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
cristybb503372010-05-27 20:51:26 +00001218 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1219 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001220 if ((clone_info->active_index_channel != MagickFalse) &&
1221 (cache_info->active_index_channel != MagickFalse))
1222 {
1223 register IndexPacket
1224 *indexes,
1225 *source_indexes;
1226
1227 /*
1228 Clone cache indexes.
1229 */
1230 length=columns*sizeof(*indexes);
1231 if (clone_info->columns == cache_info->columns)
1232 (void) CopyMagickMemory(clone_info->indexes,cache_info->indexes,
1233 length*rows);
1234 else
1235 {
1236 source_indexes=cache_info->indexes+cache_info->columns*rows;
1237 indexes=clone_info->indexes+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001238 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001239 {
1240 source_indexes-=cache_info->columns;
1241 indexes-=clone_info->columns;
1242 (void) CopyMagickMemory(indexes,source_indexes,length);
1243 }
1244 if (clone_info->columns > cache_info->columns)
1245 {
1246 length=(clone_info->columns-cache_info->columns)*
1247 sizeof(*indexes);
1248 indexes=clone_info->indexes+clone_info->columns*rows+
1249 cache_info->columns;
cristybb503372010-05-27 20:51:26 +00001250 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001251 {
1252 indexes-=clone_info->columns;
1253 (void) ResetMagickMemory(indexes,0,length);
1254 }
1255 }
1256 }
1257 }
1258 /*
1259 Clone cache pixels.
1260 */
1261 length=columns*sizeof(*pixels);
1262 if (clone_info->columns == cache_info->columns)
1263 (void) CopyMagickMemory(clone_info->pixels,cache_info->pixels,length*rows);
1264 else
1265 {
1266 source_pixels=cache_info->pixels+cache_info->columns*rows;
1267 pixels=clone_info->pixels+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001268 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001269 {
1270 source_pixels-=cache_info->columns;
1271 pixels-=clone_info->columns;
1272 (void) CopyMagickMemory(pixels,source_pixels,length);
1273 }
1274 if (clone_info->columns > cache_info->columns)
1275 {
1276 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1277 pixels=clone_info->pixels+clone_info->columns*rows+
1278 cache_info->columns;
cristybb503372010-05-27 20:51:26 +00001279 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001280 {
1281 pixels-=clone_info->columns;
1282 (void) ResetMagickMemory(pixels,0,length);
1283 }
1284 }
1285 }
1286 return(MagickTrue);
1287}
1288
1289static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1290 CacheInfo *cache_info,ExceptionInfo *exception)
1291{
1292 if ((clone_info->type != DiskCache) && (cache_info->type != DiskCache))
1293 return(CloneMemoryToMemoryPixelCache(clone_info,cache_info,exception));
1294 if ((clone_info->type == DiskCache) && (cache_info->type == DiskCache))
1295 return(CloneDiskToDiskPixelCache(clone_info,cache_info,exception));
1296 if (cache_info->type == DiskCache)
1297 return(CloneDiskToMemoryPixelCache(clone_info,cache_info,exception));
1298 return(CloneMemoryToDiskPixelCache(clone_info,cache_info,exception));
1299}
1300
1301/*
1302%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1303% %
1304% %
1305% %
1306+ C l o n e P i x e l C a c h e M e t h o d s %
1307% %
1308% %
1309% %
1310%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1311%
1312% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1313% another.
1314%
1315% The format of the ClonePixelCacheMethods() method is:
1316%
1317% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1318%
1319% A description of each parameter follows:
1320%
1321% o clone: Specifies a pointer to a Cache structure.
1322%
1323% o cache: the pixel cache.
1324%
1325*/
1326MagickExport void ClonePixelCacheMethods(Cache clone,const Cache cache)
1327{
1328 CacheInfo
1329 *cache_info,
1330 *source_info;
1331
1332 assert(clone != (Cache) NULL);
1333 source_info=(CacheInfo *) clone;
1334 assert(source_info->signature == MagickSignature);
1335 if (source_info->debug != MagickFalse)
1336 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1337 source_info->filename);
1338 assert(cache != (Cache) NULL);
1339 cache_info=(CacheInfo *) cache;
1340 assert(cache_info->signature == MagickSignature);
1341 source_info->methods=cache_info->methods;
1342}
1343
1344/*
1345%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1346% %
1347% %
1348% %
1349+ D e s t r o y I m a g e P i x e l C a c h e %
1350% %
1351% %
1352% %
1353%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1354%
1355% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1356%
1357% The format of the DestroyImagePixelCache() method is:
1358%
1359% void DestroyImagePixelCache(Image *image)
1360%
1361% A description of each parameter follows:
1362%
1363% o image: the image.
1364%
1365*/
1366static void DestroyImagePixelCache(Image *image)
1367{
1368 assert(image != (Image *) NULL);
1369 assert(image->signature == MagickSignature);
1370 if (image->debug != MagickFalse)
1371 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1372 if (image->cache == (void *) NULL)
1373 return;
1374 image->cache=DestroyPixelCache(image->cache);
1375}
1376
1377/*
1378%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1379% %
1380% %
1381% %
1382+ D e s t r o y I m a g e P i x e l s %
1383% %
1384% %
1385% %
1386%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1387%
1388% DestroyImagePixels() deallocates memory associated with the pixel cache.
1389%
1390% The format of the DestroyImagePixels() method is:
1391%
1392% void DestroyImagePixels(Image *image)
1393%
1394% A description of each parameter follows:
1395%
1396% o image: the image.
1397%
1398*/
1399MagickExport void DestroyImagePixels(Image *image)
1400{
1401 CacheInfo
1402 *cache_info;
1403
1404 assert(image != (const Image *) NULL);
1405 assert(image->signature == MagickSignature);
1406 if (image->debug != MagickFalse)
1407 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1408 assert(image->cache != (Cache) NULL);
1409 cache_info=(CacheInfo *) image->cache;
1410 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001411 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1412 {
1413 cache_info->methods.destroy_pixel_handler(image);
1414 return;
1415 }
1416 DestroyImagePixelCache(image);
cristy3ed852e2009-09-05 21:47:34 +00001417}
1418
1419/*
1420%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1421% %
1422% %
1423% %
1424+ D e s t r o y P i x e l C a c h e %
1425% %
1426% %
1427% %
1428%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1429%
1430% DestroyPixelCache() deallocates memory associated with the pixel cache.
1431%
1432% The format of the DestroyPixelCache() method is:
1433%
1434% Cache DestroyPixelCache(Cache cache)
1435%
1436% A description of each parameter follows:
1437%
1438% o cache: the pixel cache.
1439%
1440*/
1441
1442static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1443{
1444 switch (cache_info->type)
1445 {
1446 case MemoryCache:
1447 {
1448 if (cache_info->mapped == MagickFalse)
1449 cache_info->pixels=(PixelPacket *) RelinquishMagickMemory(
1450 cache_info->pixels);
1451 else
1452 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,
1453 (size_t) cache_info->length);
1454 RelinquishMagickResource(MemoryResource,cache_info->length);
1455 break;
1456 }
1457 case MapCache:
1458 {
1459 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,(size_t)
1460 cache_info->length);
1461 RelinquishMagickResource(MapResource,cache_info->length);
1462 }
1463 case DiskCache:
1464 {
1465 if (cache_info->file != -1)
1466 (void) ClosePixelCacheOnDisk(cache_info);
1467 RelinquishMagickResource(DiskResource,cache_info->length);
1468 break;
1469 }
1470 default:
1471 break;
1472 }
1473 cache_info->type=UndefinedCache;
1474 cache_info->mapped=MagickFalse;
1475 cache_info->indexes=(IndexPacket *) NULL;
1476}
1477
1478MagickExport Cache DestroyPixelCache(Cache cache)
1479{
1480 CacheInfo
1481 *cache_info;
1482
cristy3ed852e2009-09-05 21:47:34 +00001483 assert(cache != (Cache) NULL);
1484 cache_info=(CacheInfo *) cache;
1485 assert(cache_info->signature == MagickSignature);
1486 if (cache_info->debug != MagickFalse)
1487 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1488 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001489 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001490 cache_info->reference_count--;
1491 if (cache_info->reference_count != 0)
1492 {
cristyf84a1932010-01-03 18:00:18 +00001493 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001494 return((Cache) NULL);
1495 }
cristyf84a1932010-01-03 18:00:18 +00001496 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001497 if (cache_resources != (SplayTreeInfo *) NULL)
1498 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
cristy5b8de732009-09-10 23:50:40 +00001499 if (cache_info->debug != MagickFalse)
1500 {
1501 char
1502 message[MaxTextExtent];
1503
1504 (void) FormatMagickString(message,MaxTextExtent,"destroy %s",
1505 cache_info->filename);
1506 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1507 }
cristyc2e1bdd2009-09-10 23:43:34 +00001508 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1509 (cache_info->type != DiskCache)))
1510 RelinquishPixelCachePixels(cache_info);
1511 else
1512 {
1513 RelinquishPixelCachePixels(cache_info);
1514 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1515 }
cristy3ed852e2009-09-05 21:47:34 +00001516 *cache_info->cache_filename='\0';
1517 if (cache_info->nexus_info != (NexusInfo **) NULL)
1518 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1519 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001520 if (cache_info->random_info != (RandomInfo *) NULL)
1521 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001522 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1523 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1524 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1525 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001526 cache_info->signature=(~MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001527 cache_info=(CacheInfo *) RelinquishAlignedMemory(cache_info);
1528 cache=(Cache) NULL;
1529 return(cache);
1530}
1531
1532/*
1533%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1534% %
1535% %
1536% %
1537+ D e s t r o y P i x e l C a c h e N e x u s %
1538% %
1539% %
1540% %
1541%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1542%
1543% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1544%
1545% The format of the DestroyPixelCacheNexus() method is:
1546%
1547% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001548% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001549%
1550% A description of each parameter follows:
1551%
1552% o nexus_info: the nexus to destroy.
1553%
1554% o number_threads: the number of nexus threads.
1555%
1556*/
1557
1558static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1559{
1560 if (nexus_info->mapped == MagickFalse)
1561 (void) RelinquishMagickMemory(nexus_info->cache);
1562 else
1563 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1564 nexus_info->cache=(PixelPacket *) NULL;
1565 nexus_info->pixels=(PixelPacket *) NULL;
1566 nexus_info->indexes=(IndexPacket *) NULL;
1567 nexus_info->length=0;
1568 nexus_info->mapped=MagickFalse;
1569}
1570
1571MagickExport NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001572 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001573{
cristybb503372010-05-27 20:51:26 +00001574 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001575 i;
1576
1577 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001578 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001579 {
1580 if (nexus_info[i]->cache != (PixelPacket *) NULL)
1581 RelinquishCacheNexusPixels(nexus_info[i]);
1582 nexus_info[i]->signature=(~MagickSignature);
1583 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
1584 }
1585 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
1586 return(nexus_info);
1587}
1588
1589/*
1590%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1591% %
1592% %
1593% %
cristy3ed852e2009-09-05 21:47:34 +00001594+ 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 %
1595% %
1596% %
1597% %
1598%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1599%
1600% GetAuthenticIndexesFromCache() returns the indexes associated with the last
1601% call to QueueAuthenticPixelsCache() or GetAuthenticPixelsCache().
1602%
1603% The format of the GetAuthenticIndexesFromCache() method is:
1604%
1605% IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1606%
1607% A description of each parameter follows:
1608%
1609% o image: the image.
1610%
1611*/
1612static IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1613{
1614 CacheInfo
1615 *cache_info;
1616
cristy5c9e6f22010-09-17 17:31:01 +00001617 const int
1618 id = GetOpenMPThreadId();
1619
cristy3ed852e2009-09-05 21:47:34 +00001620 cache_info=(CacheInfo *) image->cache;
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
1655 assert(image != (const Image *) NULL);
1656 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001657 assert(image->cache != (Cache) NULL);
1658 cache_info=(CacheInfo *) image->cache;
1659 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001660 if (cache_info->methods.get_authentic_indexes_from_handler !=
cristy3ed852e2009-09-05 21:47:34 +00001661 (GetAuthenticIndexesFromHandler) NULL)
cristyd317f372010-09-18 01:42:20 +00001662 return(cache_info->methods.get_authentic_indexes_from_handler(image));
1663 return(GetAuthenticIndexesFromCache(image));
cristy3ed852e2009-09-05 21:47:34 +00001664}
1665
1666/*
1667%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1668% %
1669% %
1670% %
1671+ 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 %
1672% %
1673% %
1674% %
1675%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1676%
1677% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1678% disk pixel cache as defined by the geometry parameters. A pointer to the
1679% pixels is returned if the pixels are transferred, otherwise a NULL is
1680% returned.
1681%
1682% The format of the GetAuthenticPixelCacheNexus() method is:
1683%
cristybb503372010-05-27 20:51:26 +00001684% PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1685% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001686% NexusInfo *nexus_info,ExceptionInfo *exception)
1687%
1688% A description of each parameter follows:
1689%
1690% o image: the image.
1691%
1692% o x,y,columns,rows: These values define the perimeter of a region of
1693% pixels.
1694%
1695% o nexus_info: the cache nexus to return.
1696%
1697% o exception: return any errors or warnings in this structure.
1698%
1699*/
1700
1701static inline MagickBooleanType IsNexusInCore(const CacheInfo *cache_info,
1702 NexusInfo *nexus_info)
1703{
1704 MagickOffsetType
1705 offset;
1706
cristy73724512010-04-12 14:43:14 +00001707 if (cache_info->type == PingCache)
1708 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001709 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1710 nexus_info->region.x;
1711 if (nexus_info->pixels != (cache_info->pixels+offset))
1712 return(MagickFalse);
1713 return(MagickTrue);
1714}
1715
cristye076a6e2010-08-15 19:59:43 +00001716MagickExport PixelPacket *GetAuthenticPixelCacheNexus(Image *image,
1717 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001718 NexusInfo *nexus_info,ExceptionInfo *exception)
1719{
1720 CacheInfo
1721 *cache_info;
1722
1723 PixelPacket
1724 *pixels;
1725
1726 /*
1727 Transfer pixels from the cache.
1728 */
1729 assert(image != (Image *) NULL);
1730 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001731 pixels=QueueAuthenticNexus(image,x,y,columns,rows,nexus_info,exception);
1732 if (pixels == (PixelPacket *) NULL)
1733 return((PixelPacket *) NULL);
1734 cache_info=(CacheInfo *) image->cache;
1735 assert(cache_info->signature == MagickSignature);
1736 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
1737 return(pixels);
1738 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1739 return((PixelPacket *) NULL);
1740 if (cache_info->active_index_channel != MagickFalse)
1741 if (ReadPixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse)
1742 return((PixelPacket *) NULL);
1743 return(pixels);
1744}
1745
1746/*
1747%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1748% %
1749% %
1750% %
1751+ 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 %
1752% %
1753% %
1754% %
1755%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1756%
1757% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1758% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1759%
1760% The format of the GetAuthenticPixelsFromCache() method is:
1761%
1762% PixelPacket *GetAuthenticPixelsFromCache(const Image image)
1763%
1764% A description of each parameter follows:
1765%
1766% o image: the image.
1767%
1768*/
1769static PixelPacket *GetAuthenticPixelsFromCache(const Image *image)
1770{
1771 CacheInfo
1772 *cache_info;
1773
cristy5c9e6f22010-09-17 17:31:01 +00001774 const int
1775 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001776
cristy3ed852e2009-09-05 21:47:34 +00001777 cache_info=(CacheInfo *) image->cache;
cristy6ebe97c2010-07-03 01:17:28 +00001778 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001779 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001780}
1781
1782/*
1783%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1784% %
1785% %
1786% %
1787% G e t A u t h e n t i c P i x e l Q u e u e %
1788% %
1789% %
1790% %
1791%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1792%
1793% GetAuthenticPixelQueue() returns the authentic pixels associated with the
1794% last call to QueueAuthenticPixels() or GetAuthenticPixels().
1795%
1796% The format of the GetAuthenticPixelQueue() method is:
1797%
1798% PixelPacket *GetAuthenticPixelQueue(const Image image)
1799%
1800% A description of each parameter follows:
1801%
1802% o image: the image.
1803%
1804*/
1805MagickExport PixelPacket *GetAuthenticPixelQueue(const Image *image)
1806{
1807 CacheInfo
1808 *cache_info;
1809
1810 assert(image != (const Image *) NULL);
1811 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001812 assert(image->cache != (Cache) NULL);
1813 cache_info=(CacheInfo *) image->cache;
1814 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001815 if (cache_info->methods.get_authentic_pixels_from_handler !=
1816 (GetAuthenticPixelsFromHandler) NULL)
1817 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1818 return(GetAuthenticPixelsFromCache(image));
cristy3ed852e2009-09-05 21:47:34 +00001819}
1820
1821/*
1822%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1823% %
1824% %
1825% %
1826% G e t A u t h e n t i c P i x e l s %
1827% %
1828% %
1829% %
1830%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1831%
1832% GetAuthenticPixels() obtains a pixel region for read/write access. If the
1833% region is successfully accessed, a pointer to a PixelPacket array
1834% representing the region is returned, otherwise NULL is returned.
1835%
1836% The returned pointer may point to a temporary working copy of the pixels
1837% or it may point to the original pixels in memory. Performance is maximized
1838% if the selected region is part of one row, or one or more full rows, since
1839% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001840% if the image is in memory, or in a memory-mapped file. The returned pointer
1841% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001842%
1843% Pixels accessed via the returned pointer represent a simple array of type
1844% PixelPacket. If the image type is CMYK or if the storage class is
1845% PseduoClass, call GetAuthenticIndexQueue() after invoking
1846% GetAuthenticPixels() to obtain the black color component or colormap indexes
1847% (of type IndexPacket) corresponding to the region. Once the PixelPacket
1848% (and/or IndexPacket) array has been updated, the changes must be saved back
1849% to the underlying image using SyncAuthenticPixels() or they may be lost.
1850%
1851% The format of the GetAuthenticPixels() method is:
1852%
cristy5f959472010-05-27 22:19:46 +00001853% PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1854% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001855% ExceptionInfo *exception)
1856%
1857% A description of each parameter follows:
1858%
1859% o image: the image.
1860%
1861% o x,y,columns,rows: These values define the perimeter of a region of
1862% pixels.
1863%
1864% o exception: return any errors or warnings in this structure.
1865%
1866*/
cristybb503372010-05-27 20:51:26 +00001867MagickExport PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1868 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001869 ExceptionInfo *exception)
1870{
1871 CacheInfo
1872 *cache_info;
1873
cristy3ed852e2009-09-05 21:47:34 +00001874 assert(image != (Image *) NULL);
1875 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001876 assert(image->cache != (Cache) NULL);
1877 cache_info=(CacheInfo *) image->cache;
1878 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001879 if (cache_info->methods.get_authentic_pixels_handler !=
1880 (GetAuthenticPixelsHandler) NULL)
1881 return(cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1882 rows,exception));
1883 return(GetAuthenticPixelsCache(image,x,y,columns,rows,exception));
cristy3ed852e2009-09-05 21:47:34 +00001884}
1885
1886/*
1887%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1888% %
1889% %
1890% %
1891+ G e t A u t h e n t i c P i x e l s C a c h e %
1892% %
1893% %
1894% %
1895%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1896%
1897% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1898% as defined by the geometry parameters. A pointer to the pixels is returned
1899% if the pixels are transferred, otherwise a NULL is returned.
1900%
1901% The format of the GetAuthenticPixelsCache() method is:
1902%
cristybb503372010-05-27 20:51:26 +00001903% PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1904% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001905% ExceptionInfo *exception)
1906%
1907% A description of each parameter follows:
1908%
1909% o image: the image.
1910%
1911% o x,y,columns,rows: These values define the perimeter of a region of
1912% pixels.
1913%
1914% o exception: return any errors or warnings in this structure.
1915%
1916*/
cristybb503372010-05-27 20:51:26 +00001917static PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1918 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001919 ExceptionInfo *exception)
1920{
1921 CacheInfo
1922 *cache_info;
1923
cristy5c9e6f22010-09-17 17:31:01 +00001924 const int
1925 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001926
cristy77ff0282010-09-13 00:51:10 +00001927 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001928 if (cache_info == (Cache) NULL)
1929 return((PixelPacket *) NULL);
cristy6ebe97c2010-07-03 01:17:28 +00001930 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001931 return(GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1932 cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00001933}
1934
1935/*
1936%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1937% %
1938% %
1939% %
1940+ G e t I m a g e E x t e n t %
1941% %
1942% %
1943% %
1944%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1945%
1946% GetImageExtent() returns the extent of the pixels associated with the
1947% last call to QueueAuthenticPixels() or GetAuthenticPixels().
1948%
1949% The format of the GetImageExtent() method is:
1950%
1951% MagickSizeType GetImageExtent(const Image *image)
1952%
1953% A description of each parameter follows:
1954%
1955% o image: the image.
1956%
1957*/
1958MagickExport MagickSizeType GetImageExtent(const Image *image)
1959{
1960 CacheInfo
1961 *cache_info;
1962
cristy5c9e6f22010-09-17 17:31:01 +00001963 const int
1964 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001965
cristy3ed852e2009-09-05 21:47:34 +00001966 assert(image != (Image *) NULL);
1967 assert(image->signature == MagickSignature);
1968 if (image->debug != MagickFalse)
1969 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1970 assert(image->cache != (Cache) NULL);
1971 cache_info=(CacheInfo *) image->cache;
1972 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001973 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001974 return(GetPixelCacheNexusExtent(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001975}
1976
1977/*
1978%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1979% %
1980% %
1981% %
1982+ G e t I m a g e P i x e l C a c h e %
1983% %
1984% %
1985% %
1986%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1987%
1988% GetImagePixelCache() ensures that there is only a single reference to the
1989% pixel cache to be modified, updating the provided cache pointer to point to
1990% a clone of the original pixel cache if necessary.
1991%
1992% The format of the GetImagePixelCache method is:
1993%
1994% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1995% ExceptionInfo *exception)
1996%
1997% A description of each parameter follows:
1998%
1999% o image: the image.
2000%
2001% o clone: any value other than MagickFalse clones the cache pixels.
2002%
2003% o exception: return any errors or warnings in this structure.
2004%
2005*/
cristy3ed852e2009-09-05 21:47:34 +00002006static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
2007{
2008 CacheInfo
2009 *cache_info;
2010
2011 /*
2012 Does the image match the pixel cache morphology?
2013 */
2014 cache_info=(CacheInfo *) image->cache;
2015 if ((image->storage_class != cache_info->storage_class) ||
2016 (image->colorspace != cache_info->colorspace) ||
2017 (image->columns != cache_info->columns) ||
2018 (image->rows != cache_info->rows) ||
2019 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2020 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2021 return(MagickFalse);
2022 return(MagickTrue);
2023}
2024
cristy77ff0282010-09-13 00:51:10 +00002025static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2026 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002027{
2028 CacheInfo
2029 *cache_info;
2030
cristy3ed852e2009-09-05 21:47:34 +00002031 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00002032 destroy,
cristy3ed852e2009-09-05 21:47:34 +00002033 status;
2034
cristy50a10922010-02-15 18:35:25 +00002035 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00002036 cpu_throttle = 0,
2037 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00002038 time_limit = 0;
2039
cristy1ea34962010-07-01 19:49:21 +00002040 static time_t
cristya21afde2010-07-02 00:45:40 +00002041 cache_genesis = 0;
cristy1ea34962010-07-01 19:49:21 +00002042
cristyc4f9f132010-03-04 18:50:01 +00002043 status=MagickTrue;
2044 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00002045 if (cpu_throttle == 0)
2046 {
2047 char
2048 *limit;
2049
2050 /*
2051 Set CPU throttle in milleseconds.
2052 */
2053 cpu_throttle=MagickResourceInfinity;
2054 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2055 if (limit == (char *) NULL)
2056 limit=GetPolicyValue("throttle");
2057 if (limit != (char *) NULL)
2058 {
2059 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2060 limit=DestroyString(limit);
2061 }
2062 }
2063 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2064 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00002065 if (time_limit == 0)
2066 {
cristy6ebe97c2010-07-03 01:17:28 +00002067 /*
2068 Set the exire time in seconds.
2069 */
cristy1ea34962010-07-01 19:49:21 +00002070 time_limit=GetMagickResourceLimit(TimeResource);
cristya21afde2010-07-02 00:45:40 +00002071 cache_genesis=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00002072 }
2073 if ((time_limit != MagickResourceInfinity) &&
cristya21afde2010-07-02 00:45:40 +00002074 ((MagickSizeType) (time((time_t *) NULL)-cache_genesis) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00002075 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00002076 assert(image->cache != (Cache) NULL);
2077 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002078 destroy=MagickFalse;
cristy01b7eb02009-09-10 23:10:14 +00002079 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002080 {
cristyaaa0cb62010-02-15 17:47:27 +00002081 LockSemaphoreInfo(cache_info->semaphore);
2082 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002083 {
cristyaaa0cb62010-02-15 17:47:27 +00002084 Image
2085 clone_image;
2086
2087 CacheInfo
2088 *clone_info;
2089
2090 /*
2091 Clone pixel cache.
2092 */
2093 clone_image=(*image);
cristy93505cf2010-08-10 21:37:49 +00002094 clone_image.semaphore=AllocateSemaphoreInfo();
2095 clone_image.reference_count=1;
cristyaaa0cb62010-02-15 17:47:27 +00002096 clone_image.cache=ClonePixelCache(cache_info);
2097 clone_info=(CacheInfo *) clone_image.cache;
cristyabd6e372010-09-15 19:11:26 +00002098 status=OpenPixelCache(&clone_image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00002099 if (status != MagickFalse)
2100 {
cristyabd6e372010-09-15 19:11:26 +00002101 if (clone != MagickFalse)
2102 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00002103 if (status != MagickFalse)
2104 {
cristyabd6e372010-09-15 19:11:26 +00002105 destroy=MagickTrue;
2106 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00002107 }
2108 }
cristy93505cf2010-08-10 21:37:49 +00002109 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002110 }
cristyaaa0cb62010-02-15 17:47:27 +00002111 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002112 }
cristy4320e0e2009-09-10 15:00:08 +00002113 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002114 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002115 if (status != MagickFalse)
2116 {
2117 /*
2118 Ensure the image matches the pixel cache morphology.
2119 */
2120 image->taint=MagickTrue;
2121 image->type=UndefinedType;
cristydd438462010-05-06 13:44:04 +00002122 if (image->colorspace == GRAYColorspace)
2123 image->colorspace=RGBColorspace;
cristy3ed852e2009-09-05 21:47:34 +00002124 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2125 status=OpenPixelCache(image,IOMode,exception);
2126 }
cristyf84a1932010-01-03 18:00:18 +00002127 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002128 if (status == MagickFalse)
2129 return((Cache) NULL);
2130 return(image->cache);
2131}
2132
2133/*
2134%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2135% %
2136% %
2137% %
2138% G e t O n e A u t h e n t i c P i x e l %
2139% %
2140% %
2141% %
2142%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2143%
2144% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2145% location. The image background color is returned if an error occurs.
2146%
2147% The format of the GetOneAuthenticPixel() method is:
2148%
cristybb503372010-05-27 20:51:26 +00002149% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2150% const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002151%
2152% A description of each parameter follows:
2153%
2154% o image: the image.
2155%
2156% o x,y: These values define the location of the pixel to return.
2157%
2158% o pixel: return a pixel at the specified (x,y) location.
2159%
2160% o exception: return any errors or warnings in this structure.
2161%
2162*/
cristyacbbb7c2010-06-30 18:56:48 +00002163MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2164 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002165{
2166 CacheInfo
2167 *cache_info;
2168
cristy3ed852e2009-09-05 21:47:34 +00002169 assert(image != (Image *) NULL);
2170 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002171 assert(image->cache != (Cache) NULL);
2172 cache_info=(CacheInfo *) image->cache;
2173 assert(cache_info->signature == MagickSignature);
2174 *pixel=image->background_color;
cristyd317f372010-09-18 01:42:20 +00002175 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2176 (GetOneAuthenticPixelFromHandler) NULL)
2177 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2178 pixel,exception));
2179 return(GetOneAuthenticPixelFromCache(image,x,y,pixel,exception));
cristy3ed852e2009-09-05 21:47:34 +00002180}
2181
2182/*
2183%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2184% %
2185% %
2186% %
2187+ 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 %
2188% %
2189% %
2190% %
2191%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2192%
2193% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2194% location. The image background color is returned if an error occurs.
2195%
2196% The format of the GetOneAuthenticPixelFromCache() method is:
2197%
2198% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy5f959472010-05-27 22:19:46 +00002199% const ssize_t x,const ssize_t y,PixelPacket *pixel,
2200% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002201%
2202% A description of each parameter follows:
2203%
2204% o image: the image.
2205%
2206% o x,y: These values define the location of the pixel to return.
2207%
2208% o pixel: return a pixel at the specified (x,y) location.
2209%
2210% o exception: return any errors or warnings in this structure.
2211%
2212*/
2213static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristybb503372010-05-27 20:51:26 +00002214 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002215{
2216 PixelPacket
2217 *pixels;
2218
cristy3ed852e2009-09-05 21:47:34 +00002219 *pixel=image->background_color;
2220 pixels=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2221 if (pixels == (PixelPacket *) NULL)
2222 return(MagickFalse);
2223 *pixel=(*pixels);
2224 return(MagickTrue);
2225}
2226
2227/*
2228%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2229% %
2230% %
2231% %
2232% G e t O n e V i r t u a l M a g i c k P i x e l %
2233% %
2234% %
2235% %
2236%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2237%
2238% GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2239% location. The image background color is returned if an error occurs. If
2240% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2241%
2242% The format of the GetOneVirtualMagickPixel() method is:
2243%
2244% MagickBooleanType GetOneVirtualMagickPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002245% const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
cristy3ed852e2009-09-05 21:47:34 +00002246% ExceptionInfo exception)
2247%
2248% A description of each parameter follows:
2249%
2250% o image: the image.
2251%
2252% o x,y: these values define the location of the pixel to return.
2253%
2254% o pixel: return a pixel at the specified (x,y) location.
2255%
2256% o exception: return any errors or warnings in this structure.
2257%
2258*/
2259MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
cristyacbbb7c2010-06-30 18:56:48 +00002260 const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
2261 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002262{
2263 CacheInfo
2264 *cache_info;
2265
2266 register const IndexPacket
2267 *indexes;
2268
2269 register const PixelPacket
2270 *p;
2271
2272 assert(image != (const Image *) NULL);
2273 assert(image->signature == MagickSignature);
2274 assert(image->cache != (Cache) NULL);
2275 cache_info=(CacheInfo *) image->cache;
2276 assert(cache_info->signature == MagickSignature);
2277 GetMagickPixelPacket(image,pixel);
2278 p=GetVirtualPixelCache(image,GetPixelCacheVirtualMethod(image),x,y,1,1,
2279 exception);
2280 if (p == (const PixelPacket *) NULL)
2281 return(MagickFalse);
2282 indexes=GetVirtualIndexQueue(image);
2283 SetMagickPixelPacket(image,p,indexes,pixel);
2284 return(MagickTrue);
2285}
2286
2287/*
2288%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2289% %
2290% %
2291% %
2292% G e t O n e V i r t u a l M e t h o d P i x e l %
2293% %
2294% %
2295% %
2296%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2297%
2298% GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2299% location as defined by specified pixel method. The image background color
2300% is returned if an error occurs. If you plan to modify the pixel, use
2301% GetOneAuthenticPixel() instead.
2302%
2303% The format of the GetOneVirtualMethodPixel() method is:
2304%
2305% MagickBooleanType GetOneVirtualMethodPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002306% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2307% const ssize_t y,Pixelpacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002308%
2309% A description of each parameter follows:
2310%
2311% o image: the image.
2312%
2313% o virtual_pixel_method: the virtual pixel method.
2314%
2315% o x,y: These values define the location of the pixel to return.
2316%
2317% o pixel: return a pixel at the specified (x,y) location.
2318%
2319% o exception: return any errors or warnings in this structure.
2320%
2321*/
2322MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002323 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002324 PixelPacket *pixel,ExceptionInfo *exception)
2325{
cristy3ed852e2009-09-05 21:47:34 +00002326 CacheInfo
2327 *cache_info;
2328
cristy3ed852e2009-09-05 21:47:34 +00002329 assert(image != (const Image *) NULL);
2330 assert(image->signature == MagickSignature);
2331 assert(image->cache != (Cache) NULL);
2332 cache_info=(CacheInfo *) image->cache;
2333 assert(cache_info->signature == MagickSignature);
2334 *pixel=image->background_color;
cristyd317f372010-09-18 01:42:20 +00002335 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2336 (GetOneVirtualPixelFromHandler) NULL)
2337 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2338 virtual_pixel_method,x,y,pixel,exception));
2339 return(GetOneVirtualPixelFromCache(image,virtual_pixel_method,x,y,pixel,
2340 exception));
cristy3ed852e2009-09-05 21:47:34 +00002341}
2342
2343/*
2344%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2345% %
2346% %
2347% %
2348% G e t O n e V i r t u a l P i x e l %
2349% %
2350% %
2351% %
2352%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2353%
2354% GetOneVirtualPixel() returns a single virtual pixel at the specified
2355% (x,y) location. The image background color is returned if an error occurs.
2356% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2357%
2358% The format of the GetOneVirtualPixel() method is:
2359%
cristybb503372010-05-27 20:51:26 +00002360% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2361% const ssize_t y,PixelPacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002362%
2363% A description of each parameter follows:
2364%
2365% o image: the image.
2366%
2367% o x,y: These values define the location of the pixel to return.
2368%
2369% o pixel: return a pixel at the specified (x,y) location.
2370%
2371% o exception: return any errors or warnings in this structure.
2372%
2373*/
2374MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002375 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002376{
cristy3ed852e2009-09-05 21:47:34 +00002377 CacheInfo
2378 *cache_info;
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 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
2390 return(GetOneVirtualPixelFromCache(image,GetPixelCacheVirtualMethod(image),
2391 x,y,pixel,exception));
cristy3ed852e2009-09-05 21:47:34 +00002392}
2393
2394/*
2395%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2396% %
2397% %
2398% %
2399+ 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 %
2400% %
2401% %
2402% %
2403%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2404%
2405% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2406% specified (x,y) location. The image background color is returned if an
2407% error occurs.
2408%
2409% The format of the GetOneVirtualPixelFromCache() method is:
2410%
2411% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristybb503372010-05-27 20:51:26 +00002412% const VirtualPixelPacket method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002413% PixelPacket *pixel,ExceptionInfo *exception)
2414%
2415% A description of each parameter follows:
2416%
2417% o image: the image.
2418%
2419% o virtual_pixel_method: the virtual pixel method.
2420%
2421% o x,y: These values define the location of the pixel to return.
2422%
2423% o pixel: return a pixel at the specified (x,y) location.
2424%
2425% o exception: return any errors or warnings in this structure.
2426%
2427*/
2428static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002429 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002430 PixelPacket *pixel,ExceptionInfo *exception)
2431{
2432 const PixelPacket
2433 *pixels;
2434
2435 *pixel=image->background_color;
2436 pixels=GetVirtualPixelCache(image,virtual_pixel_method,x,y,1UL,1UL,exception);
2437 if (pixels == (const PixelPacket *) NULL)
2438 return(MagickFalse);
2439 *pixel=(*pixels);
2440 return(MagickTrue);
2441}
2442
2443/*
2444%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2445% %
2446% %
2447% %
2448+ G e t P i x e l C a c h e C o l o r s p a c e %
2449% %
2450% %
2451% %
2452%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2453%
2454% GetPixelCacheColorspace() returns the class type of the pixel cache.
2455%
2456% The format of the GetPixelCacheColorspace() method is:
2457%
2458% Colorspace GetPixelCacheColorspace(Cache cache)
2459%
2460% A description of each parameter follows:
2461%
2462% o cache: the pixel cache.
2463%
2464*/
2465MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
2466{
2467 CacheInfo
2468 *cache_info;
2469
2470 assert(cache != (Cache) NULL);
2471 cache_info=(CacheInfo *) cache;
2472 assert(cache_info->signature == MagickSignature);
2473 if (cache_info->debug != MagickFalse)
2474 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2475 cache_info->filename);
2476 return(cache_info->colorspace);
2477}
2478
2479/*
2480%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2481% %
2482% %
2483% %
2484+ G e t P i x e l C a c h e M e t h o d s %
2485% %
2486% %
2487% %
2488%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2489%
2490% GetPixelCacheMethods() initializes the CacheMethods structure.
2491%
2492% The format of the GetPixelCacheMethods() method is:
2493%
2494% void GetPixelCacheMethods(CacheMethods *cache_methods)
2495%
2496% A description of each parameter follows:
2497%
2498% o cache_methods: Specifies a pointer to a CacheMethods structure.
2499%
2500*/
2501MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
2502{
2503 assert(cache_methods != (CacheMethods *) NULL);
2504 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2505 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2506 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2507 cache_methods->get_virtual_indexes_from_handler=GetVirtualIndexesFromCache;
2508 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2509 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2510 cache_methods->get_authentic_indexes_from_handler=
2511 GetAuthenticIndexesFromCache;
2512 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2513 cache_methods->get_one_authentic_pixel_from_handler=
2514 GetOneAuthenticPixelFromCache;
2515 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2516 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2517 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2518}
2519
2520/*
2521%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2522% %
2523% %
2524% %
2525+ G e t P i x e l C a c h e N e x u s E x t e n t %
2526% %
2527% %
2528% %
2529%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2530%
2531% GetPixelCacheNexusExtent() returns the extent of the pixels associated with
2532% the last call to SetPixelCacheNexusPixels() or GetPixelCacheNexusPixels().
2533%
2534% The format of the GetPixelCacheNexusExtent() method is:
2535%
2536% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2537% NexusInfo *nexus_info)
2538%
2539% A description of each parameter follows:
2540%
2541% o nexus_info: the nexus info.
2542%
2543*/
2544MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2545 NexusInfo *nexus_info)
2546{
2547 CacheInfo
2548 *cache_info;
2549
2550 MagickSizeType
2551 extent;
2552
2553 if (cache == (Cache) NULL)
2554 return(0);
2555 cache_info=(CacheInfo *) cache;
2556 assert(cache_info->signature == MagickSignature);
2557 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2558 if (extent == 0)
2559 return((MagickSizeType) cache_info->columns*cache_info->rows);
2560 return(extent);
2561}
2562
2563/*
2564%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2565% %
2566% %
2567% %
2568+ 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 %
2569% %
2570% %
2571% %
2572%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2573%
2574% GetPixelCacheNexusIndexes() returns the indexes associated with the
2575% specified cache nexus.
2576%
2577% The format of the GetPixelCacheNexusIndexes() method is:
2578%
2579% IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2580% NexusInfo *nexus_info)
2581%
2582% A description of each parameter follows:
2583%
2584% o cache: the pixel cache.
2585%
2586% o nexus_info: the cache nexus to return the colormap indexes.
2587%
2588*/
2589MagickExport IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2590 NexusInfo *nexus_info)
2591{
2592 CacheInfo
2593 *cache_info;
2594
2595 if (cache == (Cache) NULL)
2596 return((IndexPacket *) NULL);
2597 cache_info=(CacheInfo *) cache;
2598 assert(cache_info->signature == MagickSignature);
2599 if (cache_info->storage_class == UndefinedClass)
2600 return((IndexPacket *) NULL);
2601 return(nexus_info->indexes);
2602}
2603
2604/*
2605%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2606% %
2607% %
2608% %
2609+ G e t P i x e l C a c h e N e x u s P i x e l s %
2610% %
2611% %
2612% %
2613%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2614%
2615% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2616% cache nexus.
2617%
2618% The format of the GetPixelCacheNexusPixels() method is:
2619%
2620% PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2621% NexusInfo *nexus_info)
2622%
2623% A description of each parameter follows:
2624%
2625% o cache: the pixel cache.
2626%
2627% o nexus_info: the cache nexus to return the pixels.
2628%
2629*/
2630MagickExport PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2631 NexusInfo *nexus_info)
2632{
2633 CacheInfo
2634 *cache_info;
2635
2636 if (cache == (Cache) NULL)
2637 return((PixelPacket *) NULL);
2638 cache_info=(CacheInfo *) cache;
2639 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002640 if (cache_info->storage_class == UndefinedClass)
2641 return((PixelPacket *) NULL);
2642 return(nexus_info->pixels);
2643}
2644
2645/*
2646%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2647% %
2648% %
2649% %
cristy056ba772010-01-02 23:33:54 +00002650+ G e t P i x e l C a c h e P i x e l s %
2651% %
2652% %
2653% %
2654%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2655%
2656% GetPixelCachePixels() returns the pixels associated with the specified image.
2657%
2658% The format of the GetPixelCachePixels() method is:
2659%
cristyf84a1932010-01-03 18:00:18 +00002660% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2661% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002662%
2663% A description of each parameter follows:
2664%
2665% o image: the image.
2666%
2667% o length: the pixel cache length.
2668%
cristyf84a1932010-01-03 18:00:18 +00002669% o exception: return any errors or warnings in this structure.
2670%
cristy056ba772010-01-02 23:33:54 +00002671*/
cristyf84a1932010-01-03 18:00:18 +00002672MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2673 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002674{
2675 CacheInfo
2676 *cache_info;
2677
2678 assert(image != (const Image *) NULL);
2679 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002680 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00002681 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002682 assert(cache_info->signature == MagickSignature);
2683 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002684 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002685 return((void *) NULL);
2686 *length=cache_info->length;
2687 return((void *) cache_info->pixels);
2688}
2689
2690/*
2691%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2692% %
2693% %
2694% %
cristyb32b90a2009-09-07 21:45:48 +00002695+ 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 +00002696% %
2697% %
2698% %
2699%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2700%
2701% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2702%
2703% The format of the GetPixelCacheStorageClass() method is:
2704%
2705% ClassType GetPixelCacheStorageClass(Cache cache)
2706%
2707% A description of each parameter follows:
2708%
2709% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2710%
2711% o cache: the pixel cache.
2712%
2713*/
2714MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
2715{
2716 CacheInfo
2717 *cache_info;
2718
2719 assert(cache != (Cache) NULL);
2720 cache_info=(CacheInfo *) cache;
2721 assert(cache_info->signature == MagickSignature);
2722 if (cache_info->debug != MagickFalse)
2723 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2724 cache_info->filename);
2725 return(cache_info->storage_class);
2726}
2727
2728/*
2729%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2730% %
2731% %
2732% %
cristyb32b90a2009-09-07 21:45:48 +00002733+ G e t P i x e l C a c h e T i l e S i z e %
2734% %
2735% %
2736% %
2737%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2738%
2739% GetPixelCacheTileSize() returns the pixel cache tile size.
2740%
2741% The format of the GetPixelCacheTileSize() method is:
2742%
cristybb503372010-05-27 20:51:26 +00002743% void GetPixelCacheTileSize(const Image *image,size_t *width,
2744% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002745%
2746% A description of each parameter follows:
2747%
2748% o image: the image.
2749%
2750% o width: the optimize cache tile width in pixels.
2751%
2752% o height: the optimize cache tile height in pixels.
2753%
2754*/
cristybb503372010-05-27 20:51:26 +00002755MagickExport void GetPixelCacheTileSize(const Image *image,size_t *width,
2756 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002757{
2758 CacheInfo
2759 *cache_info;
2760
2761 assert(image != (Image *) NULL);
2762 assert(image->signature == MagickSignature);
2763 if (image->debug != MagickFalse)
2764 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2765 assert(image->cache != (Cache) NULL);
2766 cache_info=(CacheInfo *) image->cache;
2767 assert(cache_info->signature == MagickSignature);
2768 *width=2048UL/sizeof(PixelPacket);
2769 if (GetPixelCacheType(image) == DiskCache)
cristydaa97692009-09-13 02:10:35 +00002770 *width=8192UL/sizeof(PixelPacket);
cristyb32b90a2009-09-07 21:45:48 +00002771 *height=(*width);
2772}
2773
2774/*
2775%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2776% %
2777% %
2778% %
2779+ G e t P i x e l C a c h e T y p e %
2780% %
2781% %
2782% %
2783%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2784%
2785% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2786%
2787% The format of the GetPixelCacheType() method is:
2788%
2789% CacheType GetPixelCacheType(const Image *image)
2790%
2791% A description of each parameter follows:
2792%
2793% o image: the image.
2794%
2795*/
2796MagickExport CacheType GetPixelCacheType(const Image *image)
2797{
2798 CacheInfo
2799 *cache_info;
2800
2801 assert(image != (Image *) NULL);
2802 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002803 assert(image->cache != (Cache) NULL);
2804 cache_info=(CacheInfo *) image->cache;
2805 assert(cache_info->signature == MagickSignature);
2806 return(cache_info->type);
2807}
2808
2809/*
2810%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2811% %
2812% %
2813% %
cristy3ed852e2009-09-05 21:47:34 +00002814+ 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 %
2815% %
2816% %
2817% %
2818%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2819%
2820% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2821% pixel cache. A virtual pixel is any pixel access that is outside the
2822% boundaries of the image cache.
2823%
2824% The format of the GetPixelCacheVirtualMethod() method is:
2825%
2826% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2827%
2828% A description of each parameter follows:
2829%
2830% o image: the image.
2831%
2832*/
2833MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2834{
2835 CacheInfo
2836 *cache_info;
2837
2838 assert(image != (Image *) NULL);
2839 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002840 assert(image->cache != (Cache) NULL);
2841 cache_info=(CacheInfo *) image->cache;
2842 assert(cache_info->signature == MagickSignature);
2843 return(cache_info->virtual_pixel_method);
2844}
2845
2846/*
2847%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2848% %
2849% %
2850% %
2851+ 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 %
2852% %
2853% %
2854% %
2855%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2856%
2857% GetVirtualIndexesFromCache() returns the indexes associated with the last
2858% call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2859%
2860% The format of the GetVirtualIndexesFromCache() method is:
2861%
2862% IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2863%
2864% A description of each parameter follows:
2865%
2866% o image: the image.
2867%
2868*/
2869static const IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2870{
2871 CacheInfo
2872 *cache_info;
2873
cristy5c9e6f22010-09-17 17:31:01 +00002874 const int
2875 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002876
cristy3ed852e2009-09-05 21:47:34 +00002877 cache_info=(CacheInfo *) image->cache;
cristy6ebe97c2010-07-03 01:17:28 +00002878 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00002879 return(GetVirtualIndexesFromNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00002880}
2881
2882/*
2883%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2884% %
2885% %
2886% %
2887+ 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 %
2888% %
2889% %
2890% %
2891%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2892%
2893% GetVirtualIndexesFromNexus() returns the indexes associated with the
2894% specified cache nexus.
2895%
2896% The format of the GetVirtualIndexesFromNexus() method is:
2897%
2898% const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2899% NexusInfo *nexus_info)
2900%
2901% A description of each parameter follows:
2902%
2903% o cache: the pixel cache.
2904%
2905% o nexus_info: the cache nexus to return the colormap indexes.
2906%
2907*/
2908MagickExport const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2909 NexusInfo *nexus_info)
2910{
2911 CacheInfo
2912 *cache_info;
2913
2914 if (cache == (Cache) NULL)
2915 return((IndexPacket *) NULL);
2916 cache_info=(CacheInfo *) cache;
2917 assert(cache_info->signature == MagickSignature);
2918 if (cache_info->storage_class == UndefinedClass)
2919 return((IndexPacket *) NULL);
2920 return(nexus_info->indexes);
2921}
2922
2923/*
2924%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2925% %
2926% %
2927% %
2928% G e t V i r t u a l I n d e x Q u e u e %
2929% %
2930% %
2931% %
2932%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2933%
2934% GetVirtualIndexQueue() returns the virtual black channel or the
2935% colormap indexes associated with the last call to QueueAuthenticPixels() or
2936% GetVirtualPixels(). NULL is returned if the black channel or colormap
2937% indexes are not available.
2938%
2939% The format of the GetVirtualIndexQueue() method is:
2940%
2941% const IndexPacket *GetVirtualIndexQueue(const Image *image)
2942%
2943% A description of each parameter follows:
2944%
2945% o image: the image.
2946%
2947*/
2948MagickExport const IndexPacket *GetVirtualIndexQueue(const Image *image)
2949{
2950 CacheInfo
2951 *cache_info;
2952
2953 assert(image != (const Image *) NULL);
2954 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002955 assert(image->cache != (Cache) NULL);
2956 cache_info=(CacheInfo *) image->cache;
2957 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00002958 if (cache_info->methods.get_virtual_indexes_from_handler !=
2959 (GetVirtualIndexesFromHandler) NULL)
2960 return(cache_info->methods.get_virtual_indexes_from_handler(image));
2961 return(GetVirtualIndexesFromCache(image));
cristy3ed852e2009-09-05 21:47:34 +00002962}
2963
2964/*
2965%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2966% %
2967% %
2968% %
2969+ 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 %
2970% %
2971% %
2972% %
2973%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2974%
2975% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2976% pixel cache as defined by the geometry parameters. A pointer to the pixels
2977% is returned if the pixels are transferred, otherwise a NULL is returned.
2978%
2979% The format of the GetVirtualPixelsFromNexus() method is:
2980%
2981% PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00002982% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00002983% const size_t columns,const size_t rows,NexusInfo *nexus_info,
2984% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002985%
2986% A description of each parameter follows:
2987%
2988% o image: the image.
2989%
2990% o virtual_pixel_method: the virtual pixel method.
2991%
2992% o x,y,columns,rows: These values define the perimeter of a region of
2993% pixels.
2994%
2995% o nexus_info: the cache nexus to acquire.
2996%
2997% o exception: return any errors or warnings in this structure.
2998%
2999*/
3000
cristybb503372010-05-27 20:51:26 +00003001static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003002 DitherMatrix[64] =
3003 {
3004 0, 48, 12, 60, 3, 51, 15, 63,
3005 32, 16, 44, 28, 35, 19, 47, 31,
3006 8, 56, 4, 52, 11, 59, 7, 55,
3007 40, 24, 36, 20, 43, 27, 39, 23,
3008 2, 50, 14, 62, 1, 49, 13, 61,
3009 34, 18, 46, 30, 33, 17, 45, 29,
3010 10, 58, 6, 54, 9, 57, 5, 53,
3011 42, 26, 38, 22, 41, 25, 37, 21
3012 };
3013
cristybb503372010-05-27 20:51:26 +00003014static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003015{
cristybb503372010-05-27 20:51:26 +00003016 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003017 index;
3018
3019 index=x+DitherMatrix[x & 0x07]-32L;
3020 if (index < 0L)
3021 return(0L);
cristybb503372010-05-27 20:51:26 +00003022 if (index >= (ssize_t) columns)
3023 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00003024 return(index);
3025}
3026
cristybb503372010-05-27 20:51:26 +00003027static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003028{
cristybb503372010-05-27 20:51:26 +00003029 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003030 index;
3031
3032 index=y+DitherMatrix[y & 0x07]-32L;
3033 if (index < 0L)
3034 return(0L);
cristybb503372010-05-27 20:51:26 +00003035 if (index >= (ssize_t) rows)
3036 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00003037 return(index);
3038}
3039
cristybb503372010-05-27 20:51:26 +00003040static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003041{
3042 if (x < 0L)
3043 return(0L);
cristybb503372010-05-27 20:51:26 +00003044 if (x >= (ssize_t) columns)
3045 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003046 return(x);
3047}
3048
cristybb503372010-05-27 20:51:26 +00003049static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003050{
3051 if (y < 0L)
3052 return(0L);
cristybb503372010-05-27 20:51:26 +00003053 if (y >= (ssize_t) rows)
3054 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003055 return(y);
3056}
3057
cristybb503372010-05-27 20:51:26 +00003058static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003059{
cristybb503372010-05-27 20:51:26 +00003060 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003061}
3062
cristybb503372010-05-27 20:51:26 +00003063static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003064{
cristybb503372010-05-27 20:51:26 +00003065 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003066}
3067
3068/*
3069 VirtualPixelModulo() computes the remainder of dividing offset by extent. It
3070 returns not only the quotient (tile the offset falls in) but also the positive
3071 remainer within that tile such that 0 <= remainder < extent. This method is
3072 essentially a ldiv() using a floored modulo division rather than the normal
3073 default truncated modulo division.
3074*/
cristybb503372010-05-27 20:51:26 +00003075static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3076 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003077{
3078 MagickModulo
3079 modulo;
3080
cristybb503372010-05-27 20:51:26 +00003081 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003082 if (offset < 0L)
3083 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003084 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003085 return(modulo);
3086}
3087
3088MagickExport const PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003089 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3090 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003091 ExceptionInfo *exception)
3092{
3093 CacheInfo
3094 *cache_info;
3095
cristyc3ec0d42010-04-07 01:18:08 +00003096 IndexPacket
3097 virtual_index;
3098
cristy3ed852e2009-09-05 21:47:34 +00003099 MagickOffsetType
3100 offset;
3101
3102 MagickSizeType
3103 length,
3104 number_pixels;
3105
3106 NexusInfo
3107 **virtual_nexus;
3108
3109 PixelPacket
3110 *pixels,
3111 virtual_pixel;
3112
3113 RectangleInfo
3114 region;
3115
3116 register const IndexPacket
cristyc3ec0d42010-04-07 01:18:08 +00003117 *restrict virtual_indexes;
cristy3ed852e2009-09-05 21:47:34 +00003118
3119 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003120 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003121
3122 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003123 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003124
cristye076a6e2010-08-15 19:59:43 +00003125 register PixelPacket
3126 *restrict q;
3127
cristybb503372010-05-27 20:51:26 +00003128 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003129 u,
3130 v;
3131
cristy3ed852e2009-09-05 21:47:34 +00003132 /*
3133 Acquire pixels.
3134 */
cristy3ed852e2009-09-05 21:47:34 +00003135 cache_info=(CacheInfo *) image->cache;
cristy4cfbb3f2010-03-14 20:40:23 +00003136 if (cache_info->type == UndefinedCache)
cristy3ed852e2009-09-05 21:47:34 +00003137 return((const PixelPacket *) NULL);
3138 region.x=x;
3139 region.y=y;
3140 region.width=columns;
3141 region.height=rows;
3142 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
3143 if (pixels == (PixelPacket *) NULL)
3144 return((const PixelPacket *) NULL);
cristydf415c82010-03-11 16:47:50 +00003145 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3146 nexus_info->region.x;
3147 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3148 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003149 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3150 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003151 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3152 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003153 {
3154 MagickBooleanType
3155 status;
3156
3157 /*
3158 Pixel request is inside cache extents.
3159 */
3160 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
3161 return(pixels);
3162 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3163 if (status == MagickFalse)
3164 return((const PixelPacket *) NULL);
3165 if ((cache_info->storage_class == PseudoClass) ||
3166 (cache_info->colorspace == CMYKColorspace))
3167 {
3168 status=ReadPixelCacheIndexes(cache_info,nexus_info,exception);
3169 if (status == MagickFalse)
3170 return((const PixelPacket *) NULL);
3171 }
3172 return(pixels);
3173 }
3174 /*
3175 Pixel request is outside cache extents.
3176 */
3177 q=pixels;
3178 indexes=GetPixelCacheNexusIndexes(cache_info,nexus_info);
3179 virtual_nexus=AcquirePixelCacheNexus(1);
3180 if (virtual_nexus == (NexusInfo **) NULL)
3181 {
3182 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3183 "UnableToGetCacheNexus","`%s'",image->filename);
3184 return((const PixelPacket *) NULL);
3185 }
3186 switch (virtual_pixel_method)
3187 {
3188 case BlackVirtualPixelMethod:
3189 {
cristy4789f0d2010-01-10 00:01:06 +00003190 SetRedPixelComponent(&virtual_pixel,0);
3191 SetGreenPixelComponent(&virtual_pixel,0);
3192 SetBluePixelComponent(&virtual_pixel,0);
3193 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003194 break;
3195 }
3196 case GrayVirtualPixelMethod:
3197 {
cristy4789f0d2010-01-10 00:01:06 +00003198 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3199 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3200 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3201 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003202 break;
3203 }
3204 case TransparentVirtualPixelMethod:
3205 {
cristy4789f0d2010-01-10 00:01:06 +00003206 SetRedPixelComponent(&virtual_pixel,0);
3207 SetGreenPixelComponent(&virtual_pixel,0);
3208 SetBluePixelComponent(&virtual_pixel,0);
3209 SetOpacityPixelComponent(&virtual_pixel,TransparentOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003210 break;
3211 }
3212 case MaskVirtualPixelMethod:
3213 case WhiteVirtualPixelMethod:
3214 {
cristy4789f0d2010-01-10 00:01:06 +00003215 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3216 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3217 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3218 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003219 break;
3220 }
3221 default:
3222 {
3223 virtual_pixel=image->background_color;
3224 break;
3225 }
3226 }
cristyc3ec0d42010-04-07 01:18:08 +00003227 virtual_index=0;
cristybb503372010-05-27 20:51:26 +00003228 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003229 {
cristybb503372010-05-27 20:51:26 +00003230 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003231 {
3232 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003233 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003234 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3235 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003236 {
3237 MagickModulo
3238 x_modulo,
3239 y_modulo;
3240
3241 /*
3242 Transfer a single pixel.
3243 */
3244 length=(MagickSizeType) 1;
3245 switch (virtual_pixel_method)
3246 {
3247 case BackgroundVirtualPixelMethod:
3248 case ConstantVirtualPixelMethod:
3249 case BlackVirtualPixelMethod:
3250 case GrayVirtualPixelMethod:
3251 case TransparentVirtualPixelMethod:
3252 case MaskVirtualPixelMethod:
3253 case WhiteVirtualPixelMethod:
3254 {
3255 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003256 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003257 break;
3258 }
3259 case EdgeVirtualPixelMethod:
3260 default:
3261 {
3262 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003263 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003264 1UL,1UL,virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003265 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3266 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003267 break;
3268 }
3269 case RandomVirtualPixelMethod:
3270 {
3271 if (cache_info->random_info == (RandomInfo *) NULL)
3272 cache_info->random_info=AcquireRandomInfo();
3273 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003274 RandomX(cache_info->random_info,cache_info->columns),
3275 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003276 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003277 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3278 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003279 break;
3280 }
3281 case DitherVirtualPixelMethod:
3282 {
3283 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003284 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003285 1UL,1UL,virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003286 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3287 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003288 break;
3289 }
3290 case TileVirtualPixelMethod:
3291 {
3292 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3293 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3294 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3295 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3296 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003297 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3298 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003299 break;
3300 }
3301 case MirrorVirtualPixelMethod:
3302 {
3303 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3304 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003305 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003306 x_modulo.remainder-1L;
3307 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3308 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003309 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003310 y_modulo.remainder-1L;
3311 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3312 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3313 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003314 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3315 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003316 break;
3317 }
3318 case CheckerTileVirtualPixelMethod:
3319 {
3320 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3321 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3322 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3323 {
3324 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003325 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003326 break;
3327 }
3328 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3329 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3330 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003331 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3332 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003333 break;
3334 }
3335 case HorizontalTileVirtualPixelMethod:
3336 {
cristybb503372010-05-27 20:51:26 +00003337 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003338 {
3339 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003340 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003341 break;
3342 }
3343 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3344 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3345 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3346 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3347 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003348 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3349 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003350 break;
3351 }
3352 case VerticalTileVirtualPixelMethod:
3353 {
cristybb503372010-05-27 20:51:26 +00003354 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
cristy3ed852e2009-09-05 21:47:34 +00003355 {
3356 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003357 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003358 break;
3359 }
3360 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3361 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3362 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3363 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3364 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003365 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3366 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003367 break;
3368 }
3369 case HorizontalTileEdgeVirtualPixelMethod:
3370 {
3371 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3372 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003373 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003374 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003375 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3376 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003377 break;
3378 }
3379 case VerticalTileEdgeVirtualPixelMethod:
3380 {
3381 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3382 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003383 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003384 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003385 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3386 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003387 break;
3388 }
3389 }
3390 if (p == (const PixelPacket *) NULL)
3391 break;
3392 *q++=(*p);
cristyc3ec0d42010-04-07 01:18:08 +00003393 if ((indexes != (IndexPacket *) NULL) &&
3394 (virtual_indexes != (const IndexPacket *) NULL))
3395 *indexes++=(*virtual_indexes);
cristy3ed852e2009-09-05 21:47:34 +00003396 continue;
3397 }
3398 /*
3399 Transfer a run of pixels.
3400 */
3401 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,
cristybb503372010-05-27 20:51:26 +00003402 (size_t) length,1UL,virtual_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003403 if (p == (const PixelPacket *) NULL)
3404 break;
cristyc3ec0d42010-04-07 01:18:08 +00003405 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003406 (void) CopyMagickMemory(q,p,(size_t) length*sizeof(*p));
3407 q+=length;
cristyc3ec0d42010-04-07 01:18:08 +00003408 if ((indexes != (IndexPacket *) NULL) &&
3409 (virtual_indexes != (const IndexPacket *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003410 {
cristyc3ec0d42010-04-07 01:18:08 +00003411 (void) CopyMagickMemory(indexes,virtual_indexes,(size_t) length*
3412 sizeof(*virtual_indexes));
3413 indexes+=length;
cristy3ed852e2009-09-05 21:47:34 +00003414 }
3415 }
3416 }
3417 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3418 return(pixels);
3419}
3420
3421/*
3422%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3423% %
3424% %
3425% %
3426+ G e t V i r t u a l P i x e l C a c h e %
3427% %
3428% %
3429% %
3430%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3431%
3432% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3433% cache as defined by the geometry parameters. A pointer to the pixels
3434% is returned if the pixels are transferred, otherwise a NULL is returned.
3435%
3436% The format of the GetVirtualPixelCache() method is:
3437%
3438% const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003439% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3440% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003441% ExceptionInfo *exception)
3442%
3443% A description of each parameter follows:
3444%
3445% o image: the image.
3446%
3447% o virtual_pixel_method: the virtual pixel method.
3448%
3449% o x,y,columns,rows: These values define the perimeter of a region of
3450% pixels.
3451%
3452% o exception: return any errors or warnings in this structure.
3453%
3454*/
3455static const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003456 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3457 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003458{
3459 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003460 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003461
cristy5c9e6f22010-09-17 17:31:01 +00003462 const int
3463 id = GetOpenMPThreadId();
3464
cristy3ed852e2009-09-05 21:47:34 +00003465 cache_info=(CacheInfo *) image->cache;
cristy6ebe97c2010-07-03 01:17:28 +00003466 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003467 return(GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3468 cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00003469}
3470
3471/*
3472%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3473% %
3474% %
3475% %
3476% G e t V i r t u a l P i x e l Q u e u e %
3477% %
3478% %
3479% %
3480%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3481%
3482% GetVirtualPixelQueue() returns the virtual pixels associated with the
3483% last call to QueueAuthenticPixels() or GetVirtualPixels().
3484%
3485% The format of the GetVirtualPixelQueue() method is:
3486%
3487% const PixelPacket *GetVirtualPixelQueue(const Image image)
3488%
3489% A description of each parameter follows:
3490%
3491% o image: the image.
3492%
3493*/
3494MagickExport const PixelPacket *GetVirtualPixelQueue(const Image *image)
3495{
3496 CacheInfo
3497 *cache_info;
3498
3499 assert(image != (const Image *) NULL);
3500 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003501 assert(image->cache != (Cache) NULL);
3502 cache_info=(CacheInfo *) image->cache;
3503 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003504 if (cache_info->methods.get_virtual_pixels_handler !=
3505 (GetVirtualPixelsHandler) NULL)
3506 return(cache_info->methods.get_virtual_pixels_handler(image));
3507 return(GetVirtualPixelsCache(image));
cristy3ed852e2009-09-05 21:47:34 +00003508}
3509
3510/*
3511%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3512% %
3513% %
3514% %
3515% G e t V i r t u a l P i x e l s %
3516% %
3517% %
3518% %
3519%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3520%
3521% GetVirtualPixels() returns an immutable pixel region. If the
3522% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003523% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003524% copy of the pixels or it may point to the original pixels in memory.
3525% Performance is maximized if the selected region is part of one row, or one
3526% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003527% (without a copy) if the image is in memory, or in a memory-mapped file. The
3528% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003529%
3530% Pixels accessed via the returned pointer represent a simple array of type
3531% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
3532% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to access
3533% the black color component or to obtain the colormap indexes (of type
3534% IndexPacket) corresponding to the region.
3535%
3536% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3537%
3538% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3539% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3540% GetCacheViewAuthenticPixels() instead.
3541%
3542% The format of the GetVirtualPixels() method is:
3543%
cristybb503372010-05-27 20:51:26 +00003544% const PixelPacket *GetVirtualPixels(const Image *image,const ssize_t x,
3545% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003546% ExceptionInfo *exception)
3547%
3548% A description of each parameter follows:
3549%
3550% o image: the image.
3551%
3552% o x,y,columns,rows: These values define the perimeter of a region of
3553% pixels.
3554%
3555% o exception: return any errors or warnings in this structure.
3556%
3557*/
3558MagickExport const PixelPacket *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003559 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3560 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003561{
3562 CacheInfo
3563 *cache_info;
3564
cristy3ed852e2009-09-05 21:47:34 +00003565 assert(image != (const Image *) NULL);
3566 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003567 assert(image->cache != (Cache) NULL);
3568 cache_info=(CacheInfo *) image->cache;
3569 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003570 if (cache_info->methods.get_virtual_pixel_handler !=
3571 (GetVirtualPixelHandler) NULL)
3572 return(cache_info->methods.get_virtual_pixel_handler(image,
3573 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3574 return(GetVirtualPixelCache(image,GetPixelCacheVirtualMethod(image),x,y,
3575 columns,rows,exception));
cristy3ed852e2009-09-05 21:47:34 +00003576}
3577
3578/*
3579%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3580% %
3581% %
3582% %
3583+ 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 %
3584% %
3585% %
3586% %
3587%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3588%
3589% GetVirtualPixelsCache() returns the pixels associated with the last call
3590% to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3591%
3592% The format of the GetVirtualPixelsCache() method is:
3593%
3594% PixelPacket *GetVirtualPixelsCache(const Image *image)
3595%
3596% A description of each parameter follows:
3597%
3598% o image: the image.
3599%
3600*/
3601static const PixelPacket *GetVirtualPixelsCache(const Image *image)
3602{
3603 CacheInfo
3604 *cache_info;
3605
cristy5c9e6f22010-09-17 17:31:01 +00003606 const int
3607 id = GetOpenMPThreadId();
3608
cristy3ed852e2009-09-05 21:47:34 +00003609 cache_info=(CacheInfo *) image->cache;
cristy6ebe97c2010-07-03 01:17:28 +00003610 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003611 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003612}
3613
3614/*
3615%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3616% %
3617% %
3618% %
3619+ G e t V i r t u a l P i x e l s N e x u s %
3620% %
3621% %
3622% %
3623%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3624%
3625% GetVirtualPixelsNexus() returns the pixels associated with the specified
3626% cache nexus.
3627%
3628% The format of the GetVirtualPixelsNexus() method is:
3629%
3630% const IndexPacket *GetVirtualPixelsNexus(const Cache cache,
3631% NexusInfo *nexus_info)
3632%
3633% A description of each parameter follows:
3634%
3635% o cache: the pixel cache.
3636%
3637% o nexus_info: the cache nexus to return the colormap pixels.
3638%
3639*/
3640MagickExport const PixelPacket *GetVirtualPixelsNexus(const Cache cache,
3641 NexusInfo *nexus_info)
3642{
3643 CacheInfo
3644 *cache_info;
3645
3646 if (cache == (Cache) NULL)
3647 return((PixelPacket *) NULL);
3648 cache_info=(CacheInfo *) cache;
3649 assert(cache_info->signature == MagickSignature);
3650 if (cache_info->storage_class == UndefinedClass)
3651 return((PixelPacket *) NULL);
3652 return((const PixelPacket *) nexus_info->pixels);
3653}
3654
3655/*
3656%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3657% %
3658% %
3659% %
3660+ M a s k P i x e l C a c h e N e x u s %
3661% %
3662% %
3663% %
3664%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3665%
3666% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3667% The method returns MagickTrue if the pixel region is masked, otherwise
3668% MagickFalse.
3669%
3670% The format of the MaskPixelCacheNexus() method is:
3671%
3672% MagickBooleanType MaskPixelCacheNexus(Image *image,
3673% NexusInfo *nexus_info,ExceptionInfo *exception)
3674%
3675% A description of each parameter follows:
3676%
3677% o image: the image.
3678%
3679% o nexus_info: the cache nexus to clip.
3680%
3681% o exception: return any errors or warnings in this structure.
3682%
3683*/
3684
3685static inline void MagickPixelCompositeMask(const MagickPixelPacket *p,
3686 const MagickRealType alpha,const MagickPixelPacket *q,
3687 const MagickRealType beta,MagickPixelPacket *composite)
3688{
3689 MagickRealType
3690 gamma;
3691
3692 if (alpha == TransparentOpacity)
3693 {
3694 *composite=(*q);
3695 return;
3696 }
3697 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3698 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3699 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3700 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3701 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3702 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3703 composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
3704}
3705
3706static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3707 ExceptionInfo *exception)
3708{
3709 CacheInfo
3710 *cache_info;
3711
3712 MagickPixelPacket
3713 alpha,
3714 beta;
3715
3716 MagickSizeType
3717 number_pixels;
3718
3719 NexusInfo
3720 **clip_nexus,
3721 **image_nexus;
3722
3723 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003724 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003725
3726 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003727 *restrict nexus_indexes,
3728 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003729
cristy3ed852e2009-09-05 21:47:34 +00003730 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003731 *restrict p,
3732 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003733
cristye076a6e2010-08-15 19:59:43 +00003734 register ssize_t
3735 i;
3736
cristy3ed852e2009-09-05 21:47:34 +00003737 /*
3738 Apply clip mask.
3739 */
3740 if (image->debug != MagickFalse)
3741 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3742 if (image->mask == (Image *) NULL)
3743 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +00003744 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00003745 if (cache_info == (Cache) NULL)
3746 return(MagickFalse);
3747 image_nexus=AcquirePixelCacheNexus(1);
3748 clip_nexus=AcquirePixelCacheNexus(1);
3749 if ((image_nexus == (NexusInfo **) NULL) ||
3750 (clip_nexus == (NexusInfo **) NULL))
3751 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy09449f72010-01-23 03:08:36 +00003752 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,
3753 nexus_info->region.y,nexus_info->region.width,nexus_info->region.height,
3754 image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003755 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
3756 q=nexus_info->pixels;
3757 nexus_indexes=nexus_info->indexes;
3758 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3759 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3760 nexus_info->region.height,clip_nexus[0],&image->exception);
3761 GetMagickPixelPacket(image,&alpha);
3762 GetMagickPixelPacket(image,&beta);
3763 number_pixels=(MagickSizeType) nexus_info->region.width*
3764 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +00003765 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +00003766 {
3767 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
3768 break;
3769 SetMagickPixelPacket(image,p,indexes+i,&alpha);
3770 SetMagickPixelPacket(image,q,nexus_indexes+i,&beta);
3771 MagickPixelCompositeMask(&beta,(MagickRealType) PixelIntensityToQuantum(r),
3772 &alpha,alpha.opacity,&beta);
cristyce70c172010-01-07 17:15:30 +00003773 q->red=ClampToQuantum(beta.red);
3774 q->green=ClampToQuantum(beta.green);
3775 q->blue=ClampToQuantum(beta.blue);
3776 q->opacity=ClampToQuantum(beta.opacity);
cristy3ed852e2009-09-05 21:47:34 +00003777 if (cache_info->active_index_channel != MagickFalse)
3778 nexus_indexes[i]=indexes[i];
3779 p++;
3780 q++;
3781 r++;
3782 }
3783 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3784 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +00003785 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003786 return(MagickFalse);
3787 return(MagickTrue);
3788}
3789
3790/*
3791%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3792% %
3793% %
3794% %
3795+ O p e n P i x e l C a c h e %
3796% %
3797% %
3798% %
3799%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3800%
3801% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3802% dimensions, allocating space for the image pixels and optionally the
3803% colormap indexes, and memory mapping the cache if it is disk based. The
3804% cache nexus array is initialized as well.
3805%
3806% The format of the OpenPixelCache() method is:
3807%
3808% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3809% ExceptionInfo *exception)
3810%
3811% A description of each parameter follows:
3812%
3813% o image: the image.
3814%
3815% o mode: ReadMode, WriteMode, or IOMode.
3816%
3817% o exception: return any errors or warnings in this structure.
3818%
3819*/
3820
cristyd43a46b2010-01-21 02:13:41 +00003821static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003822{
3823 cache_info->mapped=MagickFalse;
3824 cache_info->pixels=(PixelPacket *) AcquireMagickMemory((size_t)
3825 cache_info->length);
3826 if (cache_info->pixels == (PixelPacket *) NULL)
3827 {
3828 cache_info->mapped=MagickTrue;
3829 cache_info->pixels=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
3830 cache_info->length);
3831 }
3832}
3833
3834static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3835{
3836 CacheInfo
3837 *cache_info;
3838
3839 MagickOffsetType
3840 count,
3841 extent,
3842 offset;
3843
3844 cache_info=(CacheInfo *) image->cache;
3845 if (image->debug != MagickFalse)
3846 {
3847 char
3848 format[MaxTextExtent],
3849 message[MaxTextExtent];
3850
cristyb9080c92009-12-01 20:13:26 +00003851 (void) FormatMagickSize(length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00003852 (void) FormatMagickString(message,MaxTextExtent,
cristy2ce15c92010-03-12 14:03:41 +00003853 "extend %s (%s[%d], disk, %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003854 cache_info->cache_filename,cache_info->file,format);
3855 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3856 }
3857 if (length != (MagickSizeType) ((MagickOffsetType) length))
3858 return(MagickFalse);
3859 extent=(MagickOffsetType) MagickSeek(cache_info->file,0,SEEK_END);
3860 if (extent < 0)
3861 return(MagickFalse);
3862 if ((MagickSizeType) extent >= length)
3863 return(MagickTrue);
3864 offset=(MagickOffsetType) length-1;
3865 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3866 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3867}
3868
3869static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3870 ExceptionInfo *exception)
3871{
3872 char
3873 format[MaxTextExtent],
3874 message[MaxTextExtent];
3875
3876 CacheInfo
3877 *cache_info,
3878 source_info;
3879
3880 MagickSizeType
3881 length,
3882 number_pixels;
3883
3884 MagickStatusType
3885 status;
3886
3887 size_t
cristye076a6e2010-08-15 19:59:43 +00003888 columns,
cristy3ed852e2009-09-05 21:47:34 +00003889 packet_size;
3890
cristy3ed852e2009-09-05 21:47:34 +00003891 if (image->debug != MagickFalse)
3892 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3893 if ((image->columns == 0) || (image->rows == 0))
3894 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3895 cache_info=(CacheInfo *) image->cache;
3896 source_info=(*cache_info);
3897 source_info.file=(-1);
cristye8c25f92010-06-03 00:53:06 +00003898 (void) FormatMagickString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3899 image->filename,(double) GetImageIndexInList(image));
cristy87528ea2009-09-10 14:53:56 +00003900 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +00003901 cache_info->rows=image->rows;
3902 cache_info->columns=image->columns;
3903 cache_info->active_index_channel=((image->storage_class == PseudoClass) ||
3904 (image->colorspace == CMYKColorspace)) ? MagickTrue : MagickFalse;
cristy73724512010-04-12 14:43:14 +00003905 if (image->ping != MagickFalse)
3906 {
3907 cache_info->storage_class=image->storage_class;
3908 cache_info->colorspace=image->colorspace;
3909 cache_info->type=PingCache;
3910 cache_info->pixels=(PixelPacket *) NULL;
3911 cache_info->indexes=(IndexPacket *) NULL;
3912 cache_info->length=0;
3913 return(MagickTrue);
3914 }
cristy3ed852e2009-09-05 21:47:34 +00003915 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3916 packet_size=sizeof(PixelPacket);
3917 if (cache_info->active_index_channel != MagickFalse)
3918 packet_size+=sizeof(IndexPacket);
3919 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00003920 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00003921 if (cache_info->columns != columns)
3922 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3923 image->filename);
3924 cache_info->length=length;
3925 status=AcquireMagickResource(AreaResource,cache_info->length);
3926 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
3927 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3928 {
3929 status=AcquireMagickResource(MemoryResource,cache_info->length);
3930 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3931 (cache_info->type == MemoryCache))
3932 {
cristyd43a46b2010-01-21 02:13:41 +00003933 AllocatePixelCachePixels(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00003934 if (cache_info->pixels == (PixelPacket *) NULL)
3935 cache_info->pixels=source_info.pixels;
3936 else
3937 {
3938 /*
3939 Create memory pixel cache.
3940 */
3941 if (image->debug != MagickFalse)
3942 {
cristy97e7a572009-12-05 15:07:53 +00003943 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00003944 format);
cristy3ed852e2009-09-05 21:47:34 +00003945 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00003946 "open %s (%s memory, %.20gx%.20g %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003947 cache_info->mapped != MagickFalse ? "anonymous" : "heap",
cristye8c25f92010-06-03 00:53:06 +00003948 (double) cache_info->columns,(double) cache_info->rows,
3949 format);
cristy3ed852e2009-09-05 21:47:34 +00003950 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3951 message);
3952 }
3953 cache_info->storage_class=image->storage_class;
3954 cache_info->colorspace=image->colorspace;
3955 cache_info->type=MemoryCache;
3956 cache_info->indexes=(IndexPacket *) NULL;
3957 if (cache_info->active_index_channel != MagickFalse)
3958 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
3959 number_pixels);
3960 if (source_info.storage_class != UndefinedClass)
3961 {
3962 status|=ClonePixelCachePixels(cache_info,&source_info,
3963 exception);
3964 RelinquishPixelCachePixels(&source_info);
3965 }
3966 return(MagickTrue);
3967 }
3968 }
3969 RelinquishMagickResource(MemoryResource,cache_info->length);
3970 }
3971 /*
3972 Create pixel cache on disk.
3973 */
3974 status=AcquireMagickResource(DiskResource,cache_info->length);
3975 if (status == MagickFalse)
3976 {
3977 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3978 "CacheResourcesExhausted","`%s'",image->filename);
3979 return(MagickFalse);
3980 }
3981 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3982 {
3983 RelinquishMagickResource(DiskResource,cache_info->length);
3984 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3985 image->filename);
3986 return(MagickFalse);
3987 }
3988 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
3989 cache_info->length);
3990 if (status == MagickFalse)
3991 {
3992 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3993 image->filename);
3994 return(MagickFalse);
3995 }
3996 cache_info->storage_class=image->storage_class;
3997 cache_info->colorspace=image->colorspace;
3998 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
3999 status=AcquireMagickResource(AreaResource,cache_info->length);
4000 if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4001 cache_info->type=DiskCache;
4002 else
4003 {
4004 status=AcquireMagickResource(MapResource,cache_info->length);
4005 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4006 (cache_info->type != MemoryCache))
4007 cache_info->type=DiskCache;
4008 else
4009 {
4010 cache_info->pixels=(PixelPacket *) MapBlob(cache_info->file,mode,
4011 cache_info->offset,(size_t) cache_info->length);
4012 if (cache_info->pixels == (PixelPacket *) NULL)
4013 {
4014 cache_info->pixels=source_info.pixels;
4015 cache_info->type=DiskCache;
4016 }
4017 else
4018 {
4019 /*
4020 Create file-backed memory-mapped pixel cache.
4021 */
4022 (void) ClosePixelCacheOnDisk(cache_info);
4023 cache_info->type=MapCache;
4024 cache_info->mapped=MagickTrue;
4025 cache_info->indexes=(IndexPacket *) NULL;
4026 if (cache_info->active_index_channel != MagickFalse)
4027 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4028 number_pixels);
4029 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4030 {
4031 status=ClonePixelCachePixels(cache_info,&source_info,
4032 exception);
4033 RelinquishPixelCachePixels(&source_info);
4034 }
4035 if (image->debug != MagickFalse)
4036 {
cristy97e7a572009-12-05 15:07:53 +00004037 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004038 format);
cristy3ed852e2009-09-05 21:47:34 +00004039 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004040 "open %s (%s[%d], memory-mapped, %.20gx%.20g %sB)",
cristy3ed852e2009-09-05 21:47:34 +00004041 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004042 cache_info->file,(double) cache_info->columns,(double)
4043 cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004044 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4045 message);
4046 }
4047 return(MagickTrue);
4048 }
4049 }
4050 RelinquishMagickResource(MapResource,cache_info->length);
4051 }
4052 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4053 {
4054 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4055 RelinquishPixelCachePixels(&source_info);
4056 }
4057 if (image->debug != MagickFalse)
4058 {
cristyb9080c92009-12-01 20:13:26 +00004059 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00004060 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004061 "open %s (%s[%d], disk, %.20gx%.20g %sB)",cache_info->filename,
4062 cache_info->cache_filename,cache_info->file,(double)
4063 cache_info->columns,(double) cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004064 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4065 }
4066 return(MagickTrue);
4067}
4068
4069/*
4070%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4071% %
4072% %
4073% %
4074+ P e r s i s t P i x e l C a c h e %
4075% %
4076% %
4077% %
4078%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4079%
4080% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4081% persistent pixel cache is one that resides on disk and is not destroyed
4082% when the program exits.
4083%
4084% The format of the PersistPixelCache() method is:
4085%
4086% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4087% const MagickBooleanType attach,MagickOffsetType *offset,
4088% ExceptionInfo *exception)
4089%
4090% A description of each parameter follows:
4091%
4092% o image: the image.
4093%
4094% o filename: the persistent pixel cache filename.
4095%
cristy01b7eb02009-09-10 23:10:14 +00004096% o attach: A value other than zero initializes the persistent pixel
4097% cache.
4098%
cristy3ed852e2009-09-05 21:47:34 +00004099% o initialize: A value other than zero initializes the persistent pixel
4100% cache.
4101%
4102% o offset: the offset in the persistent cache to store pixels.
4103%
4104% o exception: return any errors or warnings in this structure.
4105%
4106*/
4107MagickExport MagickBooleanType PersistPixelCache(Image *image,
4108 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4109 ExceptionInfo *exception)
4110{
4111 CacheInfo
4112 *cache_info,
4113 *clone_info;
4114
4115 Image
4116 clone_image;
4117
cristy3ed852e2009-09-05 21:47:34 +00004118 MagickBooleanType
4119 status;
4120
cristye076a6e2010-08-15 19:59:43 +00004121 ssize_t
4122 page_size;
4123
cristy3ed852e2009-09-05 21:47:34 +00004124 assert(image != (Image *) NULL);
4125 assert(image->signature == MagickSignature);
4126 if (image->debug != MagickFalse)
4127 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4128 assert(image->cache != (void *) NULL);
4129 assert(filename != (const char *) NULL);
4130 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004131 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004132 cache_info=(CacheInfo *) image->cache;
4133 assert(cache_info->signature == MagickSignature);
4134 if (attach != MagickFalse)
4135 {
4136 /*
cristy01b7eb02009-09-10 23:10:14 +00004137 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004138 */
4139 if (image->debug != MagickFalse)
4140 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4141 "attach persistent cache");
4142 (void) CopyMagickString(cache_info->cache_filename,filename,
4143 MaxTextExtent);
4144 cache_info->type=DiskCache;
4145 cache_info->offset=(*offset);
4146 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4147 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004148 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004149 return(MagickTrue);
4150 }
cristy01b7eb02009-09-10 23:10:14 +00004151 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4152 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004153 {
cristyf84a1932010-01-03 18:00:18 +00004154 LockSemaphoreInfo(cache_info->semaphore);
cristy09449f72010-01-23 03:08:36 +00004155 if ((cache_info->mode != ReadMode) &&
4156 (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004157 (cache_info->reference_count == 1))
4158 {
4159 int
4160 status;
4161
4162 /*
cristy01b7eb02009-09-10 23:10:14 +00004163 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004164 */
4165 status=rename(cache_info->cache_filename,filename);
4166 if (status == 0)
4167 {
4168 (void) CopyMagickString(cache_info->cache_filename,filename,
4169 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004170 *offset+=cache_info->length+page_size-(cache_info->length %
4171 page_size);
cristyf84a1932010-01-03 18:00:18 +00004172 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004173 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004174 if (image->debug != MagickFalse)
4175 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4176 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004177 return(MagickTrue);
4178 }
4179 }
cristyf84a1932010-01-03 18:00:18 +00004180 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004181 }
4182 /*
cristy01b7eb02009-09-10 23:10:14 +00004183 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004184 */
4185 clone_image=(*image);
4186 clone_info=(CacheInfo *) clone_image.cache;
4187 image->cache=ClonePixelCache(cache_info);
4188 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4189 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4190 cache_info->type=DiskCache;
4191 cache_info->offset=(*offset);
4192 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004193 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004194 if (status != MagickFalse)
cristyabd6e372010-09-15 19:11:26 +00004195 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
cristy688f07b2009-09-27 15:19:13 +00004196 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004197 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4198 return(status);
4199}
4200
4201/*
4202%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4203% %
4204% %
4205% %
4206+ Q u e u e A u t h e n t i c N e x u s %
4207% %
4208% %
4209% %
4210%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4211%
4212% QueueAuthenticNexus() allocates an region to store image pixels as defined
4213% by the region rectangle and returns a pointer to the region. This region is
4214% subsequently transferred from the pixel cache with
4215% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4216% pixels are transferred, otherwise a NULL is returned.
4217%
4218% The format of the QueueAuthenticNexus() method is:
4219%
cristy5f959472010-05-27 22:19:46 +00004220% PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
4221% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004222% NexusInfo *nexus_info,ExceptionInfo *exception)
4223%
4224% A description of each parameter follows:
4225%
4226% o image: the image.
4227%
4228% o x,y,columns,rows: These values define the perimeter of a region of
4229% pixels.
4230%
4231% o nexus_info: the cache nexus to set.
4232%
4233% o exception: return any errors or warnings in this structure.
4234%
4235*/
cristybb503372010-05-27 20:51:26 +00004236MagickExport PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy30097232010-07-01 02:16:30 +00004237 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
4238 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004239{
4240 CacheInfo
4241 *cache_info;
4242
4243 MagickOffsetType
4244 offset;
4245
4246 MagickSizeType
4247 number_pixels;
4248
4249 RectangleInfo
4250 region;
4251
4252 /*
4253 Validate pixel cache geometry.
4254 */
cristy77ff0282010-09-13 00:51:10 +00004255 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
4256 if (cache_info == (Cache) NULL)
4257 return((PixelPacket *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004258 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4259 {
4260 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4261 "NoPixelsDefinedInCache","`%s'",image->filename);
4262 return((PixelPacket *) NULL);
4263 }
cristybb503372010-05-27 20:51:26 +00004264 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4265 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004266 {
4267 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4268 "PixelsAreNotAuthentic","`%s'",image->filename);
4269 return((PixelPacket *) NULL);
4270 }
4271 offset=(MagickOffsetType) y*cache_info->columns+x;
4272 if (offset < 0)
4273 return((PixelPacket *) NULL);
4274 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4275 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4276 if ((MagickSizeType) offset >= number_pixels)
4277 return((PixelPacket *) NULL);
4278 /*
4279 Return pixel cache.
4280 */
4281 region.x=x;
4282 region.y=y;
4283 region.width=columns;
4284 region.height=rows;
4285 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4286}
4287
4288/*
4289%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4290% %
4291% %
4292% %
4293+ 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 %
4294% %
4295% %
4296% %
4297%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4298%
4299% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4300% defined by the region rectangle and returns a pointer to the region. This
4301% region is subsequently transferred from the pixel cache with
4302% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4303% pixels are transferred, otherwise a NULL is returned.
4304%
4305% The format of the QueueAuthenticPixelsCache() method is:
4306%
cristybb503372010-05-27 20:51:26 +00004307% PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4308% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004309% ExceptionInfo *exception)
4310%
4311% A description of each parameter follows:
4312%
4313% o image: the image.
4314%
4315% o x,y,columns,rows: These values define the perimeter of a region of
4316% pixels.
4317%
4318% o exception: return any errors or warnings in this structure.
4319%
4320*/
cristybb503372010-05-27 20:51:26 +00004321static PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4322 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004323 ExceptionInfo *exception)
4324{
4325 CacheInfo
4326 *cache_info;
4327
cristy5c9e6f22010-09-17 17:31:01 +00004328 const int
4329 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004330
cristy77ff0282010-09-13 00:51:10 +00004331 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00004332 if (cache_info == (Cache) NULL)
4333 return((PixelPacket *) NULL);
cristy6ebe97c2010-07-03 01:17:28 +00004334 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00004335 return(QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4336 exception));
cristy3ed852e2009-09-05 21:47:34 +00004337}
4338
4339/*
4340%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4341% %
4342% %
4343% %
4344% Q u e u e A u t h e n t i c P i x e l s %
4345% %
4346% %
4347% %
4348%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4349%
4350% QueueAuthenticPixels() queues a mutable pixel region. If the region is
4351% successfully intialized a pointer to a PixelPacket array representing the
4352% region is returned, otherwise NULL is returned. The returned pointer may
4353% point to a temporary working buffer for the pixels or it may point to the
4354% final location of the pixels in memory.
4355%
4356% Write-only access means that any existing pixel values corresponding to
4357% the region are ignored. This is useful if the initial image is being
4358% created from scratch, or if the existing pixel values are to be
4359% completely replaced without need to refer to their pre-existing values.
4360% The application is free to read and write the pixel buffer returned by
4361% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4362% initialize the pixel array values. Initializing pixel array values is the
4363% application's responsibility.
4364%
4365% Performance is maximized if the selected region is part of one row, or
4366% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004367% pixels in-place (without a copy) if the image is in memory, or in a
4368% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004369% by the user.
4370%
4371% Pixels accessed via the returned pointer represent a simple array of type
4372% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
4373% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
4374% the black color component or the colormap indexes (of type IndexPacket)
4375% corresponding to the region. Once the PixelPacket (and/or IndexPacket)
4376% array has been updated, the changes must be saved back to the underlying
4377% image using SyncAuthenticPixels() or they may be lost.
4378%
4379% The format of the QueueAuthenticPixels() method is:
4380%
cristy5f959472010-05-27 22:19:46 +00004381% PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4382% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004383% ExceptionInfo *exception)
4384%
4385% A description of each parameter follows:
4386%
4387% o image: the image.
4388%
4389% o x,y,columns,rows: These values define the perimeter of a region of
4390% pixels.
4391%
4392% o exception: return any errors or warnings in this structure.
4393%
4394*/
cristybb503372010-05-27 20:51:26 +00004395MagickExport PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4396 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004397 ExceptionInfo *exception)
4398{
4399 CacheInfo
4400 *cache_info;
4401
cristy3ed852e2009-09-05 21:47:34 +00004402 assert(image != (Image *) NULL);
4403 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004404 assert(image->cache != (Cache) NULL);
4405 cache_info=(CacheInfo *) image->cache;
4406 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004407 if (cache_info->methods.queue_authentic_pixels_handler !=
4408 (QueueAuthenticPixelsHandler) NULL)
4409 return(cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4410 rows,exception));
4411 return(QueueAuthenticPixelsCache(image,x,y,columns,rows,exception));
cristy3ed852e2009-09-05 21:47:34 +00004412}
4413
4414/*
4415%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4416% %
4417% %
4418% %
4419+ R e a d P i x e l C a c h e I n d e x e s %
4420% %
4421% %
4422% %
4423%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4424%
4425% ReadPixelCacheIndexes() reads colormap indexes from the specified region of
4426% the pixel cache.
4427%
4428% The format of the ReadPixelCacheIndexes() method is:
4429%
4430% MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4431% NexusInfo *nexus_info,ExceptionInfo *exception)
4432%
4433% A description of each parameter follows:
4434%
4435% o cache_info: the pixel cache.
4436%
4437% o nexus_info: the cache nexus to read the colormap indexes.
4438%
4439% o exception: return any errors or warnings in this structure.
4440%
4441*/
4442static MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4443 NexusInfo *nexus_info,ExceptionInfo *exception)
4444{
4445 MagickOffsetType
4446 count,
4447 offset;
4448
4449 MagickSizeType
4450 length,
4451 number_pixels;
4452
4453 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004454 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004455
cristybb503372010-05-27 20:51:26 +00004456 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004457 y;
4458
cristybb503372010-05-27 20:51:26 +00004459 size_t
cristy3ed852e2009-09-05 21:47:34 +00004460 rows;
4461
cristy3ed852e2009-09-05 21:47:34 +00004462 if (cache_info->active_index_channel == MagickFalse)
4463 return(MagickFalse);
4464 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4465 return(MagickTrue);
4466 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4467 nexus_info->region.x;
4468 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
4469 rows=nexus_info->region.height;
4470 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004471 q=nexus_info->indexes;
4472 switch (cache_info->type)
4473 {
4474 case MemoryCache:
4475 case MapCache:
4476 {
4477 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004478 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004479
4480 /*
4481 Read indexes from memory.
4482 */
cristydd341db2010-03-04 19:06:38 +00004483 if ((cache_info->columns == nexus_info->region.width) &&
4484 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4485 {
4486 length=number_pixels;
4487 rows=1UL;
4488 }
cristy3ed852e2009-09-05 21:47:34 +00004489 p=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00004490 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004491 {
4492 (void) CopyMagickMemory(q,p,(size_t) length);
4493 p+=cache_info->columns;
4494 q+=nexus_info->region.width;
4495 }
4496 break;
4497 }
4498 case DiskCache:
4499 {
4500 /*
4501 Read indexes from disk.
4502 */
4503 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4504 {
4505 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4506 cache_info->cache_filename);
4507 return(MagickFalse);
4508 }
cristydd341db2010-03-04 19:06:38 +00004509 if ((cache_info->columns == nexus_info->region.width) &&
4510 (number_pixels < MagickMaxBufferExtent))
4511 {
4512 length=number_pixels;
4513 rows=1UL;
4514 }
cristy3ed852e2009-09-05 21:47:34 +00004515 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004516 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004517 {
4518 count=ReadPixelCacheRegion(cache_info,cache_info->offset+number_pixels*
4519 sizeof(PixelPacket)+offset*sizeof(*q),length,(unsigned char *) q);
4520 if ((MagickSizeType) count < length)
4521 break;
4522 offset+=cache_info->columns;
4523 q+=nexus_info->region.width;
4524 }
cristybb503372010-05-27 20:51:26 +00004525 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004526 {
4527 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4528 cache_info->cache_filename);
4529 return(MagickFalse);
4530 }
4531 break;
4532 }
4533 default:
4534 break;
4535 }
4536 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004537 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004538 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004539 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004540 nexus_info->region.width,(double) nexus_info->region.height,(double)
4541 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004542 return(MagickTrue);
4543}
4544
4545/*
4546%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4547% %
4548% %
4549% %
4550+ R e a d P i x e l C a c h e P i x e l s %
4551% %
4552% %
4553% %
4554%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4555%
4556% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4557% cache.
4558%
4559% The format of the ReadPixelCachePixels() method is:
4560%
4561% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4562% NexusInfo *nexus_info,ExceptionInfo *exception)
4563%
4564% A description of each parameter follows:
4565%
4566% o cache_info: the pixel cache.
4567%
4568% o nexus_info: the cache nexus to read the pixels.
4569%
4570% o exception: return any errors or warnings in this structure.
4571%
4572*/
4573static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4574 NexusInfo *nexus_info,ExceptionInfo *exception)
4575{
4576 MagickOffsetType
4577 count,
4578 offset;
4579
4580 MagickSizeType
4581 length,
4582 number_pixels;
4583
cristy3ed852e2009-09-05 21:47:34 +00004584 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004585 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004586
cristye076a6e2010-08-15 19:59:43 +00004587 register ssize_t
4588 y;
4589
cristybb503372010-05-27 20:51:26 +00004590 size_t
cristy3ed852e2009-09-05 21:47:34 +00004591 rows;
4592
cristy3ed852e2009-09-05 21:47:34 +00004593 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4594 return(MagickTrue);
4595 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4596 nexus_info->region.x;
4597 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
4598 rows=nexus_info->region.height;
4599 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004600 q=nexus_info->pixels;
4601 switch (cache_info->type)
4602 {
4603 case MemoryCache:
4604 case MapCache:
4605 {
4606 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004607 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004608
4609 /*
4610 Read pixels from memory.
4611 */
cristydd341db2010-03-04 19:06:38 +00004612 if ((cache_info->columns == nexus_info->region.width) &&
4613 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4614 {
4615 length=number_pixels;
4616 rows=1UL;
4617 }
cristy3ed852e2009-09-05 21:47:34 +00004618 p=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00004619 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004620 {
4621 (void) CopyMagickMemory(q,p,(size_t) length);
4622 p+=cache_info->columns;
4623 q+=nexus_info->region.width;
4624 }
4625 break;
4626 }
4627 case DiskCache:
4628 {
4629 /*
4630 Read pixels from disk.
4631 */
4632 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4633 {
4634 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4635 cache_info->cache_filename);
4636 return(MagickFalse);
4637 }
cristydd341db2010-03-04 19:06:38 +00004638 if ((cache_info->columns == nexus_info->region.width) &&
4639 (number_pixels < MagickMaxBufferExtent))
4640 {
4641 length=number_pixels;
4642 rows=1UL;
4643 }
cristybb503372010-05-27 20:51:26 +00004644 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004645 {
4646 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4647 sizeof(*q),length,(unsigned char *) q);
4648 if ((MagickSizeType) count < length)
4649 break;
4650 offset+=cache_info->columns;
4651 q+=nexus_info->region.width;
4652 }
cristybb503372010-05-27 20:51:26 +00004653 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004654 {
4655 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4656 cache_info->cache_filename);
4657 return(MagickFalse);
4658 }
4659 break;
4660 }
4661 default:
4662 break;
4663 }
4664 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004665 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004666 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004667 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004668 nexus_info->region.width,(double) nexus_info->region.height,(double)
4669 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004670 return(MagickTrue);
4671}
4672
4673/*
4674%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4675% %
4676% %
4677% %
4678+ R e f e r e n c e P i x e l C a c h e %
4679% %
4680% %
4681% %
4682%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4683%
4684% ReferencePixelCache() increments the reference count associated with the
4685% pixel cache returning a pointer to the cache.
4686%
4687% The format of the ReferencePixelCache method is:
4688%
4689% Cache ReferencePixelCache(Cache cache_info)
4690%
4691% A description of each parameter follows:
4692%
4693% o cache_info: the pixel cache.
4694%
4695*/
4696MagickExport Cache ReferencePixelCache(Cache cache)
4697{
4698 CacheInfo
4699 *cache_info;
4700
4701 assert(cache != (Cache *) NULL);
4702 cache_info=(CacheInfo *) cache;
4703 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004704 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004705 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004706 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004707 return(cache_info);
4708}
4709
4710/*
4711%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4712% %
4713% %
4714% %
4715+ S e t P i x e l C a c h e M e t h o d s %
4716% %
4717% %
4718% %
4719%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4720%
4721% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4722%
4723% The format of the SetPixelCacheMethods() method is:
4724%
4725% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4726%
4727% A description of each parameter follows:
4728%
4729% o cache: the pixel cache.
4730%
4731% o cache_methods: Specifies a pointer to a CacheMethods structure.
4732%
4733*/
4734MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4735{
4736 CacheInfo
4737 *cache_info;
4738
4739 GetOneAuthenticPixelFromHandler
4740 get_one_authentic_pixel_from_handler;
4741
4742 GetOneVirtualPixelFromHandler
4743 get_one_virtual_pixel_from_handler;
4744
4745 /*
4746 Set cache pixel methods.
4747 */
4748 assert(cache != (Cache) NULL);
4749 assert(cache_methods != (CacheMethods *) NULL);
4750 cache_info=(CacheInfo *) cache;
4751 assert(cache_info->signature == MagickSignature);
4752 if (cache_info->debug != MagickFalse)
4753 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4754 cache_info->filename);
4755 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4756 cache_info->methods.get_virtual_pixel_handler=
4757 cache_methods->get_virtual_pixel_handler;
4758 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4759 cache_info->methods.destroy_pixel_handler=
4760 cache_methods->destroy_pixel_handler;
4761 if (cache_methods->get_virtual_indexes_from_handler !=
4762 (GetVirtualIndexesFromHandler) NULL)
4763 cache_info->methods.get_virtual_indexes_from_handler=
4764 cache_methods->get_virtual_indexes_from_handler;
4765 if (cache_methods->get_authentic_pixels_handler !=
4766 (GetAuthenticPixelsHandler) NULL)
4767 cache_info->methods.get_authentic_pixels_handler=
4768 cache_methods->get_authentic_pixels_handler;
4769 if (cache_methods->queue_authentic_pixels_handler !=
4770 (QueueAuthenticPixelsHandler) NULL)
4771 cache_info->methods.queue_authentic_pixels_handler=
4772 cache_methods->queue_authentic_pixels_handler;
4773 if (cache_methods->sync_authentic_pixels_handler !=
4774 (SyncAuthenticPixelsHandler) NULL)
4775 cache_info->methods.sync_authentic_pixels_handler=
4776 cache_methods->sync_authentic_pixels_handler;
4777 if (cache_methods->get_authentic_pixels_from_handler !=
4778 (GetAuthenticPixelsFromHandler) NULL)
4779 cache_info->methods.get_authentic_pixels_from_handler=
4780 cache_methods->get_authentic_pixels_from_handler;
4781 if (cache_methods->get_authentic_indexes_from_handler !=
4782 (GetAuthenticIndexesFromHandler) NULL)
4783 cache_info->methods.get_authentic_indexes_from_handler=
4784 cache_methods->get_authentic_indexes_from_handler;
4785 get_one_virtual_pixel_from_handler=
4786 cache_info->methods.get_one_virtual_pixel_from_handler;
4787 if (get_one_virtual_pixel_from_handler !=
4788 (GetOneVirtualPixelFromHandler) NULL)
4789 cache_info->methods.get_one_virtual_pixel_from_handler=
4790 cache_methods->get_one_virtual_pixel_from_handler;
4791 get_one_authentic_pixel_from_handler=
4792 cache_methods->get_one_authentic_pixel_from_handler;
4793 if (get_one_authentic_pixel_from_handler !=
4794 (GetOneAuthenticPixelFromHandler) NULL)
4795 cache_info->methods.get_one_authentic_pixel_from_handler=
4796 cache_methods->get_one_authentic_pixel_from_handler;
4797}
4798
4799/*
4800%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4801% %
4802% %
4803% %
4804+ S e t P i x e l C a c h e N e x u s P i x e l s %
4805% %
4806% %
4807% %
4808%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4809%
4810% SetPixelCacheNexusPixels() defines the region of the cache for the
4811% specified cache nexus.
4812%
4813% The format of the SetPixelCacheNexusPixels() method is:
4814%
4815% PixelPacket SetPixelCacheNexusPixels(const Image *image,
4816% const RectangleInfo *region,NexusInfo *nexus_info,
4817% ExceptionInfo *exception)
4818%
4819% A description of each parameter follows:
4820%
4821% o image: the image.
4822%
4823% o region: A pointer to the RectangleInfo structure that defines the
4824% region of this particular cache nexus.
4825%
4826% o nexus_info: the cache nexus to set.
4827%
4828% o exception: return any errors or warnings in this structure.
4829%
4830*/
cristyabd6e372010-09-15 19:11:26 +00004831
4832static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4833 NexusInfo *nexus_info,ExceptionInfo *exception)
4834{
4835 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4836 return(MagickFalse);
4837 nexus_info->mapped=MagickFalse;
4838 nexus_info->cache=(PixelPacket *) AcquireMagickMemory((size_t)
4839 nexus_info->length);
4840 if (nexus_info->cache == (PixelPacket *) NULL)
4841 {
4842 nexus_info->mapped=MagickTrue;
4843 nexus_info->cache=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
4844 nexus_info->length);
4845 }
4846 if (nexus_info->cache == (PixelPacket *) NULL)
4847 {
4848 (void) ThrowMagickException(exception,GetMagickModule(),
4849 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4850 cache_info->filename);
4851 return(MagickFalse);
4852 }
4853 return(MagickTrue);
4854}
4855
cristy3ed852e2009-09-05 21:47:34 +00004856static PixelPacket *SetPixelCacheNexusPixels(const Image *image,
4857 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4858{
4859 CacheInfo
4860 *cache_info;
4861
4862 MagickBooleanType
4863 status;
4864
cristy3ed852e2009-09-05 21:47:34 +00004865 MagickSizeType
4866 length,
4867 number_pixels;
4868
cristy3ed852e2009-09-05 21:47:34 +00004869 cache_info=(CacheInfo *) image->cache;
4870 assert(cache_info->signature == MagickSignature);
4871 if (cache_info->type == UndefinedCache)
4872 return((PixelPacket *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00004873 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00004874 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
4875 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00004876 {
cristybb503372010-05-27 20:51:26 +00004877 ssize_t
cristybad067a2010-02-15 17:20:55 +00004878 x,
4879 y;
cristy3ed852e2009-09-05 21:47:34 +00004880
cristyeaedf062010-05-29 22:36:02 +00004881 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4882 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00004883 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4884 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00004885 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00004886 ((nexus_info->region.width == cache_info->columns) ||
4887 ((nexus_info->region.width % cache_info->columns) == 0)))))
4888 {
4889 MagickOffsetType
4890 offset;
4891
4892 /*
4893 Pixels are accessed directly from memory.
4894 */
4895 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4896 nexus_info->region.x;
4897 nexus_info->pixels=cache_info->pixels+offset;
4898 nexus_info->indexes=(IndexPacket *) NULL;
4899 if (cache_info->active_index_channel != MagickFalse)
4900 nexus_info->indexes=cache_info->indexes+offset;
4901 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00004902 }
4903 }
4904 /*
4905 Pixels are stored in a cache region until they are synced to the cache.
4906 */
4907 number_pixels=(MagickSizeType) nexus_info->region.width*
4908 nexus_info->region.height;
4909 length=number_pixels*sizeof(PixelPacket);
4910 if (cache_info->active_index_channel != MagickFalse)
4911 length+=number_pixels*sizeof(IndexPacket);
4912 if (nexus_info->cache == (PixelPacket *) NULL)
4913 {
4914 nexus_info->length=length;
4915 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4916 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004917 {
4918 nexus_info->length=0;
4919 return((PixelPacket *) NULL);
4920 }
cristy3ed852e2009-09-05 21:47:34 +00004921 }
4922 else
4923 if (nexus_info->length != length)
4924 {
4925 RelinquishCacheNexusPixels(nexus_info);
4926 nexus_info->length=length;
4927 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4928 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004929 {
4930 nexus_info->length=0;
4931 return((PixelPacket *) NULL);
4932 }
cristy3ed852e2009-09-05 21:47:34 +00004933 }
4934 nexus_info->pixels=nexus_info->cache;
4935 nexus_info->indexes=(IndexPacket *) NULL;
4936 if (cache_info->active_index_channel != MagickFalse)
4937 nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
4938 return(nexus_info->pixels);
4939}
4940
4941/*
4942%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4943% %
4944% %
4945% %
4946% 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 %
4947% %
4948% %
4949% %
4950%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4951%
4952% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4953% pixel cache and returns the previous setting. A virtual pixel is any pixel
4954% access that is outside the boundaries of the image cache.
4955%
4956% The format of the SetPixelCacheVirtualMethod() method is:
4957%
4958% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
4959% const VirtualPixelMethod virtual_pixel_method)
4960%
4961% A description of each parameter follows:
4962%
4963% o image: the image.
4964%
4965% o virtual_pixel_method: choose the type of virtual pixel.
4966%
4967*/
4968MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
4969 const VirtualPixelMethod virtual_pixel_method)
4970{
4971 CacheInfo
4972 *cache_info;
4973
4974 VirtualPixelMethod
4975 method;
4976
4977 assert(image != (Image *) NULL);
4978 assert(image->signature == MagickSignature);
4979 if (image->debug != MagickFalse)
4980 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4981 assert(image->cache != (Cache) NULL);
4982 cache_info=(CacheInfo *) image->cache;
4983 assert(cache_info->signature == MagickSignature);
4984 method=cache_info->virtual_pixel_method;
4985 cache_info->virtual_pixel_method=virtual_pixel_method;
4986 return(method);
4987}
4988
4989/*
4990%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4991% %
4992% %
4993% %
4994+ 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 %
4995% %
4996% %
4997% %
4998%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4999%
5000% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5001% in-memory or disk cache. The method returns MagickTrue if the pixel region
5002% is synced, otherwise MagickFalse.
5003%
5004% The format of the SyncAuthenticPixelCacheNexus() method is:
5005%
5006% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5007% NexusInfo *nexus_info,ExceptionInfo *exception)
5008%
5009% A description of each parameter follows:
5010%
5011% o image: the image.
5012%
5013% o nexus_info: the cache nexus to sync.
5014%
5015% o exception: return any errors or warnings in this structure.
5016%
5017*/
5018MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5019 NexusInfo *nexus_info,ExceptionInfo *exception)
5020{
5021 CacheInfo
5022 *cache_info;
5023
5024 MagickBooleanType
5025 status;
5026
5027 /*
5028 Transfer pixels to the cache.
5029 */
5030 assert(image != (Image *) NULL);
5031 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005032 if (image->cache == (Cache) NULL)
5033 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5034 cache_info=(CacheInfo *) image->cache;
5035 if (cache_info->type == UndefinedCache)
5036 return(MagickFalse);
5037 if ((image->clip_mask != (Image *) NULL) &&
5038 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5039 return(MagickFalse);
5040 if ((image->mask != (Image *) NULL) &&
5041 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5042 return(MagickFalse);
5043 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5044 return(MagickTrue);
5045 assert(cache_info->signature == MagickSignature);
5046 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5047 if ((cache_info->active_index_channel != MagickFalse) &&
5048 (WritePixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse))
5049 return(MagickFalse);
5050 return(status);
5051}
5052
5053/*
5054%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5055% %
5056% %
5057% %
5058+ S y n c A u t h e n t i c P i x e l C a c h e %
5059% %
5060% %
5061% %
5062%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5063%
5064% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5065% or disk cache. The method returns MagickTrue if the pixel region is synced,
5066% otherwise MagickFalse.
5067%
5068% The format of the SyncAuthenticPixelsCache() method is:
5069%
5070% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5071% ExceptionInfo *exception)
5072%
5073% A description of each parameter follows:
5074%
5075% o image: the image.
5076%
5077% o exception: return any errors or warnings in this structure.
5078%
5079*/
5080static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5081 ExceptionInfo *exception)
5082{
5083 CacheInfo
5084 *cache_info;
5085
cristy5c9e6f22010-09-17 17:31:01 +00005086 const int
5087 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005088
cristy3ed852e2009-09-05 21:47:34 +00005089 cache_info=(CacheInfo *) image->cache;
cristy6ebe97c2010-07-03 01:17:28 +00005090 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00005091 return(SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5092 exception));
cristy3ed852e2009-09-05 21:47:34 +00005093}
5094
5095/*
5096%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5097% %
5098% %
5099% %
5100% S y n c A u t h e n t i c P i x e l s %
5101% %
5102% %
5103% %
5104%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5105%
5106% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5107% The method returns MagickTrue if the pixel region is flushed, otherwise
5108% MagickFalse.
5109%
5110% The format of the SyncAuthenticPixels() method is:
5111%
5112% MagickBooleanType SyncAuthenticPixels(Image *image,
5113% ExceptionInfo *exception)
5114%
5115% A description of each parameter follows:
5116%
5117% o image: the image.
5118%
5119% o exception: return any errors or warnings in this structure.
5120%
5121*/
5122MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5123 ExceptionInfo *exception)
5124{
5125 CacheInfo
5126 *cache_info;
5127
5128 assert(image != (Image *) NULL);
5129 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005130 assert(image->cache != (Cache) NULL);
5131 cache_info=(CacheInfo *) image->cache;
5132 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005133 if (cache_info->methods.sync_authentic_pixels_handler !=
5134 (SyncAuthenticPixelsHandler) NULL)
5135 return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
5136 return(SyncAuthenticPixelsCache(image,exception));
cristy3ed852e2009-09-05 21:47:34 +00005137}
5138
5139/*
5140%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5141% %
5142% %
5143% %
5144+ W r i t e P i x e l C a c h e I n d e x e s %
5145% %
5146% %
5147% %
5148%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5149%
5150% WritePixelCacheIndexes() writes the colormap indexes to the specified
5151% region of the pixel cache.
5152%
5153% The format of the WritePixelCacheIndexes() method is:
5154%
5155% MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5156% NexusInfo *nexus_info,ExceptionInfo *exception)
5157%
5158% A description of each parameter follows:
5159%
5160% o cache_info: the pixel cache.
5161%
5162% o nexus_info: the cache nexus to write the colormap indexes.
5163%
5164% o exception: return any errors or warnings in this structure.
5165%
5166*/
5167static MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5168 NexusInfo *nexus_info,ExceptionInfo *exception)
5169{
5170 MagickOffsetType
5171 count,
5172 offset;
5173
5174 MagickSizeType
5175 length,
5176 number_pixels;
5177
5178 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005179 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005180
cristybb503372010-05-27 20:51:26 +00005181 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005182 y;
5183
cristybb503372010-05-27 20:51:26 +00005184 size_t
cristy3ed852e2009-09-05 21:47:34 +00005185 rows;
5186
cristy3ed852e2009-09-05 21:47:34 +00005187 if (cache_info->active_index_channel == MagickFalse)
5188 return(MagickFalse);
5189 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5190 return(MagickTrue);
5191 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5192 nexus_info->region.x;
5193 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
5194 rows=nexus_info->region.height;
5195 number_pixels=(MagickSizeType) length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005196 p=nexus_info->indexes;
5197 switch (cache_info->type)
5198 {
5199 case MemoryCache:
5200 case MapCache:
5201 {
5202 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005203 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005204
5205 /*
5206 Write indexes to memory.
5207 */
cristydd341db2010-03-04 19:06:38 +00005208 if ((cache_info->columns == nexus_info->region.width) &&
5209 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5210 {
5211 length=number_pixels;
5212 rows=1UL;
5213 }
cristy3ed852e2009-09-05 21:47:34 +00005214 q=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00005215 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005216 {
5217 (void) CopyMagickMemory(q,p,(size_t) length);
5218 p+=nexus_info->region.width;
5219 q+=cache_info->columns;
5220 }
5221 break;
5222 }
5223 case DiskCache:
5224 {
5225 /*
5226 Write indexes to disk.
5227 */
5228 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5229 {
5230 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5231 cache_info->cache_filename);
5232 return(MagickFalse);
5233 }
cristydd341db2010-03-04 19:06:38 +00005234 if ((cache_info->columns == nexus_info->region.width) &&
5235 (number_pixels < MagickMaxBufferExtent))
5236 {
5237 length=number_pixels;
5238 rows=1UL;
5239 }
cristy3ed852e2009-09-05 21:47:34 +00005240 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005241 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005242 {
5243 count=WritePixelCacheRegion(cache_info,cache_info->offset+number_pixels*
5244 sizeof(PixelPacket)+offset*sizeof(*p),length,
5245 (const unsigned char *) p);
5246 if ((MagickSizeType) count < length)
5247 break;
5248 p+=nexus_info->region.width;
5249 offset+=cache_info->columns;
5250 }
cristybb503372010-05-27 20:51:26 +00005251 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005252 {
5253 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5254 cache_info->cache_filename);
5255 return(MagickFalse);
5256 }
5257 break;
5258 }
5259 default:
5260 break;
5261 }
5262 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005263 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005264 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005265 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005266 nexus_info->region.width,(double) nexus_info->region.height,(double)
5267 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005268 return(MagickTrue);
5269}
5270
5271/*
5272%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5273% %
5274% %
5275% %
5276+ W r i t e C a c h e P i x e l s %
5277% %
5278% %
5279% %
5280%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5281%
5282% WritePixelCachePixels() writes image pixels to the specified region of the
5283% pixel cache.
5284%
5285% The format of the WritePixelCachePixels() method is:
5286%
5287% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5288% NexusInfo *nexus_info,ExceptionInfo *exception)
5289%
5290% A description of each parameter follows:
5291%
5292% o cache_info: the pixel cache.
5293%
5294% o nexus_info: the cache nexus to write the pixels.
5295%
5296% o exception: return any errors or warnings in this structure.
5297%
5298*/
5299static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5300 NexusInfo *nexus_info,ExceptionInfo *exception)
5301{
5302 MagickOffsetType
5303 count,
5304 offset;
5305
5306 MagickSizeType
5307 length,
5308 number_pixels;
5309
cristy3ed852e2009-09-05 21:47:34 +00005310 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005311 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005312
cristybb503372010-05-27 20:51:26 +00005313 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005314 y;
5315
cristybb503372010-05-27 20:51:26 +00005316 size_t
cristy3ed852e2009-09-05 21:47:34 +00005317 rows;
5318
cristy3ed852e2009-09-05 21:47:34 +00005319 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5320 return(MagickTrue);
5321 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5322 nexus_info->region.x;
5323 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
5324 rows=nexus_info->region.height;
5325 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005326 p=nexus_info->pixels;
5327 switch (cache_info->type)
5328 {
5329 case MemoryCache:
5330 case MapCache:
5331 {
5332 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005333 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005334
5335 /*
5336 Write pixels to memory.
5337 */
cristydd341db2010-03-04 19:06:38 +00005338 if ((cache_info->columns == nexus_info->region.width) &&
5339 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5340 {
5341 length=number_pixels;
5342 rows=1UL;
5343 }
cristy3ed852e2009-09-05 21:47:34 +00005344 q=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00005345 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005346 {
5347 (void) CopyMagickMemory(q,p,(size_t) length);
5348 p+=nexus_info->region.width;
5349 q+=cache_info->columns;
5350 }
5351 break;
5352 }
5353 case DiskCache:
5354 {
5355 /*
5356 Write pixels to disk.
5357 */
5358 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5359 {
5360 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5361 cache_info->cache_filename);
5362 return(MagickFalse);
5363 }
cristydd341db2010-03-04 19:06:38 +00005364 if ((cache_info->columns == nexus_info->region.width) &&
5365 (number_pixels < MagickMaxBufferExtent))
5366 {
5367 length=number_pixels;
5368 rows=1UL;
5369 }
cristybb503372010-05-27 20:51:26 +00005370 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005371 {
5372 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5373 sizeof(*p),length,(const unsigned char *) p);
5374 if ((MagickSizeType) count < length)
5375 break;
5376 p+=nexus_info->region.width;
5377 offset+=cache_info->columns;
5378 }
cristybb503372010-05-27 20:51:26 +00005379 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005380 {
5381 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5382 cache_info->cache_filename);
5383 return(MagickFalse);
5384 }
5385 break;
5386 }
5387 default:
5388 break;
5389 }
5390 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005391 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005392 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005393 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005394 nexus_info->region.width,(double) nexus_info->region.height,(double)
5395 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005396 return(MagickTrue);
5397}