blob: d1505fca49f0d383a4658c6aec3f1f6b1893f8c5 [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,
cristy0158a4b2010-09-20 13:59:45 +0000122 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);
cristy2036f5c2010-09-19 21:18:17 +0000448 indexes=GetPixelCacheNexusIndexes(cache_info,image_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +0000449 q=nexus_info->pixels;
450 nexus_indexes=nexus_info->indexes;
451 r=GetVirtualPixelsFromNexus(image->clip_mask,MaskVirtualPixelMethod,
452 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
453 nexus_info->region.height,clip_nexus[0],exception);
454 number_pixels=(MagickSizeType) nexus_info->region.width*
455 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +0000456 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000457 {
458 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
459 break;
460 if (PixelIntensityToQuantum(r) > ((Quantum) QuantumRange/2))
461 {
cristyce70c172010-01-07 17:15:30 +0000462 SetRedPixelComponent(q,GetRedPixelComponent(p));
463 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
464 SetBluePixelComponent(q,GetBluePixelComponent(p));
465 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
cristy3ed852e2009-09-05 21:47:34 +0000466 if (cache_info->active_index_channel != MagickFalse)
467 nexus_indexes[i]=indexes[i];
468 }
469 p++;
470 q++;
471 r++;
472 }
473 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
474 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +0000475 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +0000476 return(MagickFalse);
477 return(MagickTrue);
478}
479
480/*
481%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
482% %
483% %
484% %
485+ C l o n e P i x e l C a c h e %
486% %
487% %
488% %
489%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
490%
491% ClonePixelCache() clones a pixel cache.
492%
493% The format of the ClonePixelCache() method is:
494%
495% Cache ClonePixelCache(const Cache cache)
496%
497% A description of each parameter follows:
498%
499% o cache: the pixel cache.
500%
501*/
502MagickExport Cache ClonePixelCache(const Cache cache)
503{
504 CacheInfo
505 *clone_info;
506
507 const CacheInfo
508 *cache_info;
509
510 assert(cache != (const Cache) NULL);
511 cache_info=(const CacheInfo *) cache;
512 assert(cache_info->signature == MagickSignature);
513 if (cache_info->debug != MagickFalse)
514 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
515 cache_info->filename);
516 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
517 if (clone_info == (Cache) NULL)
518 return((Cache) NULL);
519 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
520 return((Cache ) clone_info);
521}
522
523/*
524%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
525% %
526% %
527% %
cristy60c44a82009-10-07 00:58:49 +0000528+ C l o n e P i x e l C a c h e P i x e l s %
cristy3ed852e2009-09-05 21:47:34 +0000529% %
530% %
531% %
532%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
533% ClonePixelCachePixels() clones the source pixel cache to the destination
534% cache.
535%
536% The format of the ClonePixelCachePixels() method is:
537%
538% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
539% CacheInfo *source_info,ExceptionInfo *exception)
540%
541% A description of each parameter follows:
542%
543% o cache_info: the pixel cache.
544%
545% o source_info: the source pixel cache.
546%
547% o exception: return any errors or warnings in this structure.
548%
549*/
550
551static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
552{
553 int
554 status;
555
cristy5ee247a2010-02-12 15:42:34 +0000556 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000557 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000558 if (cache_info->file != -1)
559 status=close(cache_info->file);
cristy3ed852e2009-09-05 21:47:34 +0000560 cache_info->file=(-1);
561 RelinquishMagickResource(FileResource,1);
cristyf84a1932010-01-03 18:00:18 +0000562 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000563 return(status == -1 ? MagickFalse : MagickTrue);
564}
565
566static void LimitPixelCacheDescriptors(void)
567{
568 register CacheInfo
569 *p,
570 *q;
571
572 /*
573 Limit # of open file descriptors.
574 */
575 if (GetMagickResource(FileResource) < GetMagickResourceLimit(FileResource))
576 return;
cristyf84a1932010-01-03 18:00:18 +0000577 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000578 if (cache_resources == (SplayTreeInfo *) NULL)
579 {
cristyf84a1932010-01-03 18:00:18 +0000580 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000581 return;
582 }
583 ResetSplayTreeIterator(cache_resources);
584 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
585 while (p != (CacheInfo *) NULL)
586 {
587 if ((p->type == DiskCache) && (p->file != -1))
cristy508d9312010-02-10 21:10:30 +0000588 break;
cristy3ed852e2009-09-05 21:47:34 +0000589 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
590 }
591 for (q=p; p != (CacheInfo *) NULL; )
592 {
593 if ((p->type == DiskCache) && (p->file != -1) &&
594 (p->timestamp < q->timestamp))
cristy508d9312010-02-10 21:10:30 +0000595 q=p;
cristy3ed852e2009-09-05 21:47:34 +0000596 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
597 }
598 if (q != (CacheInfo *) NULL)
cristy9e116922010-02-12 20:58:13 +0000599 {
600 /*
601 Close least recently used cache.
602 */
603 (void) close(q->file);
604 q->file=(-1);
605 }
cristyf84a1932010-01-03 18:00:18 +0000606 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000607}
608
609static inline MagickSizeType MagickMax(const MagickSizeType x,
610 const MagickSizeType y)
611{
612 if (x > y)
613 return(x);
614 return(y);
615}
616
617static inline MagickSizeType MagickMin(const MagickSizeType x,
618 const MagickSizeType y)
619{
620 if (x < y)
621 return(x);
622 return(y);
623}
624
625static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
626 const MapMode mode)
627{
628 int
629 file;
630
631 /*
632 Open pixel cache on disk.
633 */
cristyf84a1932010-01-03 18:00:18 +0000634 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000635 if (cache_info->file != -1)
636 {
cristyf84a1932010-01-03 18:00:18 +0000637 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000638 return(MagickTrue); /* cache already open */
639 }
640 LimitPixelCacheDescriptors();
641 if (*cache_info->cache_filename == '\0')
642 file=AcquireUniqueFileResource(cache_info->cache_filename);
643 else
644 switch (mode)
645 {
646 case ReadMode:
647 {
648 file=open(cache_info->cache_filename,O_RDONLY | O_BINARY);
649 break;
650 }
651 case WriteMode:
652 {
653 file=open(cache_info->cache_filename,O_WRONLY | O_CREAT | O_BINARY |
654 O_EXCL,S_MODE);
655 if (file == -1)
656 file=open(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
657 break;
658 }
659 case IOMode:
660 default:
661 {
662 file=open(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
663 O_EXCL,S_MODE);
664 if (file == -1)
665 file=open(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
666 break;
667 }
668 }
669 if (file == -1)
670 {
cristyf84a1932010-01-03 18:00:18 +0000671 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000672 return(MagickFalse);
673 }
674 (void) AcquireMagickResource(FileResource,1);
675 cache_info->file=file;
676 cache_info->timestamp=time(0);
cristyf84a1932010-01-03 18:00:18 +0000677 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000678 return(MagickTrue);
679}
680
681static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
682 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000683 unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000684{
685 register MagickOffsetType
686 i;
687
688 ssize_t
689 count;
690
cristy08a88202010-03-04 19:18:05 +0000691 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000692#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000693 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000694 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
695 {
cristyf84a1932010-01-03 18:00:18 +0000696 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000697 return((MagickOffsetType) -1);
698 }
699#endif
700 count=0;
701 for (i=0; i < (MagickOffsetType) length; i+=count)
702 {
703#if !defined(MAGICKCORE_HAVE_PREAD)
704 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
705 (MagickSizeType) SSIZE_MAX));
706#else
707 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
708 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
709#endif
710 if (count > 0)
711 continue;
712 count=0;
713 if (errno != EINTR)
714 {
715 i=(-1);
716 break;
717 }
718 }
719#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000720 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000721#endif
722 return(i);
723}
724
725static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
726 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000727 const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000728{
729 register MagickOffsetType
730 i;
731
732 ssize_t
733 count;
734
cristy08a88202010-03-04 19:18:05 +0000735 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000736#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000737 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000738 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
739 {
cristyf84a1932010-01-03 18:00:18 +0000740 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000741 return((MagickOffsetType) -1);
742 }
743#endif
744 count=0;
745 for (i=0; i < (MagickOffsetType) length; i+=count)
746 {
747#if !defined(MAGICKCORE_HAVE_PWRITE)
748 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
749 (MagickSizeType) SSIZE_MAX));
750#else
751 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
752 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
753#endif
754 if (count > 0)
755 continue;
756 count=0;
757 if (errno != EINTR)
758 {
759 i=(-1);
760 break;
761 }
762 }
763#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000764 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000765#endif
766 return(i);
767}
768
769static MagickBooleanType CloneDiskToDiskPixelCache(CacheInfo *clone_info,
770 CacheInfo *cache_info,ExceptionInfo *exception)
771{
772 MagickOffsetType
773 count,
774 offset,
775 source_offset;
776
777 MagickSizeType
778 length;
779
cristy3ed852e2009-09-05 21:47:34 +0000780 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000781 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +0000782
cristye076a6e2010-08-15 19:59:43 +0000783 register ssize_t
784 y;
785
cristybb503372010-05-27 20:51:26 +0000786 size_t
cristy3ed852e2009-09-05 21:47:34 +0000787 columns,
788 rows;
789
790 if (cache_info->debug != MagickFalse)
791 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
792 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
793 {
794 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
795 clone_info->cache_filename);
796 return(MagickFalse);
797 }
798 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
799 {
800 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
801 cache_info->cache_filename);
802 return(MagickFalse);
803 }
cristybb503372010-05-27 20:51:26 +0000804 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
805 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +0000806 if ((clone_info->active_index_channel != MagickFalse) &&
807 (cache_info->active_index_channel != MagickFalse))
808 {
809 register IndexPacket
810 *indexes;
811
812 /*
813 Clone cache indexes.
814 */
815 length=MagickMax(clone_info->columns,cache_info->columns)*
816 sizeof(*indexes);
817 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
818 if (indexes == (IndexPacket *) NULL)
819 {
820 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
821 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
822 return(MagickFalse);
823 }
824 (void) ResetMagickMemory(indexes,0,(size_t) length);
825 length=columns*sizeof(*indexes);
826 source_offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
827 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
828 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
829 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +0000830 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000831 {
832 source_offset-=cache_info->columns*sizeof(*indexes);
833 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
834 length,(unsigned char *) indexes);
835 if ((MagickSizeType) count != length)
836 break;
837 offset-=clone_info->columns*sizeof(*indexes);
838 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
839 (unsigned char *) indexes);
840 if ((MagickSizeType) count != length)
841 break;
842 }
cristybb503372010-05-27 20:51:26 +0000843 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000844 {
845 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
846 ThrowFileException(exception,CacheError,"UnableToCloneCache",
847 cache_info->cache_filename);
848 return(MagickFalse);
849 }
850 if (clone_info->columns > cache_info->columns)
851 {
852 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
853 (void) ResetMagickMemory(indexes,0,(size_t) length);
854 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
855 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +0000856 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000857 {
858 offset-=clone_info->columns*sizeof(*indexes);
859 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
860 length,(unsigned char *) indexes);
861 if ((MagickSizeType) count != length)
862 break;
863 }
cristybb503372010-05-27 20:51:26 +0000864 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000865 {
866 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
867 ThrowFileException(exception,CacheError,"UnableToCloneCache",
868 cache_info->cache_filename);
869 return(MagickFalse);
870 }
871 }
872 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
873 }
874 /*
875 Clone cache pixels.
876 */
877 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
878 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
879 if (pixels == (PixelPacket *) NULL)
880 {
881 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
882 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
883 return(MagickFalse);
884 }
885 (void) ResetMagickMemory(pixels,0,(size_t) length);
886 length=columns*sizeof(*pixels);
887 source_offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
888 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +0000889 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000890 {
891 source_offset-=cache_info->columns*sizeof(*pixels);
892 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
893 length,(unsigned char *) pixels);
894 if ((MagickSizeType) count != length)
895 break;
896 offset-=clone_info->columns*sizeof(*pixels);
897 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
898 (unsigned char *) pixels);
899 if ((MagickSizeType) count != length)
900 break;
901 }
cristybb503372010-05-27 20:51:26 +0000902 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000903 {
904 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
905 ThrowFileException(exception,CacheError,"UnableToCloneCache",
906 cache_info->cache_filename);
907 return(MagickFalse);
908 }
909 if (clone_info->columns > cache_info->columns)
910 {
911 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
912 sizeof(*pixels);
913 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
914 (void) ResetMagickMemory(pixels,0,(size_t) length);
cristybb503372010-05-27 20:51:26 +0000915 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000916 {
917 offset-=clone_info->columns*sizeof(*pixels);
918 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
919 (unsigned char *) pixels);
920 if ((MagickSizeType) count != length)
921 break;
922 }
cristybb503372010-05-27 20:51:26 +0000923 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000924 {
925 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
926 ThrowFileException(exception,CacheError,"UnableToCloneCache",
927 cache_info->cache_filename);
928 return(MagickFalse);
929 }
930 }
931 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
932 return(MagickTrue);
933}
934
935static MagickBooleanType CloneDiskToMemoryPixelCache(CacheInfo *clone_info,
936 CacheInfo *cache_info,ExceptionInfo *exception)
937{
938 MagickOffsetType
939 count,
940 offset;
941
942 MagickSizeType
943 length;
944
cristy3ed852e2009-09-05 21:47:34 +0000945 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000946 *restrict pixels,
947 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000948
cristye076a6e2010-08-15 19:59:43 +0000949 register ssize_t
950 y;
951
cristybb503372010-05-27 20:51:26 +0000952 size_t
cristy3ed852e2009-09-05 21:47:34 +0000953 columns,
954 rows;
955
956 if (cache_info->debug != MagickFalse)
957 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
958 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
959 {
960 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
961 cache_info->cache_filename);
962 return(MagickFalse);
963 }
cristybb503372010-05-27 20:51:26 +0000964 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
965 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +0000966 if ((clone_info->active_index_channel != MagickFalse) &&
967 (cache_info->active_index_channel != MagickFalse))
968 {
969 register IndexPacket
970 *indexes,
971 *q;
972
973 /*
974 Clone cache indexes.
975 */
976 length=MagickMax(clone_info->columns,cache_info->columns)*
977 sizeof(*indexes);
978 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
979 if (indexes == (IndexPacket *) NULL)
980 {
981 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
982 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
983 return(MagickFalse);
984 }
985 (void) ResetMagickMemory(indexes,0,(size_t) length);
986 length=columns*sizeof(IndexPacket);
987 offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
988 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
989 q=clone_info->indexes+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +0000990 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000991 {
992 offset-=cache_info->columns*sizeof(IndexPacket);
993 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,
994 length,(unsigned char *) indexes);
995 if ((MagickSizeType) count != length)
996 break;
997 q-=clone_info->columns;
cristy8f036fe2010-09-18 02:02:00 +0000998 (void) memcpy(q,indexes,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +0000999 if ((MagickSizeType) count != length)
1000 break;
1001 }
cristybb503372010-05-27 20:51:26 +00001002 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001003 {
1004 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1005 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1006 cache_info->cache_filename);
1007 return(MagickFalse);
1008 }
1009 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1010 }
1011 /*
1012 Clone cache pixels.
1013 */
1014 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1015 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1016 if (pixels == (PixelPacket *) NULL)
1017 {
1018 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1019 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1020 return(MagickFalse);
1021 }
1022 (void) ResetMagickMemory(pixels,0,(size_t) length);
1023 length=columns*sizeof(*pixels);
1024 offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
1025 q=clone_info->pixels+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001026 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001027 {
1028 offset-=cache_info->columns*sizeof(*pixels);
1029 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,length,
1030 (unsigned char *) pixels);
1031 if ((MagickSizeType) count != length)
1032 break;
1033 q-=clone_info->columns;
cristy8f036fe2010-09-18 02:02:00 +00001034 (void) memcpy(q,pixels,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00001035 }
cristybb503372010-05-27 20:51:26 +00001036 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001037 {
1038 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1039 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1040 cache_info->cache_filename);
1041 return(MagickFalse);
1042 }
1043 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1044 return(MagickTrue);
1045}
1046
1047static MagickBooleanType CloneMemoryToDiskPixelCache(CacheInfo *clone_info,
1048 CacheInfo *cache_info,ExceptionInfo *exception)
1049{
1050 MagickOffsetType
1051 count,
1052 offset;
1053
1054 MagickSizeType
1055 length;
1056
cristy3ed852e2009-09-05 21:47:34 +00001057 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001058 *restrict p,
1059 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +00001060
cristye076a6e2010-08-15 19:59:43 +00001061 register ssize_t
1062 y;
1063
cristybb503372010-05-27 20:51:26 +00001064 size_t
cristy3ed852e2009-09-05 21:47:34 +00001065 columns,
1066 rows;
1067
1068 if (cache_info->debug != MagickFalse)
1069 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
1070 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
1071 {
1072 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1073 clone_info->cache_filename);
1074 return(MagickFalse);
1075 }
cristybb503372010-05-27 20:51:26 +00001076 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1077 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001078 if ((clone_info->active_index_channel != MagickFalse) &&
1079 (cache_info->active_index_channel != MagickFalse))
1080 {
1081 register IndexPacket
1082 *p,
1083 *indexes;
1084
1085 /*
1086 Clone cache indexes.
1087 */
1088 length=MagickMax(clone_info->columns,cache_info->columns)*
1089 sizeof(*indexes);
1090 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
1091 if (indexes == (IndexPacket *) NULL)
1092 {
1093 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1094 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1095 return(MagickFalse);
1096 }
1097 (void) ResetMagickMemory(indexes,0,(size_t) length);
1098 length=columns*sizeof(*indexes);
1099 p=cache_info->indexes+cache_info->columns*rows;
1100 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1101 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +00001102 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001103 {
1104 p-=cache_info->columns;
cristy8f036fe2010-09-18 02:02:00 +00001105 (void) memcpy(indexes,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00001106 offset-=clone_info->columns*sizeof(*indexes);
1107 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1108 (unsigned char *) indexes);
1109 if ((MagickSizeType) count != length)
1110 break;
1111 }
cristybb503372010-05-27 20:51:26 +00001112 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001113 {
1114 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1115 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1116 cache_info->cache_filename);
1117 return(MagickFalse);
1118 }
1119 if (clone_info->columns > cache_info->columns)
1120 {
1121 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
1122 (void) ResetMagickMemory(indexes,0,(size_t) length);
1123 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1124 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +00001125 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001126 {
1127 offset-=clone_info->columns*sizeof(*indexes);
1128 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
1129 length,(unsigned char *) indexes);
1130 if ((MagickSizeType) count != length)
1131 break;
1132 }
cristybb503372010-05-27 20:51:26 +00001133 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001134 {
1135 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1136 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1137 cache_info->cache_filename);
1138 return(MagickFalse);
1139 }
1140 }
1141 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1142 }
1143 /*
1144 Clone cache pixels.
1145 */
1146 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1147 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1148 if (pixels == (PixelPacket *) NULL)
1149 {
1150 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1151 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1152 return(MagickFalse);
1153 }
1154 (void) ResetMagickMemory(pixels,0,(size_t) length);
1155 length=columns*sizeof(*pixels);
1156 p=cache_info->pixels+cache_info->columns*rows;
1157 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +00001158 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001159 {
1160 p-=cache_info->columns;
cristy8f036fe2010-09-18 02:02:00 +00001161 (void) memcpy(pixels,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00001162 offset-=clone_info->columns*sizeof(*pixels);
1163 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1164 (unsigned char *) pixels);
1165 if ((MagickSizeType) count != length)
1166 break;
1167 }
cristybb503372010-05-27 20:51:26 +00001168 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001169 {
1170 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1171 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1172 cache_info->cache_filename);
1173 return(MagickFalse);
1174 }
1175 if (clone_info->columns > cache_info->columns)
1176 {
1177 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
1178 sizeof(*pixels);
1179 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1180 (void) ResetMagickMemory(pixels,0,(size_t) length);
cristybb503372010-05-27 20:51:26 +00001181 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001182 {
1183 offset-=clone_info->columns*sizeof(*pixels);
1184 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1185 (unsigned char *) pixels);
1186 if ((MagickSizeType) count != length)
1187 break;
1188 }
cristybb503372010-05-27 20:51:26 +00001189 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001190 {
1191 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1192 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1193 cache_info->cache_filename);
1194 return(MagickFalse);
1195 }
1196 }
1197 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1198 return(MagickTrue);
1199}
1200
1201static MagickBooleanType CloneMemoryToMemoryPixelCache(CacheInfo *clone_info,
1202 CacheInfo *cache_info,ExceptionInfo *magick_unused(exception))
1203{
cristy3ed852e2009-09-05 21:47:34 +00001204 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001205 *restrict pixels,
1206 *restrict source_pixels;
cristy3ed852e2009-09-05 21:47:34 +00001207
cristye076a6e2010-08-15 19:59:43 +00001208 register ssize_t
1209 y;
cristy3ed852e2009-09-05 21:47:34 +00001210
cristybb503372010-05-27 20:51:26 +00001211 size_t
cristy3ed852e2009-09-05 21:47:34 +00001212 columns,
cristye076a6e2010-08-15 19:59:43 +00001213 length,
cristy3ed852e2009-09-05 21:47:34 +00001214 rows;
1215
1216 if (cache_info->debug != MagickFalse)
1217 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
cristybb503372010-05-27 20:51:26 +00001218 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1219 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001220 if ((clone_info->active_index_channel != MagickFalse) &&
1221 (cache_info->active_index_channel != MagickFalse))
1222 {
1223 register IndexPacket
1224 *indexes,
1225 *source_indexes;
1226
1227 /*
1228 Clone cache indexes.
1229 */
1230 length=columns*sizeof(*indexes);
1231 if (clone_info->columns == cache_info->columns)
cristy8f036fe2010-09-18 02:02:00 +00001232 (void) memcpy(clone_info->indexes,cache_info->indexes,length*rows);
cristy3ed852e2009-09-05 21:47:34 +00001233 else
1234 {
1235 source_indexes=cache_info->indexes+cache_info->columns*rows;
1236 indexes=clone_info->indexes+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001237 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001238 {
1239 source_indexes-=cache_info->columns;
1240 indexes-=clone_info->columns;
cristy8f036fe2010-09-18 02:02:00 +00001241 (void) memcpy(indexes,source_indexes,length);
cristy3ed852e2009-09-05 21:47:34 +00001242 }
1243 if (clone_info->columns > cache_info->columns)
1244 {
1245 length=(clone_info->columns-cache_info->columns)*
1246 sizeof(*indexes);
1247 indexes=clone_info->indexes+clone_info->columns*rows+
1248 cache_info->columns;
cristybb503372010-05-27 20:51:26 +00001249 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001250 {
1251 indexes-=clone_info->columns;
1252 (void) ResetMagickMemory(indexes,0,length);
1253 }
1254 }
1255 }
1256 }
1257 /*
1258 Clone cache pixels.
1259 */
1260 length=columns*sizeof(*pixels);
1261 if (clone_info->columns == cache_info->columns)
cristy8f036fe2010-09-18 02:02:00 +00001262 (void) memcpy(clone_info->pixels,cache_info->pixels,length*rows);
cristy3ed852e2009-09-05 21:47:34 +00001263 else
1264 {
1265 source_pixels=cache_info->pixels+cache_info->columns*rows;
1266 pixels=clone_info->pixels+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001267 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001268 {
1269 source_pixels-=cache_info->columns;
1270 pixels-=clone_info->columns;
cristy8f036fe2010-09-18 02:02:00 +00001271 (void) memcpy(pixels,source_pixels,length);
cristy3ed852e2009-09-05 21:47:34 +00001272 }
1273 if (clone_info->columns > cache_info->columns)
1274 {
1275 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1276 pixels=clone_info->pixels+clone_info->columns*rows+
1277 cache_info->columns;
cristybb503372010-05-27 20:51:26 +00001278 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001279 {
1280 pixels-=clone_info->columns;
1281 (void) ResetMagickMemory(pixels,0,length);
1282 }
1283 }
1284 }
1285 return(MagickTrue);
1286}
1287
1288static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1289 CacheInfo *cache_info,ExceptionInfo *exception)
1290{
1291 if ((clone_info->type != DiskCache) && (cache_info->type != DiskCache))
1292 return(CloneMemoryToMemoryPixelCache(clone_info,cache_info,exception));
1293 if ((clone_info->type == DiskCache) && (cache_info->type == DiskCache))
1294 return(CloneDiskToDiskPixelCache(clone_info,cache_info,exception));
1295 if (cache_info->type == DiskCache)
1296 return(CloneDiskToMemoryPixelCache(clone_info,cache_info,exception));
1297 return(CloneMemoryToDiskPixelCache(clone_info,cache_info,exception));
1298}
1299
1300/*
1301%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1302% %
1303% %
1304% %
1305+ C l o n e P i x e l C a c h e M e t h o d s %
1306% %
1307% %
1308% %
1309%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1310%
1311% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1312% another.
1313%
1314% The format of the ClonePixelCacheMethods() method is:
1315%
1316% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1317%
1318% A description of each parameter follows:
1319%
1320% o clone: Specifies a pointer to a Cache structure.
1321%
1322% o cache: the pixel cache.
1323%
1324*/
1325MagickExport void ClonePixelCacheMethods(Cache clone,const Cache cache)
1326{
1327 CacheInfo
1328 *cache_info,
1329 *source_info;
1330
1331 assert(clone != (Cache) NULL);
1332 source_info=(CacheInfo *) clone;
1333 assert(source_info->signature == MagickSignature);
1334 if (source_info->debug != MagickFalse)
1335 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1336 source_info->filename);
1337 assert(cache != (Cache) NULL);
1338 cache_info=(CacheInfo *) cache;
1339 assert(cache_info->signature == MagickSignature);
1340 source_info->methods=cache_info->methods;
1341}
1342
1343/*
1344%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1345% %
1346% %
1347% %
1348+ D e s t r o y I m a g e P i x e l C a c h e %
1349% %
1350% %
1351% %
1352%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1353%
1354% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1355%
1356% The format of the DestroyImagePixelCache() method is:
1357%
1358% void DestroyImagePixelCache(Image *image)
1359%
1360% A description of each parameter follows:
1361%
1362% o image: the image.
1363%
1364*/
1365static void DestroyImagePixelCache(Image *image)
1366{
1367 assert(image != (Image *) NULL);
1368 assert(image->signature == MagickSignature);
1369 if (image->debug != MagickFalse)
1370 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1371 if (image->cache == (void *) NULL)
1372 return;
1373 image->cache=DestroyPixelCache(image->cache);
1374}
1375
1376/*
1377%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1378% %
1379% %
1380% %
1381+ D e s t r o y I m a g e P i x e l s %
1382% %
1383% %
1384% %
1385%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1386%
1387% DestroyImagePixels() deallocates memory associated with the pixel cache.
1388%
1389% The format of the DestroyImagePixels() method is:
1390%
1391% void DestroyImagePixels(Image *image)
1392%
1393% A description of each parameter follows:
1394%
1395% o image: the image.
1396%
1397*/
1398MagickExport void DestroyImagePixels(Image *image)
1399{
1400 CacheInfo
1401 *cache_info;
1402
1403 assert(image != (const Image *) NULL);
1404 assert(image->signature == MagickSignature);
1405 if (image->debug != MagickFalse)
1406 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1407 assert(image->cache != (Cache) NULL);
1408 cache_info=(CacheInfo *) image->cache;
1409 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001410 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1411 {
1412 cache_info->methods.destroy_pixel_handler(image);
1413 return;
1414 }
cristy2036f5c2010-09-19 21:18:17 +00001415 image->cache=DestroyPixelCache(image->cache);
cristy3ed852e2009-09-05 21:47:34 +00001416}
1417
1418/*
1419%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1420% %
1421% %
1422% %
1423+ D e s t r o y P i x e l C a c h e %
1424% %
1425% %
1426% %
1427%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1428%
1429% DestroyPixelCache() deallocates memory associated with the pixel cache.
1430%
1431% The format of the DestroyPixelCache() method is:
1432%
1433% Cache DestroyPixelCache(Cache cache)
1434%
1435% A description of each parameter follows:
1436%
1437% o cache: the pixel cache.
1438%
1439*/
1440
1441static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1442{
1443 switch (cache_info->type)
1444 {
1445 case MemoryCache:
1446 {
1447 if (cache_info->mapped == MagickFalse)
1448 cache_info->pixels=(PixelPacket *) RelinquishMagickMemory(
1449 cache_info->pixels);
1450 else
1451 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,
1452 (size_t) cache_info->length);
1453 RelinquishMagickResource(MemoryResource,cache_info->length);
1454 break;
1455 }
1456 case MapCache:
1457 {
1458 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,(size_t)
1459 cache_info->length);
1460 RelinquishMagickResource(MapResource,cache_info->length);
1461 }
1462 case DiskCache:
1463 {
1464 if (cache_info->file != -1)
1465 (void) ClosePixelCacheOnDisk(cache_info);
1466 RelinquishMagickResource(DiskResource,cache_info->length);
1467 break;
1468 }
1469 default:
1470 break;
1471 }
1472 cache_info->type=UndefinedCache;
1473 cache_info->mapped=MagickFalse;
1474 cache_info->indexes=(IndexPacket *) NULL;
1475}
1476
1477MagickExport Cache DestroyPixelCache(Cache cache)
1478{
1479 CacheInfo
1480 *cache_info;
1481
cristy3ed852e2009-09-05 21:47:34 +00001482 assert(cache != (Cache) NULL);
1483 cache_info=(CacheInfo *) cache;
1484 assert(cache_info->signature == MagickSignature);
1485 if (cache_info->debug != MagickFalse)
1486 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1487 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001488 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001489 cache_info->reference_count--;
1490 if (cache_info->reference_count != 0)
1491 {
cristyf84a1932010-01-03 18:00:18 +00001492 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001493 return((Cache) NULL);
1494 }
cristyf84a1932010-01-03 18:00:18 +00001495 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001496 if (cache_resources != (SplayTreeInfo *) NULL)
1497 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
cristy5b8de732009-09-10 23:50:40 +00001498 if (cache_info->debug != MagickFalse)
1499 {
1500 char
1501 message[MaxTextExtent];
1502
1503 (void) FormatMagickString(message,MaxTextExtent,"destroy %s",
1504 cache_info->filename);
1505 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1506 }
cristyc2e1bdd2009-09-10 23:43:34 +00001507 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1508 (cache_info->type != DiskCache)))
1509 RelinquishPixelCachePixels(cache_info);
1510 else
1511 {
1512 RelinquishPixelCachePixels(cache_info);
1513 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1514 }
cristy3ed852e2009-09-05 21:47:34 +00001515 *cache_info->cache_filename='\0';
1516 if (cache_info->nexus_info != (NexusInfo **) NULL)
1517 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1518 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001519 if (cache_info->random_info != (RandomInfo *) NULL)
1520 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001521 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1522 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1523 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1524 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001525 cache_info->signature=(~MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001526 cache_info=(CacheInfo *) RelinquishAlignedMemory(cache_info);
1527 cache=(Cache) NULL;
1528 return(cache);
1529}
1530
1531/*
1532%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1533% %
1534% %
1535% %
1536+ D e s t r o y P i x e l C a c h e N e x u s %
1537% %
1538% %
1539% %
1540%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1541%
1542% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1543%
1544% The format of the DestroyPixelCacheNexus() method is:
1545%
1546% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001547% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001548%
1549% A description of each parameter follows:
1550%
1551% o nexus_info: the nexus to destroy.
1552%
1553% o number_threads: the number of nexus threads.
1554%
1555*/
1556
1557static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1558{
1559 if (nexus_info->mapped == MagickFalse)
1560 (void) RelinquishMagickMemory(nexus_info->cache);
1561 else
1562 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1563 nexus_info->cache=(PixelPacket *) NULL;
1564 nexus_info->pixels=(PixelPacket *) NULL;
1565 nexus_info->indexes=(IndexPacket *) NULL;
1566 nexus_info->length=0;
1567 nexus_info->mapped=MagickFalse;
1568}
1569
1570MagickExport NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001571 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001572{
cristybb503372010-05-27 20:51:26 +00001573 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001574 i;
1575
1576 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001577 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001578 {
1579 if (nexus_info[i]->cache != (PixelPacket *) NULL)
1580 RelinquishCacheNexusPixels(nexus_info[i]);
1581 nexus_info[i]->signature=(~MagickSignature);
1582 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
1583 }
1584 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
1585 return(nexus_info);
1586}
1587
1588/*
1589%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1590% %
1591% %
1592% %
cristy3ed852e2009-09-05 21:47:34 +00001593+ G e t A u t h e n t i c I n d e x e s F r o m C a c h e %
1594% %
1595% %
1596% %
1597%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1598%
1599% GetAuthenticIndexesFromCache() returns the indexes associated with the last
1600% call to QueueAuthenticPixelsCache() or GetAuthenticPixelsCache().
1601%
1602% The format of the GetAuthenticIndexesFromCache() method is:
1603%
1604% IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1605%
1606% A description of each parameter follows:
1607%
1608% o image: the image.
1609%
1610*/
1611static IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1612{
1613 CacheInfo
1614 *cache_info;
1615
cristy5c9e6f22010-09-17 17:31:01 +00001616 const int
1617 id = GetOpenMPThreadId();
1618
cristy3ed852e2009-09-05 21:47:34 +00001619 cache_info=(CacheInfo *) image->cache;
cristy6ebe97c2010-07-03 01:17:28 +00001620 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001621 return(GetPixelCacheNexusIndexes(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001622}
1623
1624/*
1625%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1626% %
1627% %
1628% %
1629% G e t A u t h e n t i c I n d e x Q u e u e %
1630% %
1631% %
1632% %
1633%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1634%
1635% GetAuthenticIndexQueue() returns the authentic black channel or the colormap
1636% indexes associated with the last call to QueueAuthenticPixels() or
1637% GetVirtualPixels(). NULL is returned if the black channel or colormap
1638% indexes are not available.
1639%
1640% The format of the GetAuthenticIndexQueue() method is:
1641%
1642% IndexPacket *GetAuthenticIndexQueue(const Image *image)
1643%
1644% A description of each parameter follows:
1645%
1646% o image: the image.
1647%
1648*/
1649MagickExport IndexPacket *GetAuthenticIndexQueue(const Image *image)
1650{
1651 CacheInfo
1652 *cache_info;
1653
cristy2036f5c2010-09-19 21:18:17 +00001654 const int
1655 id = GetOpenMPThreadId();
1656
cristy3ed852e2009-09-05 21:47:34 +00001657 assert(image != (const Image *) NULL);
1658 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001659 assert(image->cache != (Cache) NULL);
1660 cache_info=(CacheInfo *) image->cache;
1661 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001662 if (cache_info->methods.get_authentic_indexes_from_handler !=
cristy3ed852e2009-09-05 21:47:34 +00001663 (GetAuthenticIndexesFromHandler) NULL)
cristyd317f372010-09-18 01:42:20 +00001664 return(cache_info->methods.get_authentic_indexes_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001665 assert(id < (int) cache_info->number_threads);
1666 return(GetPixelCacheNexusIndexes(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001667}
1668
1669/*
1670%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1671% %
1672% %
1673% %
1674+ 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 %
1675% %
1676% %
1677% %
1678%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1679%
1680% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1681% disk pixel cache as defined by the geometry parameters. A pointer to the
1682% pixels is returned if the pixels are transferred, otherwise a NULL is
1683% returned.
1684%
1685% The format of the GetAuthenticPixelCacheNexus() method is:
1686%
cristybb503372010-05-27 20:51:26 +00001687% PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1688% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001689% NexusInfo *nexus_info,ExceptionInfo *exception)
1690%
1691% A description of each parameter follows:
1692%
1693% o image: the image.
1694%
1695% o x,y,columns,rows: These values define the perimeter of a region of
1696% pixels.
1697%
1698% o nexus_info: the cache nexus to return.
1699%
1700% o exception: return any errors or warnings in this structure.
1701%
1702*/
1703
1704static inline MagickBooleanType IsNexusInCore(const CacheInfo *cache_info,
1705 NexusInfo *nexus_info)
1706{
1707 MagickOffsetType
1708 offset;
1709
cristy73724512010-04-12 14:43:14 +00001710 if (cache_info->type == PingCache)
1711 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001712 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1713 nexus_info->region.x;
1714 if (nexus_info->pixels != (cache_info->pixels+offset))
1715 return(MagickFalse);
1716 return(MagickTrue);
1717}
1718
cristye076a6e2010-08-15 19:59:43 +00001719MagickExport PixelPacket *GetAuthenticPixelCacheNexus(Image *image,
1720 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001721 NexusInfo *nexus_info,ExceptionInfo *exception)
1722{
1723 CacheInfo
1724 *cache_info;
1725
1726 PixelPacket
1727 *pixels;
1728
1729 /*
1730 Transfer pixels from the cache.
1731 */
1732 assert(image != (Image *) NULL);
1733 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001734 pixels=QueueAuthenticNexus(image,x,y,columns,rows,nexus_info,exception);
1735 if (pixels == (PixelPacket *) NULL)
1736 return((PixelPacket *) NULL);
1737 cache_info=(CacheInfo *) image->cache;
1738 assert(cache_info->signature == MagickSignature);
1739 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
1740 return(pixels);
1741 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1742 return((PixelPacket *) NULL);
1743 if (cache_info->active_index_channel != MagickFalse)
1744 if (ReadPixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse)
1745 return((PixelPacket *) NULL);
1746 return(pixels);
1747}
1748
1749/*
1750%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1751% %
1752% %
1753% %
1754+ G e t A u t h e n t i c P i x e l s F r o m C a c h e %
1755% %
1756% %
1757% %
1758%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1759%
1760% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1761% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1762%
1763% The format of the GetAuthenticPixelsFromCache() method is:
1764%
1765% PixelPacket *GetAuthenticPixelsFromCache(const Image image)
1766%
1767% A description of each parameter follows:
1768%
1769% o image: the image.
1770%
1771*/
1772static PixelPacket *GetAuthenticPixelsFromCache(const Image *image)
1773{
1774 CacheInfo
1775 *cache_info;
1776
cristy5c9e6f22010-09-17 17:31:01 +00001777 const int
1778 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001779
cristy3ed852e2009-09-05 21:47:34 +00001780 cache_info=(CacheInfo *) image->cache;
cristy6ebe97c2010-07-03 01:17:28 +00001781 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001782 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001783}
1784
1785/*
1786%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1787% %
1788% %
1789% %
1790% G e t A u t h e n t i c P i x e l Q u e u e %
1791% %
1792% %
1793% %
1794%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1795%
1796% GetAuthenticPixelQueue() returns the authentic pixels associated with the
1797% last call to QueueAuthenticPixels() or GetAuthenticPixels().
1798%
1799% The format of the GetAuthenticPixelQueue() method is:
1800%
1801% PixelPacket *GetAuthenticPixelQueue(const Image image)
1802%
1803% A description of each parameter follows:
1804%
1805% o image: the image.
1806%
1807*/
1808MagickExport PixelPacket *GetAuthenticPixelQueue(const Image *image)
1809{
1810 CacheInfo
1811 *cache_info;
1812
cristy2036f5c2010-09-19 21:18:17 +00001813 const int
1814 id = GetOpenMPThreadId();
1815
cristy3ed852e2009-09-05 21:47:34 +00001816 assert(image != (const Image *) NULL);
1817 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001818 assert(image->cache != (Cache) NULL);
1819 cache_info=(CacheInfo *) image->cache;
1820 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001821 if (cache_info->methods.get_authentic_pixels_from_handler !=
1822 (GetAuthenticPixelsFromHandler) NULL)
1823 return(cache_info->methods.get_authentic_pixels_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001824 assert(id < (int) cache_info->number_threads);
1825 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001826}
1827
1828/*
1829%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1830% %
1831% %
1832% %
1833% G e t A u t h e n t i c P i x e l s %
1834% %
1835% %
1836% %
1837%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1838%
1839% GetAuthenticPixels() obtains a pixel region for read/write access. If the
1840% region is successfully accessed, a pointer to a PixelPacket array
1841% representing the region is returned, otherwise NULL is returned.
1842%
1843% The returned pointer may point to a temporary working copy of the pixels
1844% or it may point to the original pixels in memory. Performance is maximized
1845% if the selected region is part of one row, or one or more full rows, since
1846% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001847% if the image is in memory, or in a memory-mapped file. The returned pointer
1848% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001849%
1850% Pixels accessed via the returned pointer represent a simple array of type
1851% PixelPacket. If the image type is CMYK or if the storage class is
1852% PseduoClass, call GetAuthenticIndexQueue() after invoking
1853% GetAuthenticPixels() to obtain the black color component or colormap indexes
1854% (of type IndexPacket) corresponding to the region. Once the PixelPacket
1855% (and/or IndexPacket) array has been updated, the changes must be saved back
1856% to the underlying image using SyncAuthenticPixels() or they may be lost.
1857%
1858% The format of the GetAuthenticPixels() method is:
1859%
cristy5f959472010-05-27 22:19:46 +00001860% PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1861% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001862% ExceptionInfo *exception)
1863%
1864% A description of each parameter follows:
1865%
1866% o image: the image.
1867%
1868% o x,y,columns,rows: These values define the perimeter of a region of
1869% pixels.
1870%
1871% o exception: return any errors or warnings in this structure.
1872%
1873*/
cristybb503372010-05-27 20:51:26 +00001874MagickExport PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1875 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001876 ExceptionInfo *exception)
1877{
1878 CacheInfo
1879 *cache_info;
1880
cristy2036f5c2010-09-19 21:18:17 +00001881 const int
1882 id = GetOpenMPThreadId();
1883
cristy3ed852e2009-09-05 21:47:34 +00001884 assert(image != (Image *) NULL);
1885 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001886 assert(image->cache != (Cache) NULL);
1887 cache_info=(CacheInfo *) image->cache;
1888 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001889 if (cache_info->methods.get_authentic_pixels_handler !=
1890 (GetAuthenticPixelsHandler) NULL)
1891 return(cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1892 rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00001893 assert(id < (int) cache_info->number_threads);
1894 return(GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1895 cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00001896}
1897
1898/*
1899%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1900% %
1901% %
1902% %
1903+ G e t A u t h e n t i c P i x e l s C a c h e %
1904% %
1905% %
1906% %
1907%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1908%
1909% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1910% as defined by the geometry parameters. A pointer to the pixels is returned
1911% if the pixels are transferred, otherwise a NULL is returned.
1912%
1913% The format of the GetAuthenticPixelsCache() method is:
1914%
cristybb503372010-05-27 20:51:26 +00001915% PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1916% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001917% ExceptionInfo *exception)
1918%
1919% A description of each parameter follows:
1920%
1921% o image: the image.
1922%
1923% o x,y,columns,rows: These values define the perimeter of a region of
1924% pixels.
1925%
1926% o exception: return any errors or warnings in this structure.
1927%
1928*/
cristybb503372010-05-27 20:51:26 +00001929static PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1930 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001931 ExceptionInfo *exception)
1932{
1933 CacheInfo
1934 *cache_info;
1935
cristy5c9e6f22010-09-17 17:31:01 +00001936 const int
1937 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001938
cristy77ff0282010-09-13 00:51:10 +00001939 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001940 if (cache_info == (Cache) NULL)
1941 return((PixelPacket *) NULL);
cristy6ebe97c2010-07-03 01:17:28 +00001942 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001943 return(GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1944 cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00001945}
1946
1947/*
1948%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1949% %
1950% %
1951% %
1952+ G e t I m a g e E x t e n t %
1953% %
1954% %
1955% %
1956%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1957%
1958% GetImageExtent() returns the extent of the pixels associated with the
1959% last call to QueueAuthenticPixels() or GetAuthenticPixels().
1960%
1961% The format of the GetImageExtent() method is:
1962%
1963% MagickSizeType GetImageExtent(const Image *image)
1964%
1965% A description of each parameter follows:
1966%
1967% o image: the image.
1968%
1969*/
1970MagickExport MagickSizeType GetImageExtent(const Image *image)
1971{
1972 CacheInfo
1973 *cache_info;
1974
cristy5c9e6f22010-09-17 17:31:01 +00001975 const int
1976 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001977
cristy3ed852e2009-09-05 21:47:34 +00001978 assert(image != (Image *) NULL);
1979 assert(image->signature == MagickSignature);
1980 if (image->debug != MagickFalse)
1981 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1982 assert(image->cache != (Cache) NULL);
1983 cache_info=(CacheInfo *) image->cache;
1984 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001985 assert(id < (int) cache_info->number_threads);
cristy2036f5c2010-09-19 21:18:17 +00001986 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001987}
1988
1989/*
1990%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1991% %
1992% %
1993% %
1994+ G e t I m a g e P i x e l C a c h e %
1995% %
1996% %
1997% %
1998%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1999%
2000% GetImagePixelCache() ensures that there is only a single reference to the
2001% pixel cache to be modified, updating the provided cache pointer to point to
2002% a clone of the original pixel cache if necessary.
2003%
2004% The format of the GetImagePixelCache method is:
2005%
2006% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2007% ExceptionInfo *exception)
2008%
2009% A description of each parameter follows:
2010%
2011% o image: the image.
2012%
2013% o clone: any value other than MagickFalse clones the cache pixels.
2014%
2015% o exception: return any errors or warnings in this structure.
2016%
2017*/
cristy3ed852e2009-09-05 21:47:34 +00002018static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
2019{
2020 CacheInfo
2021 *cache_info;
2022
2023 /*
2024 Does the image match the pixel cache morphology?
2025 */
2026 cache_info=(CacheInfo *) image->cache;
2027 if ((image->storage_class != cache_info->storage_class) ||
2028 (image->colorspace != cache_info->colorspace) ||
2029 (image->columns != cache_info->columns) ||
2030 (image->rows != cache_info->rows) ||
2031 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2032 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2033 return(MagickFalse);
2034 return(MagickTrue);
2035}
2036
cristy77ff0282010-09-13 00:51:10 +00002037static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2038 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002039{
2040 CacheInfo
2041 *cache_info;
2042
cristy3ed852e2009-09-05 21:47:34 +00002043 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00002044 destroy,
cristy3ed852e2009-09-05 21:47:34 +00002045 status;
2046
cristy50a10922010-02-15 18:35:25 +00002047 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00002048 cpu_throttle = 0,
2049 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00002050 time_limit = 0;
2051
cristy1ea34962010-07-01 19:49:21 +00002052 static time_t
cristya21afde2010-07-02 00:45:40 +00002053 cache_genesis = 0;
cristy1ea34962010-07-01 19:49:21 +00002054
cristyc4f9f132010-03-04 18:50:01 +00002055 status=MagickTrue;
2056 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00002057 if (cpu_throttle == 0)
2058 {
2059 char
2060 *limit;
2061
2062 /*
2063 Set CPU throttle in milleseconds.
2064 */
2065 cpu_throttle=MagickResourceInfinity;
2066 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2067 if (limit == (char *) NULL)
2068 limit=GetPolicyValue("throttle");
2069 if (limit != (char *) NULL)
2070 {
2071 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2072 limit=DestroyString(limit);
2073 }
2074 }
2075 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2076 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00002077 if (time_limit == 0)
2078 {
cristy6ebe97c2010-07-03 01:17:28 +00002079 /*
2080 Set the exire time in seconds.
2081 */
cristy1ea34962010-07-01 19:49:21 +00002082 time_limit=GetMagickResourceLimit(TimeResource);
cristya21afde2010-07-02 00:45:40 +00002083 cache_genesis=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00002084 }
2085 if ((time_limit != MagickResourceInfinity) &&
cristya21afde2010-07-02 00:45:40 +00002086 ((MagickSizeType) (time((time_t *) NULL)-cache_genesis) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00002087 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00002088 assert(image->cache != (Cache) NULL);
2089 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002090 destroy=MagickFalse;
cristy01b7eb02009-09-10 23:10:14 +00002091 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002092 {
cristyaaa0cb62010-02-15 17:47:27 +00002093 LockSemaphoreInfo(cache_info->semaphore);
2094 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002095 {
cristyaaa0cb62010-02-15 17:47:27 +00002096 Image
2097 clone_image;
2098
2099 CacheInfo
2100 *clone_info;
2101
2102 /*
2103 Clone pixel cache.
2104 */
2105 clone_image=(*image);
cristy93505cf2010-08-10 21:37:49 +00002106 clone_image.semaphore=AllocateSemaphoreInfo();
2107 clone_image.reference_count=1;
cristyaaa0cb62010-02-15 17:47:27 +00002108 clone_image.cache=ClonePixelCache(cache_info);
2109 clone_info=(CacheInfo *) clone_image.cache;
cristyabd6e372010-09-15 19:11:26 +00002110 status=OpenPixelCache(&clone_image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00002111 if (status != MagickFalse)
2112 {
cristyabd6e372010-09-15 19:11:26 +00002113 if (clone != MagickFalse)
2114 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00002115 if (status != MagickFalse)
2116 {
cristyabd6e372010-09-15 19:11:26 +00002117 destroy=MagickTrue;
2118 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00002119 }
2120 }
cristy93505cf2010-08-10 21:37:49 +00002121 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002122 }
cristyaaa0cb62010-02-15 17:47:27 +00002123 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002124 }
cristy4320e0e2009-09-10 15:00:08 +00002125 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002126 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002127 if (status != MagickFalse)
2128 {
2129 /*
2130 Ensure the image matches the pixel cache morphology.
2131 */
2132 image->taint=MagickTrue;
2133 image->type=UndefinedType;
cristydd438462010-05-06 13:44:04 +00002134 if (image->colorspace == GRAYColorspace)
2135 image->colorspace=RGBColorspace;
cristy3ed852e2009-09-05 21:47:34 +00002136 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2137 status=OpenPixelCache(image,IOMode,exception);
2138 }
cristyf84a1932010-01-03 18:00:18 +00002139 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002140 if (status == MagickFalse)
2141 return((Cache) NULL);
2142 return(image->cache);
2143}
2144
2145/*
2146%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2147% %
2148% %
2149% %
2150% G e t O n e A u t h e n t i c P i x e l %
2151% %
2152% %
2153% %
2154%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2155%
2156% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2157% location. The image background color is returned if an error occurs.
2158%
2159% The format of the GetOneAuthenticPixel() method is:
2160%
cristybb503372010-05-27 20:51:26 +00002161% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2162% const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002163%
2164% A description of each parameter follows:
2165%
2166% o image: the image.
2167%
2168% o x,y: These values define the location of the pixel to return.
2169%
2170% o pixel: return a pixel at the specified (x,y) location.
2171%
2172% o exception: return any errors or warnings in this structure.
2173%
2174*/
cristyacbbb7c2010-06-30 18:56:48 +00002175MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2176 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002177{
2178 CacheInfo
2179 *cache_info;
2180
cristy2036f5c2010-09-19 21:18:17 +00002181 PixelPacket
2182 *pixels;
2183
cristy3ed852e2009-09-05 21:47:34 +00002184 assert(image != (Image *) NULL);
2185 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002186 assert(image->cache != (Cache) NULL);
2187 cache_info=(CacheInfo *) image->cache;
2188 assert(cache_info->signature == MagickSignature);
2189 *pixel=image->background_color;
cristyd317f372010-09-18 01:42:20 +00002190 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2191 (GetOneAuthenticPixelFromHandler) NULL)
2192 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2193 pixel,exception));
cristy2036f5c2010-09-19 21:18:17 +00002194 *pixel=image->background_color;
2195 pixels=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2196 if (pixels == (PixelPacket *) NULL)
2197 return(MagickFalse);
2198 *pixel=(*pixels);
2199 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002200}
2201
2202/*
2203%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2204% %
2205% %
2206% %
2207+ 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 %
2208% %
2209% %
2210% %
2211%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2212%
2213% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2214% location. The image background color is returned if an error occurs.
2215%
2216% The format of the GetOneAuthenticPixelFromCache() method is:
2217%
2218% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy5f959472010-05-27 22:19:46 +00002219% const ssize_t x,const ssize_t y,PixelPacket *pixel,
2220% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002221%
2222% A description of each parameter follows:
2223%
2224% o image: the image.
2225%
2226% o x,y: These values define the location of the pixel to return.
2227%
2228% o pixel: return a pixel at the specified (x,y) location.
2229%
2230% o exception: return any errors or warnings in this structure.
2231%
2232*/
2233static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristybb503372010-05-27 20:51:26 +00002234 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002235{
cristy0158a4b2010-09-20 13:59:45 +00002236 CacheInfo
2237 *cache_info;
2238
2239 const int
2240 id = GetOpenMPThreadId();
2241
cristy3ed852e2009-09-05 21:47:34 +00002242 PixelPacket
2243 *pixels;
2244
cristy0158a4b2010-09-20 13:59:45 +00002245 assert(image != (const Image *) NULL);
2246 assert(image->signature == MagickSignature);
2247 assert(image->cache != (Cache) NULL);
2248 cache_info=(CacheInfo *) image->cache;
2249 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002250 *pixel=image->background_color;
cristy0158a4b2010-09-20 13:59:45 +00002251 assert(id < (int) cache_info->number_threads);
2252 pixels=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,
2253 cache_info->nexus_info[id],exception);
cristy3ed852e2009-09-05 21:47:34 +00002254 if (pixels == (PixelPacket *) NULL)
2255 return(MagickFalse);
2256 *pixel=(*pixels);
2257 return(MagickTrue);
2258}
2259
2260/*
2261%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2262% %
2263% %
2264% %
2265% G e t O n e V i r t u a l M a g i c k P i x e l %
2266% %
2267% %
2268% %
2269%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2270%
2271% GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2272% location. The image background color is returned if an error occurs. If
2273% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2274%
2275% The format of the GetOneVirtualMagickPixel() method is:
2276%
2277% MagickBooleanType GetOneVirtualMagickPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002278% const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
cristy3ed852e2009-09-05 21:47:34 +00002279% ExceptionInfo exception)
2280%
2281% A description of each parameter follows:
2282%
2283% o image: the image.
2284%
2285% o x,y: these values define the location of the pixel to return.
2286%
2287% o pixel: return a pixel at the specified (x,y) location.
2288%
2289% o exception: return any errors or warnings in this structure.
2290%
2291*/
2292MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
cristyacbbb7c2010-06-30 18:56:48 +00002293 const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
2294 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002295{
2296 CacheInfo
2297 *cache_info;
2298
cristy0158a4b2010-09-20 13:59:45 +00002299 const int
2300 id = GetOpenMPThreadId();
2301
cristy3ed852e2009-09-05 21:47:34 +00002302 register const IndexPacket
2303 *indexes;
2304
2305 register const PixelPacket
cristy0158a4b2010-09-20 13:59:45 +00002306 *pixels;
cristy3ed852e2009-09-05 21:47:34 +00002307
2308 assert(image != (const Image *) NULL);
2309 assert(image->signature == MagickSignature);
2310 assert(image->cache != (Cache) NULL);
2311 cache_info=(CacheInfo *) image->cache;
2312 assert(cache_info->signature == MagickSignature);
2313 GetMagickPixelPacket(image,pixel);
cristy0158a4b2010-09-20 13:59:45 +00002314 assert(id < (int) cache_info->number_threads);
2315 pixels=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2316 1UL,1UL,cache_info->nexus_info[id],exception);
2317 if (pixels == (const PixelPacket *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002318 return(MagickFalse);
cristy0158a4b2010-09-20 13:59:45 +00002319 indexes=GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[id]);
2320 SetMagickPixelPacket(image,pixels,indexes,pixel);
cristy3ed852e2009-09-05 21:47:34 +00002321 return(MagickTrue);
2322}
2323
2324/*
2325%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2326% %
2327% %
2328% %
2329% G e t O n e V i r t u a l M e t h o d P i x e l %
2330% %
2331% %
2332% %
2333%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2334%
2335% GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2336% location as defined by specified pixel method. The image background color
2337% is returned if an error occurs. If you plan to modify the pixel, use
2338% GetOneAuthenticPixel() instead.
2339%
2340% The format of the GetOneVirtualMethodPixel() method is:
2341%
2342% MagickBooleanType GetOneVirtualMethodPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002343% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2344% const ssize_t y,Pixelpacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002345%
2346% A description of each parameter follows:
2347%
2348% o image: the image.
2349%
2350% o virtual_pixel_method: the virtual pixel method.
2351%
2352% o x,y: These values define the location of the pixel to return.
2353%
2354% o pixel: return a pixel at the specified (x,y) location.
2355%
2356% o exception: return any errors or warnings in this structure.
2357%
2358*/
2359MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002360 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002361 PixelPacket *pixel,ExceptionInfo *exception)
2362{
cristy3ed852e2009-09-05 21:47:34 +00002363 CacheInfo
2364 *cache_info;
2365
cristy0158a4b2010-09-20 13:59:45 +00002366 const int
2367 id = GetOpenMPThreadId();
2368
cristy2036f5c2010-09-19 21:18:17 +00002369 const PixelPacket
2370 *pixels;
2371
cristy3ed852e2009-09-05 21:47:34 +00002372 assert(image != (const Image *) NULL);
2373 assert(image->signature == MagickSignature);
2374 assert(image->cache != (Cache) NULL);
2375 cache_info=(CacheInfo *) image->cache;
2376 assert(cache_info->signature == MagickSignature);
2377 *pixel=image->background_color;
cristyd317f372010-09-18 01:42:20 +00002378 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2379 (GetOneVirtualPixelFromHandler) NULL)
2380 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2381 virtual_pixel_method,x,y,pixel,exception));
cristy2036f5c2010-09-19 21:18:17 +00002382 *pixel=image->background_color;
cristy0158a4b2010-09-20 13:59:45 +00002383 assert(id < (int) cache_info->number_threads);
2384 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2385 cache_info->nexus_info[id],exception);
cristy2036f5c2010-09-19 21:18:17 +00002386 if (pixels == (const PixelPacket *) NULL)
2387 return(MagickFalse);
2388 *pixel=(*pixels);
2389 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002390}
2391
2392/*
2393%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2394% %
2395% %
2396% %
2397% G e t O n e V i r t u a l P i x e l %
2398% %
2399% %
2400% %
2401%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2402%
2403% GetOneVirtualPixel() returns a single virtual pixel at the specified
2404% (x,y) location. The image background color is returned if an error occurs.
2405% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2406%
2407% The format of the GetOneVirtualPixel() method is:
2408%
cristybb503372010-05-27 20:51:26 +00002409% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2410% const ssize_t y,PixelPacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002411%
2412% A description of each parameter follows:
2413%
2414% o image: the image.
2415%
2416% o x,y: These values define the location of the pixel to return.
2417%
2418% o pixel: return a pixel at the specified (x,y) location.
2419%
2420% o exception: return any errors or warnings in this structure.
2421%
2422*/
2423MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002424 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002425{
cristy3ed852e2009-09-05 21:47:34 +00002426 CacheInfo
2427 *cache_info;
2428
cristy0158a4b2010-09-20 13:59:45 +00002429 const int
2430 id = GetOpenMPThreadId();
2431
cristy2036f5c2010-09-19 21:18:17 +00002432 const PixelPacket
2433 *pixels;
2434
cristy3ed852e2009-09-05 21:47:34 +00002435 assert(image != (const Image *) NULL);
2436 assert(image->signature == MagickSignature);
2437 assert(image->cache != (Cache) NULL);
2438 cache_info=(CacheInfo *) image->cache;
2439 assert(cache_info->signature == MagickSignature);
2440 *pixel=image->background_color;
cristyd317f372010-09-18 01:42:20 +00002441 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2442 (GetOneVirtualPixelFromHandler) NULL)
2443 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2444 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002445 assert(id < (int) cache_info->number_threads);
2446 pixels=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2447 1UL,1UL,cache_info->nexus_info[id],exception);
cristy2036f5c2010-09-19 21:18:17 +00002448 if (pixels == (const PixelPacket *) NULL)
2449 return(MagickFalse);
2450 *pixel=(*pixels);
2451 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002452}
2453
2454/*
2455%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2456% %
2457% %
2458% %
2459+ 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 %
2460% %
2461% %
2462% %
2463%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2464%
2465% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2466% specified (x,y) location. The image background color is returned if an
2467% error occurs.
2468%
2469% The format of the GetOneVirtualPixelFromCache() method is:
2470%
2471% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristybb503372010-05-27 20:51:26 +00002472% const VirtualPixelPacket method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002473% PixelPacket *pixel,ExceptionInfo *exception)
2474%
2475% A description of each parameter follows:
2476%
2477% o image: the image.
2478%
2479% o virtual_pixel_method: the virtual pixel method.
2480%
2481% o x,y: These values define the location of the pixel to return.
2482%
2483% o pixel: return a pixel at the specified (x,y) location.
2484%
2485% o exception: return any errors or warnings in this structure.
2486%
2487*/
2488static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002489 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002490 PixelPacket *pixel,ExceptionInfo *exception)
2491{
cristy0158a4b2010-09-20 13:59:45 +00002492 CacheInfo
2493 *cache_info;
2494
2495 const int
2496 id = GetOpenMPThreadId();
2497
cristy3ed852e2009-09-05 21:47:34 +00002498 const PixelPacket
2499 *pixels;
2500
2501 *pixel=image->background_color;
cristy0158a4b2010-09-20 13:59:45 +00002502 cache_info=(CacheInfo *) image->cache;
2503 assert(id < (int) cache_info->number_threads);
2504 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2505 cache_info->nexus_info[id],exception);
cristy3ed852e2009-09-05 21:47:34 +00002506 if (pixels == (const PixelPacket *) NULL)
2507 return(MagickFalse);
2508 *pixel=(*pixels);
2509 return(MagickTrue);
2510}
2511
2512/*
2513%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2514% %
2515% %
2516% %
2517+ G e t P i x e l C a c h e C o l o r s p a c e %
2518% %
2519% %
2520% %
2521%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2522%
2523% GetPixelCacheColorspace() returns the class type of the pixel cache.
2524%
2525% The format of the GetPixelCacheColorspace() method is:
2526%
2527% Colorspace GetPixelCacheColorspace(Cache cache)
2528%
2529% A description of each parameter follows:
2530%
2531% o cache: the pixel cache.
2532%
2533*/
2534MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
2535{
2536 CacheInfo
2537 *cache_info;
2538
2539 assert(cache != (Cache) NULL);
2540 cache_info=(CacheInfo *) cache;
2541 assert(cache_info->signature == MagickSignature);
2542 if (cache_info->debug != MagickFalse)
2543 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2544 cache_info->filename);
2545 return(cache_info->colorspace);
2546}
2547
2548/*
2549%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2550% %
2551% %
2552% %
2553+ G e t P i x e l C a c h e M e t h o d s %
2554% %
2555% %
2556% %
2557%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2558%
2559% GetPixelCacheMethods() initializes the CacheMethods structure.
2560%
2561% The format of the GetPixelCacheMethods() method is:
2562%
2563% void GetPixelCacheMethods(CacheMethods *cache_methods)
2564%
2565% A description of each parameter follows:
2566%
2567% o cache_methods: Specifies a pointer to a CacheMethods structure.
2568%
2569*/
2570MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
2571{
2572 assert(cache_methods != (CacheMethods *) NULL);
2573 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2574 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2575 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2576 cache_methods->get_virtual_indexes_from_handler=GetVirtualIndexesFromCache;
2577 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2578 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2579 cache_methods->get_authentic_indexes_from_handler=
2580 GetAuthenticIndexesFromCache;
2581 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2582 cache_methods->get_one_authentic_pixel_from_handler=
2583 GetOneAuthenticPixelFromCache;
2584 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2585 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2586 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2587}
2588
2589/*
2590%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2591% %
2592% %
2593% %
2594+ G e t P i x e l C a c h e N e x u s E x t e n t %
2595% %
2596% %
2597% %
2598%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2599%
2600% GetPixelCacheNexusExtent() returns the extent of the pixels associated with
2601% the last call to SetPixelCacheNexusPixels() or GetPixelCacheNexusPixels().
2602%
2603% The format of the GetPixelCacheNexusExtent() method is:
2604%
2605% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2606% NexusInfo *nexus_info)
2607%
2608% A description of each parameter follows:
2609%
2610% o nexus_info: the nexus info.
2611%
2612*/
2613MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2614 NexusInfo *nexus_info)
2615{
2616 CacheInfo
2617 *cache_info;
2618
2619 MagickSizeType
2620 extent;
2621
cristy0158a4b2010-09-20 13:59:45 +00002622 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002623 cache_info=(CacheInfo *) cache;
2624 assert(cache_info->signature == MagickSignature);
2625 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2626 if (extent == 0)
2627 return((MagickSizeType) cache_info->columns*cache_info->rows);
2628 return(extent);
2629}
2630
2631/*
2632%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2633% %
2634% %
2635% %
2636+ 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 %
2637% %
2638% %
2639% %
2640%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2641%
2642% GetPixelCacheNexusIndexes() returns the indexes associated with the
2643% specified cache nexus.
2644%
2645% The format of the GetPixelCacheNexusIndexes() method is:
2646%
2647% IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2648% NexusInfo *nexus_info)
2649%
2650% A description of each parameter follows:
2651%
2652% o cache: the pixel cache.
2653%
2654% o nexus_info: the cache nexus to return the colormap indexes.
2655%
2656*/
2657MagickExport IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2658 NexusInfo *nexus_info)
2659{
2660 CacheInfo
2661 *cache_info;
2662
2663 if (cache == (Cache) NULL)
2664 return((IndexPacket *) NULL);
2665 cache_info=(CacheInfo *) cache;
2666 assert(cache_info->signature == MagickSignature);
2667 if (cache_info->storage_class == UndefinedClass)
2668 return((IndexPacket *) NULL);
2669 return(nexus_info->indexes);
2670}
2671
2672/*
2673%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2674% %
2675% %
2676% %
2677+ G e t P i x e l C a c h e N e x u s P i x e l s %
2678% %
2679% %
2680% %
2681%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2682%
2683% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2684% cache nexus.
2685%
2686% The format of the GetPixelCacheNexusPixels() method is:
2687%
2688% PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2689% NexusInfo *nexus_info)
2690%
2691% A description of each parameter follows:
2692%
2693% o cache: the pixel cache.
2694%
2695% o nexus_info: the cache nexus to return the pixels.
2696%
2697*/
2698MagickExport PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2699 NexusInfo *nexus_info)
2700{
2701 CacheInfo
2702 *cache_info;
2703
2704 if (cache == (Cache) NULL)
2705 return((PixelPacket *) NULL);
2706 cache_info=(CacheInfo *) cache;
2707 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002708 if (cache_info->storage_class == UndefinedClass)
2709 return((PixelPacket *) NULL);
2710 return(nexus_info->pixels);
2711}
2712
2713/*
2714%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2715% %
2716% %
2717% %
cristy056ba772010-01-02 23:33:54 +00002718+ G e t P i x e l C a c h e P i x e l s %
2719% %
2720% %
2721% %
2722%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2723%
2724% GetPixelCachePixels() returns the pixels associated with the specified image.
2725%
2726% The format of the GetPixelCachePixels() method is:
2727%
cristyf84a1932010-01-03 18:00:18 +00002728% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2729% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002730%
2731% A description of each parameter follows:
2732%
2733% o image: the image.
2734%
2735% o length: the pixel cache length.
2736%
cristyf84a1932010-01-03 18:00:18 +00002737% o exception: return any errors or warnings in this structure.
2738%
cristy056ba772010-01-02 23:33:54 +00002739*/
cristyf84a1932010-01-03 18:00:18 +00002740MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2741 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002742{
2743 CacheInfo
2744 *cache_info;
2745
2746 assert(image != (const Image *) NULL);
2747 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002748 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00002749 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002750 assert(cache_info->signature == MagickSignature);
2751 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002752 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002753 return((void *) NULL);
2754 *length=cache_info->length;
2755 return((void *) cache_info->pixels);
2756}
2757
2758/*
2759%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2760% %
2761% %
2762% %
cristyb32b90a2009-09-07 21:45:48 +00002763+ 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 +00002764% %
2765% %
2766% %
2767%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2768%
2769% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2770%
2771% The format of the GetPixelCacheStorageClass() method is:
2772%
2773% ClassType GetPixelCacheStorageClass(Cache cache)
2774%
2775% A description of each parameter follows:
2776%
2777% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2778%
2779% o cache: the pixel cache.
2780%
2781*/
2782MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
2783{
2784 CacheInfo
2785 *cache_info;
2786
2787 assert(cache != (Cache) NULL);
2788 cache_info=(CacheInfo *) cache;
2789 assert(cache_info->signature == MagickSignature);
2790 if (cache_info->debug != MagickFalse)
2791 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2792 cache_info->filename);
2793 return(cache_info->storage_class);
2794}
2795
2796/*
2797%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2798% %
2799% %
2800% %
cristyb32b90a2009-09-07 21:45:48 +00002801+ G e t P i x e l C a c h e T i l e S i z e %
2802% %
2803% %
2804% %
2805%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2806%
2807% GetPixelCacheTileSize() returns the pixel cache tile size.
2808%
2809% The format of the GetPixelCacheTileSize() method is:
2810%
cristybb503372010-05-27 20:51:26 +00002811% void GetPixelCacheTileSize(const Image *image,size_t *width,
2812% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002813%
2814% A description of each parameter follows:
2815%
2816% o image: the image.
2817%
2818% o width: the optimize cache tile width in pixels.
2819%
2820% o height: the optimize cache tile height in pixels.
2821%
2822*/
cristybb503372010-05-27 20:51:26 +00002823MagickExport void GetPixelCacheTileSize(const Image *image,size_t *width,
2824 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002825{
2826 CacheInfo
2827 *cache_info;
2828
2829 assert(image != (Image *) NULL);
2830 assert(image->signature == MagickSignature);
2831 if (image->debug != MagickFalse)
2832 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2833 assert(image->cache != (Cache) NULL);
2834 cache_info=(CacheInfo *) image->cache;
2835 assert(cache_info->signature == MagickSignature);
2836 *width=2048UL/sizeof(PixelPacket);
2837 if (GetPixelCacheType(image) == DiskCache)
cristydaa97692009-09-13 02:10:35 +00002838 *width=8192UL/sizeof(PixelPacket);
cristyb32b90a2009-09-07 21:45:48 +00002839 *height=(*width);
2840}
2841
2842/*
2843%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2844% %
2845% %
2846% %
2847+ G e t P i x e l C a c h e T y p e %
2848% %
2849% %
2850% %
2851%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2852%
2853% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2854%
2855% The format of the GetPixelCacheType() method is:
2856%
2857% CacheType GetPixelCacheType(const Image *image)
2858%
2859% A description of each parameter follows:
2860%
2861% o image: the image.
2862%
2863*/
2864MagickExport CacheType GetPixelCacheType(const Image *image)
2865{
2866 CacheInfo
2867 *cache_info;
2868
2869 assert(image != (Image *) NULL);
2870 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002871 assert(image->cache != (Cache) NULL);
2872 cache_info=(CacheInfo *) image->cache;
2873 assert(cache_info->signature == MagickSignature);
2874 return(cache_info->type);
2875}
2876
2877/*
2878%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2879% %
2880% %
2881% %
cristy3ed852e2009-09-05 21:47:34 +00002882+ 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 %
2883% %
2884% %
2885% %
2886%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2887%
2888% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2889% pixel cache. A virtual pixel is any pixel access that is outside the
2890% boundaries of the image cache.
2891%
2892% The format of the GetPixelCacheVirtualMethod() method is:
2893%
2894% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2895%
2896% A description of each parameter follows:
2897%
2898% o image: the image.
2899%
2900*/
2901MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2902{
2903 CacheInfo
2904 *cache_info;
2905
2906 assert(image != (Image *) NULL);
2907 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002908 assert(image->cache != (Cache) NULL);
2909 cache_info=(CacheInfo *) image->cache;
2910 assert(cache_info->signature == MagickSignature);
2911 return(cache_info->virtual_pixel_method);
2912}
2913
2914/*
2915%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2916% %
2917% %
2918% %
2919+ 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 %
2920% %
2921% %
2922% %
2923%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2924%
2925% GetVirtualIndexesFromCache() returns the indexes associated with the last
2926% call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2927%
2928% The format of the GetVirtualIndexesFromCache() method is:
2929%
2930% IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2931%
2932% A description of each parameter follows:
2933%
2934% o image: the image.
2935%
2936*/
2937static const IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2938{
2939 CacheInfo
2940 *cache_info;
2941
cristy5c9e6f22010-09-17 17:31:01 +00002942 const int
2943 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002944
cristy3ed852e2009-09-05 21:47:34 +00002945 cache_info=(CacheInfo *) image->cache;
cristy6ebe97c2010-07-03 01:17:28 +00002946 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00002947 return(GetVirtualIndexesFromNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00002948}
2949
2950/*
2951%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2952% %
2953% %
2954% %
2955+ 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 %
2956% %
2957% %
2958% %
2959%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2960%
2961% GetVirtualIndexesFromNexus() returns the indexes associated with the
2962% specified cache nexus.
2963%
2964% The format of the GetVirtualIndexesFromNexus() method is:
2965%
2966% const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2967% NexusInfo *nexus_info)
2968%
2969% A description of each parameter follows:
2970%
2971% o cache: the pixel cache.
2972%
2973% o nexus_info: the cache nexus to return the colormap indexes.
2974%
2975*/
2976MagickExport const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2977 NexusInfo *nexus_info)
2978{
2979 CacheInfo
2980 *cache_info;
2981
2982 if (cache == (Cache) NULL)
2983 return((IndexPacket *) NULL);
2984 cache_info=(CacheInfo *) cache;
2985 assert(cache_info->signature == MagickSignature);
2986 if (cache_info->storage_class == UndefinedClass)
2987 return((IndexPacket *) NULL);
2988 return(nexus_info->indexes);
2989}
2990
2991/*
2992%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2993% %
2994% %
2995% %
2996% G e t V i r t u a l I n d e x Q u e u e %
2997% %
2998% %
2999% %
3000%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3001%
3002% GetVirtualIndexQueue() returns the virtual black channel or the
3003% colormap indexes associated with the last call to QueueAuthenticPixels() or
3004% GetVirtualPixels(). NULL is returned if the black channel or colormap
3005% indexes are not available.
3006%
3007% The format of the GetVirtualIndexQueue() method is:
3008%
3009% const IndexPacket *GetVirtualIndexQueue(const Image *image)
3010%
3011% A description of each parameter follows:
3012%
3013% o image: the image.
3014%
3015*/
3016MagickExport const IndexPacket *GetVirtualIndexQueue(const Image *image)
3017{
3018 CacheInfo
3019 *cache_info;
3020
cristy2036f5c2010-09-19 21:18:17 +00003021 const int
3022 id = GetOpenMPThreadId();
3023
cristy3ed852e2009-09-05 21:47:34 +00003024 assert(image != (const Image *) NULL);
3025 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003026 assert(image->cache != (Cache) NULL);
3027 cache_info=(CacheInfo *) image->cache;
3028 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003029 if (cache_info->methods.get_virtual_indexes_from_handler !=
3030 (GetVirtualIndexesFromHandler) NULL)
3031 return(cache_info->methods.get_virtual_indexes_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003032 assert(id < (int) cache_info->number_threads);
3033 return(GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003034}
3035
3036/*
3037%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3038% %
3039% %
3040% %
3041+ 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 %
3042% %
3043% %
3044% %
3045%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3046%
3047% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3048% pixel cache as defined by the geometry parameters. A pointer to the pixels
3049% is returned if the pixels are transferred, otherwise a NULL is returned.
3050%
3051% The format of the GetVirtualPixelsFromNexus() method is:
3052%
3053% PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003054% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00003055% const size_t columns,const size_t rows,NexusInfo *nexus_info,
3056% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003057%
3058% A description of each parameter follows:
3059%
3060% o image: the image.
3061%
3062% o virtual_pixel_method: the virtual pixel method.
3063%
3064% o x,y,columns,rows: These values define the perimeter of a region of
3065% pixels.
3066%
3067% o nexus_info: the cache nexus to acquire.
3068%
3069% o exception: return any errors or warnings in this structure.
3070%
3071*/
3072
cristybb503372010-05-27 20:51:26 +00003073static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003074 DitherMatrix[64] =
3075 {
3076 0, 48, 12, 60, 3, 51, 15, 63,
3077 32, 16, 44, 28, 35, 19, 47, 31,
3078 8, 56, 4, 52, 11, 59, 7, 55,
3079 40, 24, 36, 20, 43, 27, 39, 23,
3080 2, 50, 14, 62, 1, 49, 13, 61,
3081 34, 18, 46, 30, 33, 17, 45, 29,
3082 10, 58, 6, 54, 9, 57, 5, 53,
3083 42, 26, 38, 22, 41, 25, 37, 21
3084 };
3085
cristybb503372010-05-27 20:51:26 +00003086static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003087{
cristybb503372010-05-27 20:51:26 +00003088 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003089 index;
3090
3091 index=x+DitherMatrix[x & 0x07]-32L;
3092 if (index < 0L)
3093 return(0L);
cristybb503372010-05-27 20:51:26 +00003094 if (index >= (ssize_t) columns)
3095 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00003096 return(index);
3097}
3098
cristybb503372010-05-27 20:51:26 +00003099static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003100{
cristybb503372010-05-27 20:51:26 +00003101 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003102 index;
3103
3104 index=y+DitherMatrix[y & 0x07]-32L;
3105 if (index < 0L)
3106 return(0L);
cristybb503372010-05-27 20:51:26 +00003107 if (index >= (ssize_t) rows)
3108 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00003109 return(index);
3110}
3111
cristybb503372010-05-27 20:51:26 +00003112static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003113{
3114 if (x < 0L)
3115 return(0L);
cristybb503372010-05-27 20:51:26 +00003116 if (x >= (ssize_t) columns)
3117 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003118 return(x);
3119}
3120
cristybb503372010-05-27 20:51:26 +00003121static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003122{
3123 if (y < 0L)
3124 return(0L);
cristybb503372010-05-27 20:51:26 +00003125 if (y >= (ssize_t) rows)
3126 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003127 return(y);
3128}
3129
cristybb503372010-05-27 20:51:26 +00003130static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003131{
cristybb503372010-05-27 20:51:26 +00003132 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003133}
3134
cristybb503372010-05-27 20:51:26 +00003135static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003136{
cristybb503372010-05-27 20:51:26 +00003137 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003138}
3139
3140/*
3141 VirtualPixelModulo() computes the remainder of dividing offset by extent. It
3142 returns not only the quotient (tile the offset falls in) but also the positive
3143 remainer within that tile such that 0 <= remainder < extent. This method is
3144 essentially a ldiv() using a floored modulo division rather than the normal
3145 default truncated modulo division.
3146*/
cristybb503372010-05-27 20:51:26 +00003147static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3148 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003149{
3150 MagickModulo
3151 modulo;
3152
cristybb503372010-05-27 20:51:26 +00003153 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003154 if (offset < 0L)
3155 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003156 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003157 return(modulo);
3158}
3159
3160MagickExport const PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003161 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3162 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003163 ExceptionInfo *exception)
3164{
3165 CacheInfo
3166 *cache_info;
3167
cristyc3ec0d42010-04-07 01:18:08 +00003168 IndexPacket
3169 virtual_index;
3170
cristy3ed852e2009-09-05 21:47:34 +00003171 MagickOffsetType
3172 offset;
3173
3174 MagickSizeType
3175 length,
3176 number_pixels;
3177
3178 NexusInfo
3179 **virtual_nexus;
3180
3181 PixelPacket
3182 *pixels,
3183 virtual_pixel;
3184
3185 RectangleInfo
3186 region;
3187
3188 register const IndexPacket
cristyc3ec0d42010-04-07 01:18:08 +00003189 *restrict virtual_indexes;
cristy3ed852e2009-09-05 21:47:34 +00003190
3191 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003192 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003193
3194 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003195 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003196
cristye076a6e2010-08-15 19:59:43 +00003197 register PixelPacket
3198 *restrict q;
3199
cristybb503372010-05-27 20:51:26 +00003200 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003201 u,
3202 v;
3203
cristy3ed852e2009-09-05 21:47:34 +00003204 /*
3205 Acquire pixels.
3206 */
cristy3ed852e2009-09-05 21:47:34 +00003207 cache_info=(CacheInfo *) image->cache;
cristy4cfbb3f2010-03-14 20:40:23 +00003208 if (cache_info->type == UndefinedCache)
cristy3ed852e2009-09-05 21:47:34 +00003209 return((const PixelPacket *) NULL);
3210 region.x=x;
3211 region.y=y;
3212 region.width=columns;
3213 region.height=rows;
3214 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
3215 if (pixels == (PixelPacket *) NULL)
3216 return((const PixelPacket *) NULL);
cristydf415c82010-03-11 16:47:50 +00003217 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3218 nexus_info->region.x;
3219 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3220 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003221 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3222 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003223 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3224 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003225 {
3226 MagickBooleanType
3227 status;
3228
3229 /*
3230 Pixel request is inside cache extents.
3231 */
3232 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
3233 return(pixels);
3234 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3235 if (status == MagickFalse)
3236 return((const PixelPacket *) NULL);
3237 if ((cache_info->storage_class == PseudoClass) ||
3238 (cache_info->colorspace == CMYKColorspace))
3239 {
3240 status=ReadPixelCacheIndexes(cache_info,nexus_info,exception);
3241 if (status == MagickFalse)
3242 return((const PixelPacket *) NULL);
3243 }
3244 return(pixels);
3245 }
3246 /*
3247 Pixel request is outside cache extents.
3248 */
3249 q=pixels;
3250 indexes=GetPixelCacheNexusIndexes(cache_info,nexus_info);
3251 virtual_nexus=AcquirePixelCacheNexus(1);
3252 if (virtual_nexus == (NexusInfo **) NULL)
3253 {
3254 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3255 "UnableToGetCacheNexus","`%s'",image->filename);
3256 return((const PixelPacket *) NULL);
3257 }
3258 switch (virtual_pixel_method)
3259 {
3260 case BlackVirtualPixelMethod:
3261 {
cristy4789f0d2010-01-10 00:01:06 +00003262 SetRedPixelComponent(&virtual_pixel,0);
3263 SetGreenPixelComponent(&virtual_pixel,0);
3264 SetBluePixelComponent(&virtual_pixel,0);
3265 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003266 break;
3267 }
3268 case GrayVirtualPixelMethod:
3269 {
cristy4789f0d2010-01-10 00:01:06 +00003270 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3271 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3272 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3273 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003274 break;
3275 }
3276 case TransparentVirtualPixelMethod:
3277 {
cristy4789f0d2010-01-10 00:01:06 +00003278 SetRedPixelComponent(&virtual_pixel,0);
3279 SetGreenPixelComponent(&virtual_pixel,0);
3280 SetBluePixelComponent(&virtual_pixel,0);
3281 SetOpacityPixelComponent(&virtual_pixel,TransparentOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003282 break;
3283 }
3284 case MaskVirtualPixelMethod:
3285 case WhiteVirtualPixelMethod:
3286 {
cristy4789f0d2010-01-10 00:01:06 +00003287 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3288 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3289 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3290 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003291 break;
3292 }
3293 default:
3294 {
3295 virtual_pixel=image->background_color;
3296 break;
3297 }
3298 }
cristyc3ec0d42010-04-07 01:18:08 +00003299 virtual_index=0;
cristybb503372010-05-27 20:51:26 +00003300 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003301 {
cristybb503372010-05-27 20:51:26 +00003302 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003303 {
3304 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003305 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003306 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3307 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003308 {
3309 MagickModulo
3310 x_modulo,
3311 y_modulo;
3312
3313 /*
3314 Transfer a single pixel.
3315 */
3316 length=(MagickSizeType) 1;
3317 switch (virtual_pixel_method)
3318 {
3319 case BackgroundVirtualPixelMethod:
3320 case ConstantVirtualPixelMethod:
3321 case BlackVirtualPixelMethod:
3322 case GrayVirtualPixelMethod:
3323 case TransparentVirtualPixelMethod:
3324 case MaskVirtualPixelMethod:
3325 case WhiteVirtualPixelMethod:
3326 {
3327 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003328 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003329 break;
3330 }
3331 case EdgeVirtualPixelMethod:
3332 default:
3333 {
3334 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003335 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003336 1UL,1UL,virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003337 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3338 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003339 break;
3340 }
3341 case RandomVirtualPixelMethod:
3342 {
3343 if (cache_info->random_info == (RandomInfo *) NULL)
3344 cache_info->random_info=AcquireRandomInfo();
3345 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003346 RandomX(cache_info->random_info,cache_info->columns),
3347 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003348 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003349 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3350 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003351 break;
3352 }
3353 case DitherVirtualPixelMethod:
3354 {
3355 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003356 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003357 1UL,1UL,virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003358 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3359 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003360 break;
3361 }
3362 case TileVirtualPixelMethod:
3363 {
3364 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3365 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3366 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3367 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3368 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003369 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3370 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003371 break;
3372 }
3373 case MirrorVirtualPixelMethod:
3374 {
3375 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3376 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003377 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003378 x_modulo.remainder-1L;
3379 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3380 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003381 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003382 y_modulo.remainder-1L;
3383 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3384 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3385 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003386 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3387 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003388 break;
3389 }
3390 case CheckerTileVirtualPixelMethod:
3391 {
3392 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3393 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3394 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3395 {
3396 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003397 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003398 break;
3399 }
3400 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3401 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3402 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003403 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3404 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003405 break;
3406 }
3407 case HorizontalTileVirtualPixelMethod:
3408 {
cristybb503372010-05-27 20:51:26 +00003409 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003410 {
3411 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003412 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003413 break;
3414 }
3415 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3416 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3417 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3418 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3419 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003420 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3421 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003422 break;
3423 }
3424 case VerticalTileVirtualPixelMethod:
3425 {
cristybb503372010-05-27 20:51:26 +00003426 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
cristy3ed852e2009-09-05 21:47:34 +00003427 {
3428 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003429 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003430 break;
3431 }
3432 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3433 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3434 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3435 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3436 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003437 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3438 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003439 break;
3440 }
3441 case HorizontalTileEdgeVirtualPixelMethod:
3442 {
3443 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3444 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003445 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003446 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003447 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3448 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003449 break;
3450 }
3451 case VerticalTileEdgeVirtualPixelMethod:
3452 {
3453 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3454 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003455 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003456 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003457 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3458 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003459 break;
3460 }
3461 }
3462 if (p == (const PixelPacket *) NULL)
3463 break;
3464 *q++=(*p);
cristyc3ec0d42010-04-07 01:18:08 +00003465 if ((indexes != (IndexPacket *) NULL) &&
3466 (virtual_indexes != (const IndexPacket *) NULL))
3467 *indexes++=(*virtual_indexes);
cristy3ed852e2009-09-05 21:47:34 +00003468 continue;
3469 }
3470 /*
3471 Transfer a run of pixels.
3472 */
3473 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,
cristybb503372010-05-27 20:51:26 +00003474 (size_t) length,1UL,virtual_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003475 if (p == (const PixelPacket *) NULL)
3476 break;
cristyc3ec0d42010-04-07 01:18:08 +00003477 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,virtual_nexus[0]);
cristy8f036fe2010-09-18 02:02:00 +00003478 (void) memcpy(q,p,(size_t) length*sizeof(*p));
cristy3ed852e2009-09-05 21:47:34 +00003479 q+=length;
cristyc3ec0d42010-04-07 01:18:08 +00003480 if ((indexes != (IndexPacket *) NULL) &&
3481 (virtual_indexes != (const IndexPacket *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003482 {
cristy8f036fe2010-09-18 02:02:00 +00003483 (void) memcpy(indexes,virtual_indexes,(size_t) length*
cristyc3ec0d42010-04-07 01:18:08 +00003484 sizeof(*virtual_indexes));
3485 indexes+=length;
cristy3ed852e2009-09-05 21:47:34 +00003486 }
3487 }
3488 }
3489 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3490 return(pixels);
3491}
3492
3493/*
3494%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3495% %
3496% %
3497% %
3498+ G e t V i r t u a l P i x e l C a c h e %
3499% %
3500% %
3501% %
3502%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3503%
3504% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3505% cache as defined by the geometry parameters. A pointer to the pixels
3506% is returned if the pixels are transferred, otherwise a NULL is returned.
3507%
3508% The format of the GetVirtualPixelCache() method is:
3509%
3510% const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003511% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3512% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003513% ExceptionInfo *exception)
3514%
3515% A description of each parameter follows:
3516%
3517% o image: the image.
3518%
3519% o virtual_pixel_method: the virtual pixel method.
3520%
3521% o x,y,columns,rows: These values define the perimeter of a region of
3522% pixels.
3523%
3524% o exception: return any errors or warnings in this structure.
3525%
3526*/
3527static const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003528 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3529 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003530{
3531 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003532 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003533
cristy5c9e6f22010-09-17 17:31:01 +00003534 const int
3535 id = GetOpenMPThreadId();
3536
cristy3ed852e2009-09-05 21:47:34 +00003537 cache_info=(CacheInfo *) image->cache;
cristy6ebe97c2010-07-03 01:17:28 +00003538 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003539 return(GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3540 cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00003541}
3542
3543/*
3544%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3545% %
3546% %
3547% %
3548% G e t V i r t u a l P i x e l Q u e u e %
3549% %
3550% %
3551% %
3552%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3553%
3554% GetVirtualPixelQueue() returns the virtual pixels associated with the
3555% last call to QueueAuthenticPixels() or GetVirtualPixels().
3556%
3557% The format of the GetVirtualPixelQueue() method is:
3558%
3559% const PixelPacket *GetVirtualPixelQueue(const Image image)
3560%
3561% A description of each parameter follows:
3562%
3563% o image: the image.
3564%
3565*/
3566MagickExport const PixelPacket *GetVirtualPixelQueue(const Image *image)
3567{
3568 CacheInfo
3569 *cache_info;
3570
cristy2036f5c2010-09-19 21:18:17 +00003571 const int
3572 id = GetOpenMPThreadId();
3573
cristy3ed852e2009-09-05 21:47:34 +00003574 assert(image != (const Image *) NULL);
3575 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003576 assert(image->cache != (Cache) NULL);
3577 cache_info=(CacheInfo *) image->cache;
3578 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003579 if (cache_info->methods.get_virtual_pixels_handler !=
3580 (GetVirtualPixelsHandler) NULL)
3581 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003582 assert(id < (int) cache_info->number_threads);
3583 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003584}
3585
3586/*
3587%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3588% %
3589% %
3590% %
3591% G e t V i r t u a l P i x e l s %
3592% %
3593% %
3594% %
3595%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3596%
3597% GetVirtualPixels() returns an immutable pixel region. If the
3598% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003599% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003600% copy of the pixels or it may point to the original pixels in memory.
3601% Performance is maximized if the selected region is part of one row, or one
3602% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003603% (without a copy) if the image is in memory, or in a memory-mapped file. The
3604% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003605%
3606% Pixels accessed via the returned pointer represent a simple array of type
3607% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
3608% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to access
3609% the black color component or to obtain the colormap indexes (of type
3610% IndexPacket) corresponding to the region.
3611%
3612% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3613%
3614% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3615% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3616% GetCacheViewAuthenticPixels() instead.
3617%
3618% The format of the GetVirtualPixels() method is:
3619%
cristybb503372010-05-27 20:51:26 +00003620% const PixelPacket *GetVirtualPixels(const Image *image,const ssize_t x,
3621% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003622% ExceptionInfo *exception)
3623%
3624% A description of each parameter follows:
3625%
3626% o image: the image.
3627%
3628% o x,y,columns,rows: These values define the perimeter of a region of
3629% pixels.
3630%
3631% o exception: return any errors or warnings in this structure.
3632%
3633*/
3634MagickExport const PixelPacket *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003635 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3636 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003637{
3638 CacheInfo
3639 *cache_info;
3640
cristy2036f5c2010-09-19 21:18:17 +00003641 const int
3642 id = GetOpenMPThreadId();
3643
cristy3ed852e2009-09-05 21:47:34 +00003644 assert(image != (const Image *) NULL);
3645 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003646 assert(image->cache != (Cache) NULL);
3647 cache_info=(CacheInfo *) image->cache;
3648 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003649 if (cache_info->methods.get_virtual_pixel_handler !=
3650 (GetVirtualPixelHandler) NULL)
3651 return(cache_info->methods.get_virtual_pixel_handler(image,
3652 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003653 assert(id < (int) cache_info->number_threads);
3654 return(GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3655 columns,rows,cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00003656}
3657
3658/*
3659%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3660% %
3661% %
3662% %
3663+ 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 %
3664% %
3665% %
3666% %
3667%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3668%
3669% GetVirtualPixelsCache() returns the pixels associated with the last call
3670% to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3671%
3672% The format of the GetVirtualPixelsCache() method is:
3673%
3674% PixelPacket *GetVirtualPixelsCache(const Image *image)
3675%
3676% A description of each parameter follows:
3677%
3678% o image: the image.
3679%
3680*/
3681static const PixelPacket *GetVirtualPixelsCache(const Image *image)
3682{
3683 CacheInfo
3684 *cache_info;
3685
cristy5c9e6f22010-09-17 17:31:01 +00003686 const int
3687 id = GetOpenMPThreadId();
3688
cristy3ed852e2009-09-05 21:47:34 +00003689 cache_info=(CacheInfo *) image->cache;
cristy6ebe97c2010-07-03 01:17:28 +00003690 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003691 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003692}
3693
3694/*
3695%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3696% %
3697% %
3698% %
3699+ G e t V i r t u a l P i x e l s N e x u s %
3700% %
3701% %
3702% %
3703%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3704%
3705% GetVirtualPixelsNexus() returns the pixels associated with the specified
3706% cache nexus.
3707%
3708% The format of the GetVirtualPixelsNexus() method is:
3709%
3710% const IndexPacket *GetVirtualPixelsNexus(const Cache cache,
3711% NexusInfo *nexus_info)
3712%
3713% A description of each parameter follows:
3714%
3715% o cache: the pixel cache.
3716%
3717% o nexus_info: the cache nexus to return the colormap pixels.
3718%
3719*/
3720MagickExport const PixelPacket *GetVirtualPixelsNexus(const Cache cache,
3721 NexusInfo *nexus_info)
3722{
3723 CacheInfo
3724 *cache_info;
3725
3726 if (cache == (Cache) NULL)
3727 return((PixelPacket *) NULL);
3728 cache_info=(CacheInfo *) cache;
3729 assert(cache_info->signature == MagickSignature);
3730 if (cache_info->storage_class == UndefinedClass)
3731 return((PixelPacket *) NULL);
3732 return((const PixelPacket *) nexus_info->pixels);
3733}
3734
3735/*
3736%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3737% %
3738% %
3739% %
3740+ M a s k P i x e l C a c h e N e x u s %
3741% %
3742% %
3743% %
3744%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3745%
3746% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3747% The method returns MagickTrue if the pixel region is masked, otherwise
3748% MagickFalse.
3749%
3750% The format of the MaskPixelCacheNexus() method is:
3751%
3752% MagickBooleanType MaskPixelCacheNexus(Image *image,
3753% NexusInfo *nexus_info,ExceptionInfo *exception)
3754%
3755% A description of each parameter follows:
3756%
3757% o image: the image.
3758%
3759% o nexus_info: the cache nexus to clip.
3760%
3761% o exception: return any errors or warnings in this structure.
3762%
3763*/
3764
3765static inline void MagickPixelCompositeMask(const MagickPixelPacket *p,
3766 const MagickRealType alpha,const MagickPixelPacket *q,
3767 const MagickRealType beta,MagickPixelPacket *composite)
3768{
3769 MagickRealType
3770 gamma;
3771
3772 if (alpha == TransparentOpacity)
3773 {
3774 *composite=(*q);
3775 return;
3776 }
3777 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3778 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3779 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3780 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3781 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3782 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3783 composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
3784}
3785
3786static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3787 ExceptionInfo *exception)
3788{
3789 CacheInfo
3790 *cache_info;
3791
3792 MagickPixelPacket
3793 alpha,
3794 beta;
3795
3796 MagickSizeType
3797 number_pixels;
3798
3799 NexusInfo
3800 **clip_nexus,
3801 **image_nexus;
3802
3803 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003804 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003805
3806 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003807 *restrict nexus_indexes,
3808 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003809
cristy3ed852e2009-09-05 21:47:34 +00003810 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003811 *restrict p,
3812 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003813
cristye076a6e2010-08-15 19:59:43 +00003814 register ssize_t
3815 i;
3816
cristy3ed852e2009-09-05 21:47:34 +00003817 /*
3818 Apply clip mask.
3819 */
3820 if (image->debug != MagickFalse)
3821 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3822 if (image->mask == (Image *) NULL)
3823 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +00003824 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00003825 if (cache_info == (Cache) NULL)
3826 return(MagickFalse);
3827 image_nexus=AcquirePixelCacheNexus(1);
3828 clip_nexus=AcquirePixelCacheNexus(1);
3829 if ((image_nexus == (NexusInfo **) NULL) ||
3830 (clip_nexus == (NexusInfo **) NULL))
3831 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy09449f72010-01-23 03:08:36 +00003832 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,
3833 nexus_info->region.y,nexus_info->region.width,nexus_info->region.height,
3834 image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003835 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
3836 q=nexus_info->pixels;
3837 nexus_indexes=nexus_info->indexes;
3838 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3839 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3840 nexus_info->region.height,clip_nexus[0],&image->exception);
3841 GetMagickPixelPacket(image,&alpha);
3842 GetMagickPixelPacket(image,&beta);
3843 number_pixels=(MagickSizeType) nexus_info->region.width*
3844 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +00003845 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +00003846 {
3847 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
3848 break;
3849 SetMagickPixelPacket(image,p,indexes+i,&alpha);
3850 SetMagickPixelPacket(image,q,nexus_indexes+i,&beta);
3851 MagickPixelCompositeMask(&beta,(MagickRealType) PixelIntensityToQuantum(r),
3852 &alpha,alpha.opacity,&beta);
cristyce70c172010-01-07 17:15:30 +00003853 q->red=ClampToQuantum(beta.red);
3854 q->green=ClampToQuantum(beta.green);
3855 q->blue=ClampToQuantum(beta.blue);
3856 q->opacity=ClampToQuantum(beta.opacity);
cristy3ed852e2009-09-05 21:47:34 +00003857 if (cache_info->active_index_channel != MagickFalse)
3858 nexus_indexes[i]=indexes[i];
3859 p++;
3860 q++;
3861 r++;
3862 }
3863 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3864 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +00003865 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003866 return(MagickFalse);
3867 return(MagickTrue);
3868}
3869
3870/*
3871%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3872% %
3873% %
3874% %
3875+ O p e n P i x e l C a c h e %
3876% %
3877% %
3878% %
3879%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3880%
3881% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3882% dimensions, allocating space for the image pixels and optionally the
3883% colormap indexes, and memory mapping the cache if it is disk based. The
3884% cache nexus array is initialized as well.
3885%
3886% The format of the OpenPixelCache() method is:
3887%
3888% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3889% ExceptionInfo *exception)
3890%
3891% A description of each parameter follows:
3892%
3893% o image: the image.
3894%
3895% o mode: ReadMode, WriteMode, or IOMode.
3896%
3897% o exception: return any errors or warnings in this structure.
3898%
3899*/
3900
cristyd43a46b2010-01-21 02:13:41 +00003901static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003902{
3903 cache_info->mapped=MagickFalse;
3904 cache_info->pixels=(PixelPacket *) AcquireMagickMemory((size_t)
3905 cache_info->length);
3906 if (cache_info->pixels == (PixelPacket *) NULL)
3907 {
3908 cache_info->mapped=MagickTrue;
3909 cache_info->pixels=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
3910 cache_info->length);
3911 }
3912}
3913
3914static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3915{
3916 CacheInfo
3917 *cache_info;
3918
3919 MagickOffsetType
3920 count,
3921 extent,
3922 offset;
3923
3924 cache_info=(CacheInfo *) image->cache;
3925 if (image->debug != MagickFalse)
3926 {
3927 char
3928 format[MaxTextExtent],
3929 message[MaxTextExtent];
3930
cristyb9080c92009-12-01 20:13:26 +00003931 (void) FormatMagickSize(length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00003932 (void) FormatMagickString(message,MaxTextExtent,
cristy2ce15c92010-03-12 14:03:41 +00003933 "extend %s (%s[%d], disk, %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003934 cache_info->cache_filename,cache_info->file,format);
3935 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3936 }
3937 if (length != (MagickSizeType) ((MagickOffsetType) length))
3938 return(MagickFalse);
3939 extent=(MagickOffsetType) MagickSeek(cache_info->file,0,SEEK_END);
3940 if (extent < 0)
3941 return(MagickFalse);
3942 if ((MagickSizeType) extent >= length)
3943 return(MagickTrue);
3944 offset=(MagickOffsetType) length-1;
3945 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3946 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3947}
3948
3949static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3950 ExceptionInfo *exception)
3951{
3952 char
3953 format[MaxTextExtent],
3954 message[MaxTextExtent];
3955
3956 CacheInfo
3957 *cache_info,
3958 source_info;
3959
3960 MagickSizeType
3961 length,
3962 number_pixels;
3963
3964 MagickStatusType
3965 status;
3966
3967 size_t
cristye076a6e2010-08-15 19:59:43 +00003968 columns,
cristy3ed852e2009-09-05 21:47:34 +00003969 packet_size;
3970
cristy3ed852e2009-09-05 21:47:34 +00003971 if (image->debug != MagickFalse)
3972 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3973 if ((image->columns == 0) || (image->rows == 0))
3974 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3975 cache_info=(CacheInfo *) image->cache;
3976 source_info=(*cache_info);
3977 source_info.file=(-1);
cristye8c25f92010-06-03 00:53:06 +00003978 (void) FormatMagickString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3979 image->filename,(double) GetImageIndexInList(image));
cristy87528ea2009-09-10 14:53:56 +00003980 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +00003981 cache_info->rows=image->rows;
3982 cache_info->columns=image->columns;
3983 cache_info->active_index_channel=((image->storage_class == PseudoClass) ||
3984 (image->colorspace == CMYKColorspace)) ? MagickTrue : MagickFalse;
cristy73724512010-04-12 14:43:14 +00003985 if (image->ping != MagickFalse)
3986 {
3987 cache_info->storage_class=image->storage_class;
3988 cache_info->colorspace=image->colorspace;
3989 cache_info->type=PingCache;
3990 cache_info->pixels=(PixelPacket *) NULL;
3991 cache_info->indexes=(IndexPacket *) NULL;
3992 cache_info->length=0;
3993 return(MagickTrue);
3994 }
cristy3ed852e2009-09-05 21:47:34 +00003995 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3996 packet_size=sizeof(PixelPacket);
3997 if (cache_info->active_index_channel != MagickFalse)
3998 packet_size+=sizeof(IndexPacket);
3999 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00004000 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00004001 if (cache_info->columns != columns)
4002 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4003 image->filename);
4004 cache_info->length=length;
4005 status=AcquireMagickResource(AreaResource,cache_info->length);
4006 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4007 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4008 {
4009 status=AcquireMagickResource(MemoryResource,cache_info->length);
4010 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4011 (cache_info->type == MemoryCache))
4012 {
cristyd43a46b2010-01-21 02:13:41 +00004013 AllocatePixelCachePixels(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004014 if (cache_info->pixels == (PixelPacket *) NULL)
4015 cache_info->pixels=source_info.pixels;
4016 else
4017 {
4018 /*
4019 Create memory pixel cache.
4020 */
4021 if (image->debug != MagickFalse)
4022 {
cristy97e7a572009-12-05 15:07:53 +00004023 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004024 format);
cristy3ed852e2009-09-05 21:47:34 +00004025 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004026 "open %s (%s memory, %.20gx%.20g %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00004027 cache_info->mapped != MagickFalse ? "anonymous" : "heap",
cristye8c25f92010-06-03 00:53:06 +00004028 (double) cache_info->columns,(double) cache_info->rows,
4029 format);
cristy3ed852e2009-09-05 21:47:34 +00004030 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4031 message);
4032 }
4033 cache_info->storage_class=image->storage_class;
4034 cache_info->colorspace=image->colorspace;
4035 cache_info->type=MemoryCache;
4036 cache_info->indexes=(IndexPacket *) NULL;
4037 if (cache_info->active_index_channel != MagickFalse)
4038 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4039 number_pixels);
4040 if (source_info.storage_class != UndefinedClass)
4041 {
4042 status|=ClonePixelCachePixels(cache_info,&source_info,
4043 exception);
4044 RelinquishPixelCachePixels(&source_info);
4045 }
4046 return(MagickTrue);
4047 }
4048 }
4049 RelinquishMagickResource(MemoryResource,cache_info->length);
4050 }
4051 /*
4052 Create pixel cache on disk.
4053 */
4054 status=AcquireMagickResource(DiskResource,cache_info->length);
4055 if (status == MagickFalse)
4056 {
4057 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4058 "CacheResourcesExhausted","`%s'",image->filename);
4059 return(MagickFalse);
4060 }
4061 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4062 {
4063 RelinquishMagickResource(DiskResource,cache_info->length);
4064 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4065 image->filename);
4066 return(MagickFalse);
4067 }
4068 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4069 cache_info->length);
4070 if (status == MagickFalse)
4071 {
4072 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4073 image->filename);
4074 return(MagickFalse);
4075 }
4076 cache_info->storage_class=image->storage_class;
4077 cache_info->colorspace=image->colorspace;
4078 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4079 status=AcquireMagickResource(AreaResource,cache_info->length);
4080 if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4081 cache_info->type=DiskCache;
4082 else
4083 {
4084 status=AcquireMagickResource(MapResource,cache_info->length);
4085 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4086 (cache_info->type != MemoryCache))
4087 cache_info->type=DiskCache;
4088 else
4089 {
4090 cache_info->pixels=(PixelPacket *) MapBlob(cache_info->file,mode,
4091 cache_info->offset,(size_t) cache_info->length);
4092 if (cache_info->pixels == (PixelPacket *) NULL)
4093 {
4094 cache_info->pixels=source_info.pixels;
4095 cache_info->type=DiskCache;
4096 }
4097 else
4098 {
4099 /*
4100 Create file-backed memory-mapped pixel cache.
4101 */
4102 (void) ClosePixelCacheOnDisk(cache_info);
4103 cache_info->type=MapCache;
4104 cache_info->mapped=MagickTrue;
4105 cache_info->indexes=(IndexPacket *) NULL;
4106 if (cache_info->active_index_channel != MagickFalse)
4107 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4108 number_pixels);
4109 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4110 {
4111 status=ClonePixelCachePixels(cache_info,&source_info,
4112 exception);
4113 RelinquishPixelCachePixels(&source_info);
4114 }
4115 if (image->debug != MagickFalse)
4116 {
cristy97e7a572009-12-05 15:07:53 +00004117 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004118 format);
cristy3ed852e2009-09-05 21:47:34 +00004119 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004120 "open %s (%s[%d], memory-mapped, %.20gx%.20g %sB)",
cristy3ed852e2009-09-05 21:47:34 +00004121 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004122 cache_info->file,(double) cache_info->columns,(double)
4123 cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004124 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4125 message);
4126 }
4127 return(MagickTrue);
4128 }
4129 }
4130 RelinquishMagickResource(MapResource,cache_info->length);
4131 }
4132 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4133 {
4134 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4135 RelinquishPixelCachePixels(&source_info);
4136 }
4137 if (image->debug != MagickFalse)
4138 {
cristyb9080c92009-12-01 20:13:26 +00004139 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00004140 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004141 "open %s (%s[%d], disk, %.20gx%.20g %sB)",cache_info->filename,
4142 cache_info->cache_filename,cache_info->file,(double)
4143 cache_info->columns,(double) cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004144 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4145 }
4146 return(MagickTrue);
4147}
4148
4149/*
4150%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4151% %
4152% %
4153% %
4154+ P e r s i s t P i x e l C a c h e %
4155% %
4156% %
4157% %
4158%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4159%
4160% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4161% persistent pixel cache is one that resides on disk and is not destroyed
4162% when the program exits.
4163%
4164% The format of the PersistPixelCache() method is:
4165%
4166% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4167% const MagickBooleanType attach,MagickOffsetType *offset,
4168% ExceptionInfo *exception)
4169%
4170% A description of each parameter follows:
4171%
4172% o image: the image.
4173%
4174% o filename: the persistent pixel cache filename.
4175%
cristy01b7eb02009-09-10 23:10:14 +00004176% o attach: A value other than zero initializes the persistent pixel
4177% cache.
4178%
cristy3ed852e2009-09-05 21:47:34 +00004179% o initialize: A value other than zero initializes the persistent pixel
4180% cache.
4181%
4182% o offset: the offset in the persistent cache to store pixels.
4183%
4184% o exception: return any errors or warnings in this structure.
4185%
4186*/
4187MagickExport MagickBooleanType PersistPixelCache(Image *image,
4188 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4189 ExceptionInfo *exception)
4190{
4191 CacheInfo
4192 *cache_info,
4193 *clone_info;
4194
4195 Image
4196 clone_image;
4197
cristy3ed852e2009-09-05 21:47:34 +00004198 MagickBooleanType
4199 status;
4200
cristye076a6e2010-08-15 19:59:43 +00004201 ssize_t
4202 page_size;
4203
cristy3ed852e2009-09-05 21:47:34 +00004204 assert(image != (Image *) NULL);
4205 assert(image->signature == MagickSignature);
4206 if (image->debug != MagickFalse)
4207 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4208 assert(image->cache != (void *) NULL);
4209 assert(filename != (const char *) NULL);
4210 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004211 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004212 cache_info=(CacheInfo *) image->cache;
4213 assert(cache_info->signature == MagickSignature);
4214 if (attach != MagickFalse)
4215 {
4216 /*
cristy01b7eb02009-09-10 23:10:14 +00004217 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004218 */
4219 if (image->debug != MagickFalse)
4220 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4221 "attach persistent cache");
4222 (void) CopyMagickString(cache_info->cache_filename,filename,
4223 MaxTextExtent);
4224 cache_info->type=DiskCache;
4225 cache_info->offset=(*offset);
4226 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4227 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004228 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004229 return(MagickTrue);
4230 }
cristy01b7eb02009-09-10 23:10:14 +00004231 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4232 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004233 {
cristyf84a1932010-01-03 18:00:18 +00004234 LockSemaphoreInfo(cache_info->semaphore);
cristy09449f72010-01-23 03:08:36 +00004235 if ((cache_info->mode != ReadMode) &&
4236 (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004237 (cache_info->reference_count == 1))
4238 {
4239 int
4240 status;
4241
4242 /*
cristy01b7eb02009-09-10 23:10:14 +00004243 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004244 */
4245 status=rename(cache_info->cache_filename,filename);
4246 if (status == 0)
4247 {
4248 (void) CopyMagickString(cache_info->cache_filename,filename,
4249 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004250 *offset+=cache_info->length+page_size-(cache_info->length %
4251 page_size);
cristyf84a1932010-01-03 18:00:18 +00004252 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004253 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004254 if (image->debug != MagickFalse)
4255 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4256 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004257 return(MagickTrue);
4258 }
4259 }
cristyf84a1932010-01-03 18:00:18 +00004260 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004261 }
4262 /*
cristy01b7eb02009-09-10 23:10:14 +00004263 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004264 */
4265 clone_image=(*image);
4266 clone_info=(CacheInfo *) clone_image.cache;
4267 image->cache=ClonePixelCache(cache_info);
4268 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4269 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4270 cache_info->type=DiskCache;
4271 cache_info->offset=(*offset);
4272 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004273 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004274 if (status != MagickFalse)
cristyabd6e372010-09-15 19:11:26 +00004275 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
cristy688f07b2009-09-27 15:19:13 +00004276 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004277 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4278 return(status);
4279}
4280
4281/*
4282%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4283% %
4284% %
4285% %
4286+ Q u e u e A u t h e n t i c N e x u s %
4287% %
4288% %
4289% %
4290%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4291%
4292% QueueAuthenticNexus() allocates an region to store image pixels as defined
4293% by the region rectangle and returns a pointer to the region. This region is
4294% subsequently transferred from the pixel cache with
4295% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4296% pixels are transferred, otherwise a NULL is returned.
4297%
4298% The format of the QueueAuthenticNexus() method is:
4299%
cristy5f959472010-05-27 22:19:46 +00004300% PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
4301% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004302% NexusInfo *nexus_info,ExceptionInfo *exception)
4303%
4304% A description of each parameter follows:
4305%
4306% o image: the image.
4307%
4308% o x,y,columns,rows: These values define the perimeter of a region of
4309% pixels.
4310%
4311% o nexus_info: the cache nexus to set.
4312%
4313% o exception: return any errors or warnings in this structure.
4314%
4315*/
cristybb503372010-05-27 20:51:26 +00004316MagickExport PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy30097232010-07-01 02:16:30 +00004317 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
4318 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004319{
4320 CacheInfo
4321 *cache_info;
4322
4323 MagickOffsetType
4324 offset;
4325
4326 MagickSizeType
4327 number_pixels;
4328
4329 RectangleInfo
4330 region;
4331
4332 /*
4333 Validate pixel cache geometry.
4334 */
cristy77ff0282010-09-13 00:51:10 +00004335 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
4336 if (cache_info == (Cache) NULL)
4337 return((PixelPacket *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004338 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4339 {
4340 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4341 "NoPixelsDefinedInCache","`%s'",image->filename);
4342 return((PixelPacket *) NULL);
4343 }
cristybb503372010-05-27 20:51:26 +00004344 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4345 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004346 {
4347 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4348 "PixelsAreNotAuthentic","`%s'",image->filename);
4349 return((PixelPacket *) NULL);
4350 }
4351 offset=(MagickOffsetType) y*cache_info->columns+x;
4352 if (offset < 0)
4353 return((PixelPacket *) NULL);
4354 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4355 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4356 if ((MagickSizeType) offset >= number_pixels)
4357 return((PixelPacket *) NULL);
4358 /*
4359 Return pixel cache.
4360 */
4361 region.x=x;
4362 region.y=y;
4363 region.width=columns;
4364 region.height=rows;
4365 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4366}
4367
4368/*
4369%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4370% %
4371% %
4372% %
4373+ 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 %
4374% %
4375% %
4376% %
4377%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4378%
4379% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4380% defined by the region rectangle and returns a pointer to the region. This
4381% region is subsequently transferred from the pixel cache with
4382% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4383% pixels are transferred, otherwise a NULL is returned.
4384%
4385% The format of the QueueAuthenticPixelsCache() method is:
4386%
cristybb503372010-05-27 20:51:26 +00004387% PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4388% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004389% ExceptionInfo *exception)
4390%
4391% A description of each parameter follows:
4392%
4393% o image: the image.
4394%
4395% o x,y,columns,rows: These values define the perimeter of a region of
4396% pixels.
4397%
4398% o exception: return any errors or warnings in this structure.
4399%
4400*/
cristybb503372010-05-27 20:51:26 +00004401static PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4402 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004403 ExceptionInfo *exception)
4404{
4405 CacheInfo
4406 *cache_info;
4407
cristy5c9e6f22010-09-17 17:31:01 +00004408 const int
4409 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004410
cristy77ff0282010-09-13 00:51:10 +00004411 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00004412 if (cache_info == (Cache) NULL)
4413 return((PixelPacket *) NULL);
cristy6ebe97c2010-07-03 01:17:28 +00004414 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00004415 return(QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4416 exception));
cristy3ed852e2009-09-05 21:47:34 +00004417}
4418
4419/*
4420%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4421% %
4422% %
4423% %
4424% Q u e u e A u t h e n t i c P i x e l s %
4425% %
4426% %
4427% %
4428%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4429%
4430% QueueAuthenticPixels() queues a mutable pixel region. If the region is
4431% successfully intialized a pointer to a PixelPacket array representing the
4432% region is returned, otherwise NULL is returned. The returned pointer may
4433% point to a temporary working buffer for the pixels or it may point to the
4434% final location of the pixels in memory.
4435%
4436% Write-only access means that any existing pixel values corresponding to
4437% the region are ignored. This is useful if the initial image is being
4438% created from scratch, or if the existing pixel values are to be
4439% completely replaced without need to refer to their pre-existing values.
4440% The application is free to read and write the pixel buffer returned by
4441% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4442% initialize the pixel array values. Initializing pixel array values is the
4443% application's responsibility.
4444%
4445% Performance is maximized if the selected region is part of one row, or
4446% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004447% pixels in-place (without a copy) if the image is in memory, or in a
4448% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004449% by the user.
4450%
4451% Pixels accessed via the returned pointer represent a simple array of type
4452% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
4453% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
4454% the black color component or the colormap indexes (of type IndexPacket)
4455% corresponding to the region. Once the PixelPacket (and/or IndexPacket)
4456% array has been updated, the changes must be saved back to the underlying
4457% image using SyncAuthenticPixels() or they may be lost.
4458%
4459% The format of the QueueAuthenticPixels() method is:
4460%
cristy5f959472010-05-27 22:19:46 +00004461% PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4462% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004463% ExceptionInfo *exception)
4464%
4465% A description of each parameter follows:
4466%
4467% o image: the image.
4468%
4469% o x,y,columns,rows: These values define the perimeter of a region of
4470% pixels.
4471%
4472% o exception: return any errors or warnings in this structure.
4473%
4474*/
cristybb503372010-05-27 20:51:26 +00004475MagickExport PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4476 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004477 ExceptionInfo *exception)
4478{
4479 CacheInfo
4480 *cache_info;
4481
cristy2036f5c2010-09-19 21:18:17 +00004482 const int
4483 id = GetOpenMPThreadId();
4484
cristy3ed852e2009-09-05 21:47:34 +00004485 assert(image != (Image *) NULL);
4486 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004487 assert(image->cache != (Cache) NULL);
4488 cache_info=(CacheInfo *) image->cache;
4489 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004490 if (cache_info->methods.queue_authentic_pixels_handler !=
4491 (QueueAuthenticPixelsHandler) NULL)
4492 return(cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4493 rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00004494 assert(id < (int) cache_info->number_threads);
4495 return(QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4496 exception));
cristy3ed852e2009-09-05 21:47:34 +00004497}
4498
4499/*
4500%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4501% %
4502% %
4503% %
4504+ R e a d P i x e l C a c h e I n d e x e s %
4505% %
4506% %
4507% %
4508%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4509%
4510% ReadPixelCacheIndexes() reads colormap indexes from the specified region of
4511% the pixel cache.
4512%
4513% The format of the ReadPixelCacheIndexes() method is:
4514%
4515% MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4516% NexusInfo *nexus_info,ExceptionInfo *exception)
4517%
4518% A description of each parameter follows:
4519%
4520% o cache_info: the pixel cache.
4521%
4522% o nexus_info: the cache nexus to read the colormap indexes.
4523%
4524% o exception: return any errors or warnings in this structure.
4525%
4526*/
4527static MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4528 NexusInfo *nexus_info,ExceptionInfo *exception)
4529{
4530 MagickOffsetType
4531 count,
4532 offset;
4533
4534 MagickSizeType
4535 length,
4536 number_pixels;
4537
4538 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004539 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004540
cristybb503372010-05-27 20:51:26 +00004541 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004542 y;
4543
cristybb503372010-05-27 20:51:26 +00004544 size_t
cristy3ed852e2009-09-05 21:47:34 +00004545 rows;
4546
cristy3ed852e2009-09-05 21:47:34 +00004547 if (cache_info->active_index_channel == MagickFalse)
4548 return(MagickFalse);
4549 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4550 return(MagickTrue);
4551 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4552 nexus_info->region.x;
4553 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
4554 rows=nexus_info->region.height;
4555 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004556 q=nexus_info->indexes;
4557 switch (cache_info->type)
4558 {
4559 case MemoryCache:
4560 case MapCache:
4561 {
4562 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004563 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004564
4565 /*
4566 Read indexes from memory.
4567 */
cristydd341db2010-03-04 19:06:38 +00004568 if ((cache_info->columns == nexus_info->region.width) &&
4569 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4570 {
4571 length=number_pixels;
4572 rows=1UL;
4573 }
cristy3ed852e2009-09-05 21:47:34 +00004574 p=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00004575 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004576 {
cristy8f036fe2010-09-18 02:02:00 +00004577 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00004578 p+=cache_info->columns;
4579 q+=nexus_info->region.width;
4580 }
4581 break;
4582 }
4583 case DiskCache:
4584 {
4585 /*
4586 Read indexes from disk.
4587 */
4588 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4589 {
4590 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4591 cache_info->cache_filename);
4592 return(MagickFalse);
4593 }
cristydd341db2010-03-04 19:06:38 +00004594 if ((cache_info->columns == nexus_info->region.width) &&
4595 (number_pixels < MagickMaxBufferExtent))
4596 {
4597 length=number_pixels;
4598 rows=1UL;
4599 }
cristy3ed852e2009-09-05 21:47:34 +00004600 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004601 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004602 {
4603 count=ReadPixelCacheRegion(cache_info,cache_info->offset+number_pixels*
4604 sizeof(PixelPacket)+offset*sizeof(*q),length,(unsigned char *) q);
4605 if ((MagickSizeType) count < length)
4606 break;
4607 offset+=cache_info->columns;
4608 q+=nexus_info->region.width;
4609 }
cristybb503372010-05-27 20:51:26 +00004610 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004611 {
4612 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4613 cache_info->cache_filename);
4614 return(MagickFalse);
4615 }
4616 break;
4617 }
4618 default:
4619 break;
4620 }
4621 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004622 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004623 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004624 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004625 nexus_info->region.width,(double) nexus_info->region.height,(double)
4626 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004627 return(MagickTrue);
4628}
4629
4630/*
4631%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4632% %
4633% %
4634% %
4635+ R e a d P i x e l C a c h e P i x e l s %
4636% %
4637% %
4638% %
4639%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4640%
4641% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4642% cache.
4643%
4644% The format of the ReadPixelCachePixels() method is:
4645%
4646% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4647% NexusInfo *nexus_info,ExceptionInfo *exception)
4648%
4649% A description of each parameter follows:
4650%
4651% o cache_info: the pixel cache.
4652%
4653% o nexus_info: the cache nexus to read the pixels.
4654%
4655% o exception: return any errors or warnings in this structure.
4656%
4657*/
4658static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4659 NexusInfo *nexus_info,ExceptionInfo *exception)
4660{
4661 MagickOffsetType
4662 count,
4663 offset;
4664
4665 MagickSizeType
4666 length,
4667 number_pixels;
4668
cristy3ed852e2009-09-05 21:47:34 +00004669 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004670 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004671
cristye076a6e2010-08-15 19:59:43 +00004672 register ssize_t
4673 y;
4674
cristybb503372010-05-27 20:51:26 +00004675 size_t
cristy3ed852e2009-09-05 21:47:34 +00004676 rows;
4677
cristy3ed852e2009-09-05 21:47:34 +00004678 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4679 return(MagickTrue);
4680 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4681 nexus_info->region.x;
4682 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
4683 rows=nexus_info->region.height;
4684 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004685 q=nexus_info->pixels;
4686 switch (cache_info->type)
4687 {
4688 case MemoryCache:
4689 case MapCache:
4690 {
4691 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004692 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004693
4694 /*
4695 Read pixels from memory.
4696 */
cristydd341db2010-03-04 19:06:38 +00004697 if ((cache_info->columns == nexus_info->region.width) &&
4698 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4699 {
4700 length=number_pixels;
4701 rows=1UL;
4702 }
cristy3ed852e2009-09-05 21:47:34 +00004703 p=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00004704 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004705 {
cristy8f036fe2010-09-18 02:02:00 +00004706 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00004707 p+=cache_info->columns;
4708 q+=nexus_info->region.width;
4709 }
4710 break;
4711 }
4712 case DiskCache:
4713 {
4714 /*
4715 Read pixels from disk.
4716 */
4717 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4718 {
4719 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4720 cache_info->cache_filename);
4721 return(MagickFalse);
4722 }
cristydd341db2010-03-04 19:06:38 +00004723 if ((cache_info->columns == nexus_info->region.width) &&
4724 (number_pixels < MagickMaxBufferExtent))
4725 {
4726 length=number_pixels;
4727 rows=1UL;
4728 }
cristybb503372010-05-27 20:51:26 +00004729 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004730 {
4731 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4732 sizeof(*q),length,(unsigned char *) q);
4733 if ((MagickSizeType) count < length)
4734 break;
4735 offset+=cache_info->columns;
4736 q+=nexus_info->region.width;
4737 }
cristybb503372010-05-27 20:51:26 +00004738 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004739 {
4740 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4741 cache_info->cache_filename);
4742 return(MagickFalse);
4743 }
4744 break;
4745 }
4746 default:
4747 break;
4748 }
4749 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004750 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004751 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004752 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004753 nexus_info->region.width,(double) nexus_info->region.height,(double)
4754 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004755 return(MagickTrue);
4756}
4757
4758/*
4759%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4760% %
4761% %
4762% %
4763+ R e f e r e n c e P i x e l C a c h e %
4764% %
4765% %
4766% %
4767%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4768%
4769% ReferencePixelCache() increments the reference count associated with the
4770% pixel cache returning a pointer to the cache.
4771%
4772% The format of the ReferencePixelCache method is:
4773%
4774% Cache ReferencePixelCache(Cache cache_info)
4775%
4776% A description of each parameter follows:
4777%
4778% o cache_info: the pixel cache.
4779%
4780*/
4781MagickExport Cache ReferencePixelCache(Cache cache)
4782{
4783 CacheInfo
4784 *cache_info;
4785
4786 assert(cache != (Cache *) NULL);
4787 cache_info=(CacheInfo *) cache;
4788 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004789 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004790 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004791 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004792 return(cache_info);
4793}
4794
4795/*
4796%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4797% %
4798% %
4799% %
4800+ S e t P i x e l C a c h e M e t h o d s %
4801% %
4802% %
4803% %
4804%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4805%
4806% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4807%
4808% The format of the SetPixelCacheMethods() method is:
4809%
4810% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4811%
4812% A description of each parameter follows:
4813%
4814% o cache: the pixel cache.
4815%
4816% o cache_methods: Specifies a pointer to a CacheMethods structure.
4817%
4818*/
4819MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4820{
4821 CacheInfo
4822 *cache_info;
4823
4824 GetOneAuthenticPixelFromHandler
4825 get_one_authentic_pixel_from_handler;
4826
4827 GetOneVirtualPixelFromHandler
4828 get_one_virtual_pixel_from_handler;
4829
4830 /*
4831 Set cache pixel methods.
4832 */
4833 assert(cache != (Cache) NULL);
4834 assert(cache_methods != (CacheMethods *) NULL);
4835 cache_info=(CacheInfo *) cache;
4836 assert(cache_info->signature == MagickSignature);
4837 if (cache_info->debug != MagickFalse)
4838 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4839 cache_info->filename);
4840 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4841 cache_info->methods.get_virtual_pixel_handler=
4842 cache_methods->get_virtual_pixel_handler;
4843 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4844 cache_info->methods.destroy_pixel_handler=
4845 cache_methods->destroy_pixel_handler;
4846 if (cache_methods->get_virtual_indexes_from_handler !=
4847 (GetVirtualIndexesFromHandler) NULL)
4848 cache_info->methods.get_virtual_indexes_from_handler=
4849 cache_methods->get_virtual_indexes_from_handler;
4850 if (cache_methods->get_authentic_pixels_handler !=
4851 (GetAuthenticPixelsHandler) NULL)
4852 cache_info->methods.get_authentic_pixels_handler=
4853 cache_methods->get_authentic_pixels_handler;
4854 if (cache_methods->queue_authentic_pixels_handler !=
4855 (QueueAuthenticPixelsHandler) NULL)
4856 cache_info->methods.queue_authentic_pixels_handler=
4857 cache_methods->queue_authentic_pixels_handler;
4858 if (cache_methods->sync_authentic_pixels_handler !=
4859 (SyncAuthenticPixelsHandler) NULL)
4860 cache_info->methods.sync_authentic_pixels_handler=
4861 cache_methods->sync_authentic_pixels_handler;
4862 if (cache_methods->get_authentic_pixels_from_handler !=
4863 (GetAuthenticPixelsFromHandler) NULL)
4864 cache_info->methods.get_authentic_pixels_from_handler=
4865 cache_methods->get_authentic_pixels_from_handler;
4866 if (cache_methods->get_authentic_indexes_from_handler !=
4867 (GetAuthenticIndexesFromHandler) NULL)
4868 cache_info->methods.get_authentic_indexes_from_handler=
4869 cache_methods->get_authentic_indexes_from_handler;
4870 get_one_virtual_pixel_from_handler=
4871 cache_info->methods.get_one_virtual_pixel_from_handler;
4872 if (get_one_virtual_pixel_from_handler !=
4873 (GetOneVirtualPixelFromHandler) NULL)
4874 cache_info->methods.get_one_virtual_pixel_from_handler=
4875 cache_methods->get_one_virtual_pixel_from_handler;
4876 get_one_authentic_pixel_from_handler=
4877 cache_methods->get_one_authentic_pixel_from_handler;
4878 if (get_one_authentic_pixel_from_handler !=
4879 (GetOneAuthenticPixelFromHandler) NULL)
4880 cache_info->methods.get_one_authentic_pixel_from_handler=
4881 cache_methods->get_one_authentic_pixel_from_handler;
4882}
4883
4884/*
4885%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4886% %
4887% %
4888% %
4889+ S e t P i x e l C a c h e N e x u s P i x e l s %
4890% %
4891% %
4892% %
4893%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4894%
4895% SetPixelCacheNexusPixels() defines the region of the cache for the
4896% specified cache nexus.
4897%
4898% The format of the SetPixelCacheNexusPixels() method is:
4899%
4900% PixelPacket SetPixelCacheNexusPixels(const Image *image,
4901% const RectangleInfo *region,NexusInfo *nexus_info,
4902% ExceptionInfo *exception)
4903%
4904% A description of each parameter follows:
4905%
4906% o image: the image.
4907%
4908% o region: A pointer to the RectangleInfo structure that defines the
4909% region of this particular cache nexus.
4910%
4911% o nexus_info: the cache nexus to set.
4912%
4913% o exception: return any errors or warnings in this structure.
4914%
4915*/
cristyabd6e372010-09-15 19:11:26 +00004916
4917static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4918 NexusInfo *nexus_info,ExceptionInfo *exception)
4919{
4920 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4921 return(MagickFalse);
4922 nexus_info->mapped=MagickFalse;
4923 nexus_info->cache=(PixelPacket *) AcquireMagickMemory((size_t)
4924 nexus_info->length);
4925 if (nexus_info->cache == (PixelPacket *) NULL)
4926 {
4927 nexus_info->mapped=MagickTrue;
4928 nexus_info->cache=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
4929 nexus_info->length);
4930 }
4931 if (nexus_info->cache == (PixelPacket *) NULL)
4932 {
4933 (void) ThrowMagickException(exception,GetMagickModule(),
4934 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4935 cache_info->filename);
4936 return(MagickFalse);
4937 }
4938 return(MagickTrue);
4939}
4940
cristy3ed852e2009-09-05 21:47:34 +00004941static PixelPacket *SetPixelCacheNexusPixels(const Image *image,
4942 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4943{
4944 CacheInfo
4945 *cache_info;
4946
4947 MagickBooleanType
4948 status;
4949
cristy3ed852e2009-09-05 21:47:34 +00004950 MagickSizeType
4951 length,
4952 number_pixels;
4953
cristy3ed852e2009-09-05 21:47:34 +00004954 cache_info=(CacheInfo *) image->cache;
4955 assert(cache_info->signature == MagickSignature);
4956 if (cache_info->type == UndefinedCache)
4957 return((PixelPacket *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00004958 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00004959 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
4960 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00004961 {
cristybb503372010-05-27 20:51:26 +00004962 ssize_t
cristybad067a2010-02-15 17:20:55 +00004963 x,
4964 y;
cristy3ed852e2009-09-05 21:47:34 +00004965
cristyeaedf062010-05-29 22:36:02 +00004966 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4967 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00004968 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4969 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00004970 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00004971 ((nexus_info->region.width == cache_info->columns) ||
4972 ((nexus_info->region.width % cache_info->columns) == 0)))))
4973 {
4974 MagickOffsetType
4975 offset;
4976
4977 /*
4978 Pixels are accessed directly from memory.
4979 */
4980 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4981 nexus_info->region.x;
4982 nexus_info->pixels=cache_info->pixels+offset;
4983 nexus_info->indexes=(IndexPacket *) NULL;
4984 if (cache_info->active_index_channel != MagickFalse)
4985 nexus_info->indexes=cache_info->indexes+offset;
4986 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00004987 }
4988 }
4989 /*
4990 Pixels are stored in a cache region until they are synced to the cache.
4991 */
4992 number_pixels=(MagickSizeType) nexus_info->region.width*
4993 nexus_info->region.height;
4994 length=number_pixels*sizeof(PixelPacket);
4995 if (cache_info->active_index_channel != MagickFalse)
4996 length+=number_pixels*sizeof(IndexPacket);
4997 if (nexus_info->cache == (PixelPacket *) NULL)
4998 {
4999 nexus_info->length=length;
5000 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5001 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005002 {
5003 nexus_info->length=0;
5004 return((PixelPacket *) NULL);
5005 }
cristy3ed852e2009-09-05 21:47:34 +00005006 }
5007 else
5008 if (nexus_info->length != length)
5009 {
5010 RelinquishCacheNexusPixels(nexus_info);
5011 nexus_info->length=length;
5012 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5013 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005014 {
5015 nexus_info->length=0;
5016 return((PixelPacket *) NULL);
5017 }
cristy3ed852e2009-09-05 21:47:34 +00005018 }
5019 nexus_info->pixels=nexus_info->cache;
5020 nexus_info->indexes=(IndexPacket *) NULL;
5021 if (cache_info->active_index_channel != MagickFalse)
5022 nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
5023 return(nexus_info->pixels);
5024}
5025
5026/*
5027%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5028% %
5029% %
5030% %
5031% 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 %
5032% %
5033% %
5034% %
5035%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5036%
5037% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5038% pixel cache and returns the previous setting. A virtual pixel is any pixel
5039% access that is outside the boundaries of the image cache.
5040%
5041% The format of the SetPixelCacheVirtualMethod() method is:
5042%
5043% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5044% const VirtualPixelMethod virtual_pixel_method)
5045%
5046% A description of each parameter follows:
5047%
5048% o image: the image.
5049%
5050% o virtual_pixel_method: choose the type of virtual pixel.
5051%
5052*/
5053MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5054 const VirtualPixelMethod virtual_pixel_method)
5055{
5056 CacheInfo
5057 *cache_info;
5058
5059 VirtualPixelMethod
5060 method;
5061
5062 assert(image != (Image *) NULL);
5063 assert(image->signature == MagickSignature);
5064 if (image->debug != MagickFalse)
5065 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5066 assert(image->cache != (Cache) NULL);
5067 cache_info=(CacheInfo *) image->cache;
5068 assert(cache_info->signature == MagickSignature);
5069 method=cache_info->virtual_pixel_method;
5070 cache_info->virtual_pixel_method=virtual_pixel_method;
5071 return(method);
5072}
5073
5074/*
5075%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5076% %
5077% %
5078% %
5079+ 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 %
5080% %
5081% %
5082% %
5083%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5084%
5085% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5086% in-memory or disk cache. The method returns MagickTrue if the pixel region
5087% is synced, otherwise MagickFalse.
5088%
5089% The format of the SyncAuthenticPixelCacheNexus() method is:
5090%
5091% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5092% NexusInfo *nexus_info,ExceptionInfo *exception)
5093%
5094% A description of each parameter follows:
5095%
5096% o image: the image.
5097%
5098% o nexus_info: the cache nexus to sync.
5099%
5100% o exception: return any errors or warnings in this structure.
5101%
5102*/
5103MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5104 NexusInfo *nexus_info,ExceptionInfo *exception)
5105{
5106 CacheInfo
5107 *cache_info;
5108
5109 MagickBooleanType
5110 status;
5111
5112 /*
5113 Transfer pixels to the cache.
5114 */
5115 assert(image != (Image *) NULL);
5116 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005117 if (image->cache == (Cache) NULL)
5118 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5119 cache_info=(CacheInfo *) image->cache;
5120 if (cache_info->type == UndefinedCache)
5121 return(MagickFalse);
5122 if ((image->clip_mask != (Image *) NULL) &&
5123 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5124 return(MagickFalse);
5125 if ((image->mask != (Image *) NULL) &&
5126 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5127 return(MagickFalse);
5128 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5129 return(MagickTrue);
5130 assert(cache_info->signature == MagickSignature);
5131 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5132 if ((cache_info->active_index_channel != MagickFalse) &&
5133 (WritePixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse))
5134 return(MagickFalse);
5135 return(status);
5136}
5137
5138/*
5139%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5140% %
5141% %
5142% %
5143+ S y n c A u t h e n t i c P i x e l C a c h e %
5144% %
5145% %
5146% %
5147%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5148%
5149% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5150% or disk cache. The method returns MagickTrue if the pixel region is synced,
5151% otherwise MagickFalse.
5152%
5153% The format of the SyncAuthenticPixelsCache() method is:
5154%
5155% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5156% ExceptionInfo *exception)
5157%
5158% A description of each parameter follows:
5159%
5160% o image: the image.
5161%
5162% o exception: return any errors or warnings in this structure.
5163%
5164*/
5165static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5166 ExceptionInfo *exception)
5167{
5168 CacheInfo
5169 *cache_info;
5170
cristy5c9e6f22010-09-17 17:31:01 +00005171 const int
5172 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005173
cristy3ed852e2009-09-05 21:47:34 +00005174 cache_info=(CacheInfo *) image->cache;
cristy6ebe97c2010-07-03 01:17:28 +00005175 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00005176 return(SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5177 exception));
cristy3ed852e2009-09-05 21:47:34 +00005178}
5179
5180/*
5181%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5182% %
5183% %
5184% %
5185% S y n c A u t h e n t i c P i x e l s %
5186% %
5187% %
5188% %
5189%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5190%
5191% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5192% The method returns MagickTrue if the pixel region is flushed, otherwise
5193% MagickFalse.
5194%
5195% The format of the SyncAuthenticPixels() method is:
5196%
5197% MagickBooleanType SyncAuthenticPixels(Image *image,
5198% ExceptionInfo *exception)
5199%
5200% A description of each parameter follows:
5201%
5202% o image: the image.
5203%
5204% o exception: return any errors or warnings in this structure.
5205%
5206*/
5207MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5208 ExceptionInfo *exception)
5209{
5210 CacheInfo
5211 *cache_info;
5212
cristy2036f5c2010-09-19 21:18:17 +00005213 const int
5214 id = GetOpenMPThreadId();
5215
cristy3ed852e2009-09-05 21:47:34 +00005216 assert(image != (Image *) NULL);
5217 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005218 assert(image->cache != (Cache) NULL);
5219 cache_info=(CacheInfo *) image->cache;
5220 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005221 if (cache_info->methods.sync_authentic_pixels_handler !=
5222 (SyncAuthenticPixelsHandler) NULL)
5223 return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
cristy2036f5c2010-09-19 21:18:17 +00005224 assert(id < (int) cache_info->number_threads);
5225 return(SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5226 exception));
cristy3ed852e2009-09-05 21:47:34 +00005227}
5228
5229/*
5230%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5231% %
5232% %
5233% %
5234+ W r i t e P i x e l C a c h e I n d e x e s %
5235% %
5236% %
5237% %
5238%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5239%
5240% WritePixelCacheIndexes() writes the colormap indexes to the specified
5241% region of the pixel cache.
5242%
5243% The format of the WritePixelCacheIndexes() method is:
5244%
5245% MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5246% NexusInfo *nexus_info,ExceptionInfo *exception)
5247%
5248% A description of each parameter follows:
5249%
5250% o cache_info: the pixel cache.
5251%
5252% o nexus_info: the cache nexus to write the colormap indexes.
5253%
5254% o exception: return any errors or warnings in this structure.
5255%
5256*/
5257static MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5258 NexusInfo *nexus_info,ExceptionInfo *exception)
5259{
5260 MagickOffsetType
5261 count,
5262 offset;
5263
5264 MagickSizeType
5265 length,
5266 number_pixels;
5267
5268 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005269 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005270
cristybb503372010-05-27 20:51:26 +00005271 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005272 y;
5273
cristybb503372010-05-27 20:51:26 +00005274 size_t
cristy3ed852e2009-09-05 21:47:34 +00005275 rows;
5276
cristy3ed852e2009-09-05 21:47:34 +00005277 if (cache_info->active_index_channel == MagickFalse)
5278 return(MagickFalse);
5279 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5280 return(MagickTrue);
5281 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5282 nexus_info->region.x;
5283 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
5284 rows=nexus_info->region.height;
5285 number_pixels=(MagickSizeType) length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005286 p=nexus_info->indexes;
5287 switch (cache_info->type)
5288 {
5289 case MemoryCache:
5290 case MapCache:
5291 {
5292 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005293 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005294
5295 /*
5296 Write indexes to memory.
5297 */
cristydd341db2010-03-04 19:06:38 +00005298 if ((cache_info->columns == nexus_info->region.width) &&
5299 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5300 {
5301 length=number_pixels;
5302 rows=1UL;
5303 }
cristy3ed852e2009-09-05 21:47:34 +00005304 q=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00005305 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005306 {
cristy8f036fe2010-09-18 02:02:00 +00005307 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00005308 p+=nexus_info->region.width;
5309 q+=cache_info->columns;
5310 }
5311 break;
5312 }
5313 case DiskCache:
5314 {
5315 /*
5316 Write indexes to disk.
5317 */
5318 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5319 {
5320 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5321 cache_info->cache_filename);
5322 return(MagickFalse);
5323 }
cristydd341db2010-03-04 19:06:38 +00005324 if ((cache_info->columns == nexus_info->region.width) &&
5325 (number_pixels < MagickMaxBufferExtent))
5326 {
5327 length=number_pixels;
5328 rows=1UL;
5329 }
cristy3ed852e2009-09-05 21:47:34 +00005330 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005331 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005332 {
5333 count=WritePixelCacheRegion(cache_info,cache_info->offset+number_pixels*
5334 sizeof(PixelPacket)+offset*sizeof(*p),length,
5335 (const unsigned char *) p);
5336 if ((MagickSizeType) count < length)
5337 break;
5338 p+=nexus_info->region.width;
5339 offset+=cache_info->columns;
5340 }
cristybb503372010-05-27 20:51:26 +00005341 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005342 {
5343 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5344 cache_info->cache_filename);
5345 return(MagickFalse);
5346 }
5347 break;
5348 }
5349 default:
5350 break;
5351 }
5352 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005353 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005354 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005355 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005356 nexus_info->region.width,(double) nexus_info->region.height,(double)
5357 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005358 return(MagickTrue);
5359}
5360
5361/*
5362%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5363% %
5364% %
5365% %
5366+ W r i t e C a c h e P i x e l s %
5367% %
5368% %
5369% %
5370%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5371%
5372% WritePixelCachePixels() writes image pixels to the specified region of the
5373% pixel cache.
5374%
5375% The format of the WritePixelCachePixels() method is:
5376%
5377% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5378% NexusInfo *nexus_info,ExceptionInfo *exception)
5379%
5380% A description of each parameter follows:
5381%
5382% o cache_info: the pixel cache.
5383%
5384% o nexus_info: the cache nexus to write the pixels.
5385%
5386% o exception: return any errors or warnings in this structure.
5387%
5388*/
5389static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5390 NexusInfo *nexus_info,ExceptionInfo *exception)
5391{
5392 MagickOffsetType
5393 count,
5394 offset;
5395
5396 MagickSizeType
5397 length,
5398 number_pixels;
5399
cristy3ed852e2009-09-05 21:47:34 +00005400 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005401 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005402
cristybb503372010-05-27 20:51:26 +00005403 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005404 y;
5405
cristybb503372010-05-27 20:51:26 +00005406 size_t
cristy3ed852e2009-09-05 21:47:34 +00005407 rows;
5408
cristy3ed852e2009-09-05 21:47:34 +00005409 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5410 return(MagickTrue);
5411 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5412 nexus_info->region.x;
5413 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
5414 rows=nexus_info->region.height;
5415 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005416 p=nexus_info->pixels;
5417 switch (cache_info->type)
5418 {
5419 case MemoryCache:
5420 case MapCache:
5421 {
5422 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005423 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005424
5425 /*
5426 Write pixels to memory.
5427 */
cristydd341db2010-03-04 19:06:38 +00005428 if ((cache_info->columns == nexus_info->region.width) &&
5429 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5430 {
5431 length=number_pixels;
5432 rows=1UL;
5433 }
cristy3ed852e2009-09-05 21:47:34 +00005434 q=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00005435 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005436 {
cristy8f036fe2010-09-18 02:02:00 +00005437 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00005438 p+=nexus_info->region.width;
5439 q+=cache_info->columns;
5440 }
5441 break;
5442 }
5443 case DiskCache:
5444 {
5445 /*
5446 Write pixels to disk.
5447 */
5448 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5449 {
5450 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5451 cache_info->cache_filename);
5452 return(MagickFalse);
5453 }
cristydd341db2010-03-04 19:06:38 +00005454 if ((cache_info->columns == nexus_info->region.width) &&
5455 (number_pixels < MagickMaxBufferExtent))
5456 {
5457 length=number_pixels;
5458 rows=1UL;
5459 }
cristybb503372010-05-27 20:51:26 +00005460 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005461 {
5462 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5463 sizeof(*p),length,(const unsigned char *) p);
5464 if ((MagickSizeType) count < length)
5465 break;
5466 p+=nexus_info->region.width;
5467 offset+=cache_info->columns;
5468 }
cristybb503372010-05-27 20:51:26 +00005469 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005470 {
5471 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5472 cache_info->cache_filename);
5473 return(MagickFalse);
5474 }
5475 break;
5476 }
5477 default:
5478 break;
5479 }
5480 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005481 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005482 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005483 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005484 nexus_info->region.width,(double) nexus_info->region.height,(double)
5485 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005486 return(MagickTrue);
5487}