blob: 68b20c345db5febcc715986143dd03b66daabc1b [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% CCCC AAA CCCC H H EEEEE %
7% C A A C H H E %
8% C AAAAA C HHHHH EEE %
9% C A A C H H E %
10% CCCC A A CCCC H H EEEEE %
11% %
12% %
13% MagickCore Pixel Cache Methods %
14% %
15% Software Design %
16% John Cristy %
17% July 1999 %
18% %
19% %
cristy16af1cb2009-12-11 21:38:29 +000020% Copyright 1999-2010 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
26% http://www.imagemagick.org/script/license.php %
27% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37%
38*/
39
40/*
41 Include declarations.
42*/
43#include "magick/studio.h"
44#include "magick/blob.h"
45#include "magick/blob-private.h"
46#include "magick/cache.h"
47#include "magick/cache-private.h"
48#include "magick/color-private.h"
49#include "magick/composite-private.h"
50#include "magick/exception.h"
51#include "magick/exception-private.h"
cristy365e58f2010-02-15 02:00:01 +000052#include "magick/geometry.h"
cristy3ed852e2009-09-05 21:47:34 +000053#include "magick/list.h"
54#include "magick/log.h"
55#include "magick/magick.h"
56#include "magick/memory_.h"
cristy4789f0d2010-01-10 00:01:06 +000057#include "magick/pixel.h"
cristy3ed852e2009-09-05 21:47:34 +000058#include "magick/pixel-private.h"
cristya21afde2010-07-02 00:45:40 +000059#include "magick/policy.h"
cristy3ed852e2009-09-05 21:47:34 +000060#include "magick/quantum.h"
61#include "magick/random_.h"
62#include "magick/resource_.h"
63#include "magick/semaphore.h"
64#include "magick/splay-tree.h"
65#include "magick/string_.h"
cristya21afde2010-07-02 00:45:40 +000066#include "magick/string-private.h"
cristy3ed852e2009-09-05 21:47:34 +000067#include "magick/thread-private.h"
68#include "magick/utility.h"
69#if defined(MAGICKCORE_ZLIB_DELEGATE)
70#include "zlib.h"
71#endif
72
73/*
cristy30097232010-07-01 02:16:30 +000074 Define declarations.
75*/
76#define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
77
78/*
cristy3ed852e2009-09-05 21:47:34 +000079 Typedef declarations.
80*/
81typedef struct _MagickModulo
82{
cristybb503372010-05-27 20:51:26 +000083 ssize_t
cristy3ed852e2009-09-05 21:47:34 +000084 quotient,
85 remainder;
86} MagickModulo;
87
88struct _NexusInfo
89{
90 MagickBooleanType
91 mapped;
92
93 RectangleInfo
94 region;
95
96 MagickSizeType
97 length;
98
99 PixelPacket
100 *cache,
101 *pixels;
102
103 IndexPacket
104 *indexes;
105
cristybb503372010-05-27 20:51:26 +0000106 size_t
cristy3ed852e2009-09-05 21:47:34 +0000107 signature;
108};
109
110/*
111 Forward declarations.
112*/
113#if defined(__cplusplus) || defined(c_plusplus)
114extern "C" {
115#endif
116
117static const IndexPacket
118 *GetVirtualIndexesFromCache(const Image *);
119
120static const PixelPacket
cristybb503372010-05-27 20:51:26 +0000121 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
122 const ssize_t,const size_t,const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000123 *GetVirtualPixelsCache(const Image *);
124
125static MagickBooleanType
cristy09c1c4d2010-06-30 18:23:16 +0000126 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,
127 PixelPacket *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000128 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
cristybb503372010-05-27 20:51:26 +0000129 const ssize_t,const ssize_t,PixelPacket *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000130 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
131 ReadPixelCacheIndexes(CacheInfo *,NexusInfo *,ExceptionInfo *),
132 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
133 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
134 WritePixelCacheIndexes(CacheInfo *,NexusInfo *,ExceptionInfo *),
135 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
136
137static PixelPacket
cristybb503372010-05-27 20:51:26 +0000138 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
139 const size_t,ExceptionInfo *),
140 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
141 const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000142 *SetPixelCacheNexusPixels(const Image *,const RectangleInfo *,NexusInfo *,
cristya4af2e32010-03-08 00:51:56 +0000143 ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +0000144
145#if defined(__cplusplus) || defined(c_plusplus)
146}
147#endif
148
149/*
150 Global declarations.
151*/
152static volatile MagickBooleanType
153 instantiate_cache = MagickFalse;
154
155static SemaphoreInfo
156 *cache_semaphore = (SemaphoreInfo *) NULL;
157
158static SplayTreeInfo
159 *cache_resources = (SplayTreeInfo *) NULL;
cristy3ed852e2009-09-05 21:47:34 +0000160
161/*
162%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
163% %
164% %
165% %
166+ A c q u i r e P i x e l C a c h e %
167% %
168% %
169% %
170%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
171%
172% AcquirePixelCache() acquires a pixel cache.
173%
174% The format of the AcquirePixelCache() method is:
175%
cristybb503372010-05-27 20:51:26 +0000176% Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000177%
178% A description of each parameter follows:
179%
180% o number_threads: the number of nexus threads.
181%
182*/
cristybb503372010-05-27 20:51:26 +0000183MagickExport Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000184{
185 CacheInfo
186 *cache_info;
187
188 cache_info=(CacheInfo *) AcquireAlignedMemory(1,sizeof(*cache_info));
189 if (cache_info == (CacheInfo *) NULL)
190 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
191 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
192 cache_info->type=UndefinedCache;
cristy87528ea2009-09-10 14:53:56 +0000193 cache_info->mode=IOMode;
cristy3ed852e2009-09-05 21:47:34 +0000194 cache_info->colorspace=RGBColorspace;
195 cache_info->file=(-1);
196 cache_info->id=GetMagickThreadId();
197 cache_info->number_threads=number_threads;
198 if (number_threads == 0)
199 cache_info->number_threads=GetOpenMPMaximumThreads();
200 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
201 if (cache_info->nexus_info == (NexusInfo **) NULL)
202 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
203 GetPixelCacheMethods(&cache_info->methods);
cristy3ed852e2009-09-05 21:47:34 +0000204 cache_info->semaphore=AllocateSemaphoreInfo();
cristy93505cf2010-08-10 21:37:49 +0000205 cache_info->reference_count=1;
cristy3ed852e2009-09-05 21:47:34 +0000206 cache_info->disk_semaphore=AllocateSemaphoreInfo();
207 cache_info->debug=IsEventLogging();
208 cache_info->signature=MagickSignature;
209 if ((cache_resources == (SplayTreeInfo *) NULL) &&
210 (instantiate_cache == MagickFalse))
211 {
cristy4e1dff62009-10-25 20:36:03 +0000212 if (cache_semaphore == (SemaphoreInfo *) NULL)
213 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000214 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000215 if ((cache_resources == (SplayTreeInfo *) NULL) &&
216 (instantiate_cache == MagickFalse))
217 {
218 cache_resources=NewSplayTree((int (*)(const void *,const void *))
219 NULL,(void *(*)(void *)) NULL,(void *(*)(void *)) NULL);
220 instantiate_cache=MagickTrue;
221 }
cristyf84a1932010-01-03 18:00:18 +0000222 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000223 }
224 (void) AddValueToSplayTree(cache_resources,cache_info,cache_info);
225 return((Cache ) cache_info);
226}
227
228/*
229%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
230% %
231% %
232% %
233% A c q u i r e P i x e l C a c h e N e x u s %
234% %
235% %
236% %
237%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
238%
239% AcquirePixelCacheNexus() allocates the NexusInfo structure.
240%
241% The format of the AcquirePixelCacheNexus method is:
242%
cristybb503372010-05-27 20:51:26 +0000243% NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000244%
245% A description of each parameter follows:
246%
247% o number_threads: the number of nexus threads.
248%
249*/
cristy2cd7a752010-08-23 00:48:54 +0000250MagickExport NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000251{
cristy3ed852e2009-09-05 21:47:34 +0000252 NexusInfo
253 **nexus_info;
254
cristye076a6e2010-08-15 19:59:43 +0000255 register ssize_t
256 i;
257
cristy3ed852e2009-09-05 21:47:34 +0000258 nexus_info=(NexusInfo **) AcquireAlignedMemory(number_threads,
259 sizeof(*nexus_info));
260 if (nexus_info == (NexusInfo **) NULL)
261 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristybb503372010-05-27 20:51:26 +0000262 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000263 {
264 nexus_info[i]=(NexusInfo *) AcquireAlignedMemory(1,sizeof(**nexus_info));
265 if (nexus_info[i] == (NexusInfo *) NULL)
266 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
267 (void) ResetMagickMemory(nexus_info[i],0,sizeof(*nexus_info[i]));
268 nexus_info[i]->signature=MagickSignature;
269 }
270 return(nexus_info);
271}
272
273/*
274%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
275% %
276% %
277% %
cristyd43a46b2010-01-21 02:13:41 +0000278+ A c q u i r e P i x e l C a c h e P i x e l s %
279% %
280% %
281% %
282%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
283%
284% AcquirePixelCachePixels() returns the pixels associated with the specified
285% image.
286%
287% The format of the AcquirePixelCachePixels() method is:
288%
289% const void *AcquirePixelCachePixels(const Image *image,
290% MagickSizeType *length,ExceptionInfo *exception)
291%
292% A description of each parameter follows:
293%
294% o image: the image.
295%
296% o length: the pixel cache length.
297%
298% o exception: return any errors or warnings in this structure.
299%
300*/
301MagickExport const void *AcquirePixelCachePixels(const Image *image,
302 MagickSizeType *length,ExceptionInfo *exception)
303{
304 CacheInfo
305 *cache_info;
306
307 assert(image != (const Image *) NULL);
308 assert(image->signature == MagickSignature);
cristyd43a46b2010-01-21 02:13:41 +0000309 assert(exception != (ExceptionInfo *) NULL);
310 assert(exception->signature == MagickSignature);
311 assert(image->cache != (Cache) NULL);
312 cache_info=(CacheInfo *) image->cache;
313 assert(cache_info->signature == MagickSignature);
314 *length=0;
315 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
316 return((const void *) NULL);
317 *length=cache_info->length;
318 return((const void *) cache_info->pixels);
319}
320
321/*
322%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
323% %
324% %
325% %
cristyf34a1452009-10-24 22:29:27 +0000326+ C a c h e C o m p o n e n t G e n e s i s %
327% %
328% %
329% %
330%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
331%
332% CacheComponentGenesis() instantiates the cache component.
333%
334% The format of the CacheComponentGenesis method is:
335%
336% MagickBooleanType CacheComponentGenesis(void)
337%
338*/
339MagickExport MagickBooleanType CacheComponentGenesis(void)
340{
cristy165b6092009-10-26 13:52:10 +0000341 AcquireSemaphoreInfo(&cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000342 return(MagickTrue);
343}
344
345/*
346%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
347% %
348% %
349% %
350+ C a c h e C o m p o n e n t T e r m i n u s %
351% %
352% %
353% %
354%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
355%
356% CacheComponentTerminus() destroys the cache component.
357%
358% The format of the CacheComponentTerminus() method is:
359%
360% CacheComponentTerminus(void)
361%
362*/
363MagickExport void CacheComponentTerminus(void)
364{
cristy18b17442009-10-25 18:36:48 +0000365 if (cache_semaphore == (SemaphoreInfo *) NULL)
366 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000367 LockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000368 if (cache_resources != (SplayTreeInfo *) NULL)
369 cache_resources=DestroySplayTree(cache_resources);
370 instantiate_cache=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +0000371 UnlockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000372 DestroySemaphoreInfo(&cache_semaphore);
373}
374
375/*
376%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
377% %
378% %
379% %
cristy3ed852e2009-09-05 21:47:34 +0000380+ C l i p P i x e l C a c h e N e x u s %
381% %
382% %
383% %
384%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
385%
386% ClipPixelCacheNexus() clips the cache nexus as defined by the image clip
387% mask. The method returns MagickTrue if the pixel region is clipped,
388% otherwise MagickFalse.
389%
390% The format of the ClipPixelCacheNexus() method is:
391%
392% MagickBooleanType ClipPixelCacheNexus(Image *image,NexusInfo *nexus_info,
393% ExceptionInfo *exception)
394%
395% A description of each parameter follows:
396%
397% o image: the image.
398%
399% o nexus_info: the cache nexus to clip.
400%
401% o exception: return any errors or warnings in this structure.
402%
403*/
404static MagickBooleanType ClipPixelCacheNexus(Image *image,
405 NexusInfo *nexus_info,ExceptionInfo *exception)
406{
407 CacheInfo
408 *cache_info;
409
410 MagickSizeType
411 number_pixels;
412
413 NexusInfo
414 **clip_nexus,
415 **image_nexus;
416
417 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000418 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +0000419
420 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +0000421 *restrict nexus_indexes,
422 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +0000423
cristy3ed852e2009-09-05 21:47:34 +0000424 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000425 *restrict p,
426 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000427
cristye076a6e2010-08-15 19:59:43 +0000428 register ssize_t
429 i;
430
cristy3ed852e2009-09-05 21:47:34 +0000431 /*
432 Apply clip mask.
433 */
434 if (image->debug != MagickFalse)
435 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
436 if (image->clip_mask == (Image *) NULL)
437 return(MagickFalse);
438 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
439 if (cache_info == (Cache) NULL)
440 return(MagickFalse);
441 image_nexus=AcquirePixelCacheNexus(1);
442 clip_nexus=AcquirePixelCacheNexus(1);
443 if ((image_nexus == (NexusInfo **) NULL) ||
444 (clip_nexus == (NexusInfo **) NULL))
445 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
446 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,nexus_info->region.y,
447 nexus_info->region.width,nexus_info->region.height,image_nexus[0],
448 exception);
449 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
450 q=nexus_info->pixels;
451 nexus_indexes=nexus_info->indexes;
452 r=GetVirtualPixelsFromNexus(image->clip_mask,MaskVirtualPixelMethod,
453 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
454 nexus_info->region.height,clip_nexus[0],exception);
455 number_pixels=(MagickSizeType) nexus_info->region.width*
456 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +0000457 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000458 {
459 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
460 break;
461 if (PixelIntensityToQuantum(r) > ((Quantum) QuantumRange/2))
462 {
cristyce70c172010-01-07 17:15:30 +0000463 SetRedPixelComponent(q,GetRedPixelComponent(p));
464 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
465 SetBluePixelComponent(q,GetBluePixelComponent(p));
466 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
cristy3ed852e2009-09-05 21:47:34 +0000467 if (cache_info->active_index_channel != MagickFalse)
468 nexus_indexes[i]=indexes[i];
469 }
470 p++;
471 q++;
472 r++;
473 }
474 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
475 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +0000476 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +0000477 return(MagickFalse);
478 return(MagickTrue);
479}
480
481/*
482%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
483% %
484% %
485% %
486+ C l o n e P i x e l C a c h e %
487% %
488% %
489% %
490%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
491%
492% ClonePixelCache() clones a pixel cache.
493%
494% The format of the ClonePixelCache() method is:
495%
496% Cache ClonePixelCache(const Cache cache)
497%
498% A description of each parameter follows:
499%
500% o cache: the pixel cache.
501%
502*/
503MagickExport Cache ClonePixelCache(const Cache cache)
504{
505 CacheInfo
506 *clone_info;
507
508 const CacheInfo
509 *cache_info;
510
511 assert(cache != (const Cache) NULL);
512 cache_info=(const CacheInfo *) cache;
513 assert(cache_info->signature == MagickSignature);
514 if (cache_info->debug != MagickFalse)
515 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
516 cache_info->filename);
517 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
518 if (clone_info == (Cache) NULL)
519 return((Cache) NULL);
520 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
521 return((Cache ) clone_info);
522}
523
524/*
525%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
526% %
527% %
528% %
529+ C l o n e P i x e l C a c h e N e x u s %
530% %
531% %
532% %
533%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
534%
535% ClonePixelCacheNexus() clones the source cache nexus to the destination
536% nexus.
537%
538% The format of the ClonePixelCacheNexus() method is:
539%
540% MagickBooleanType ClonePixelCacheNexus(CacheInfo *destination,
541% CacheInfo *source,ExceptionInfo *exception)
542%
543% A description of each parameter follows:
544%
545% o destination: the destination cache nexus.
546%
547% o source: the source cache nexus.
548%
549% o exception: return any errors or warnings in this structure.
550%
551*/
552
553static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
554 NexusInfo *nexus_info,ExceptionInfo *exception)
555{
556 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
557 return(MagickFalse);
558 nexus_info->mapped=MagickFalse;
559 nexus_info->cache=(PixelPacket *) AcquireMagickMemory((size_t)
560 nexus_info->length);
561 if (nexus_info->cache == (PixelPacket *) NULL)
562 {
563 nexus_info->mapped=MagickTrue;
564 nexus_info->cache=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
565 nexus_info->length);
566 }
567 if (nexus_info->cache == (PixelPacket *) NULL)
568 {
569 (void) ThrowMagickException(exception,GetMagickModule(),
570 ResourceLimitError,"MemoryAllocationFailed","`%s'",
571 cache_info->filename);
572 return(MagickFalse);
573 }
574 return(MagickTrue);
575}
576
577static MagickBooleanType ClonePixelCacheNexus(CacheInfo *destination,
578 CacheInfo *source,ExceptionInfo *exception)
579{
580 MagickBooleanType
581 status;
582
583 MagickSizeType
584 number_pixels;
585
cristy3ed852e2009-09-05 21:47:34 +0000586 register const NexusInfo
587 *p;
588
589 register NexusInfo
590 *q;
591
cristye076a6e2010-08-15 19:59:43 +0000592 register ssize_t
593 i;
594
cristy3ed852e2009-09-05 21:47:34 +0000595 status=MagickTrue;
cristybb503372010-05-27 20:51:26 +0000596 for (i=0; i < (ssize_t) source->number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000597 {
598 p=source->nexus_info[i];
599 q=destination->nexus_info[i];
600 q->mapped=p->mapped;
601 q->region=p->region;
602 q->length=p->length;
603 q->cache=p->cache;
604 q->pixels=p->pixels;
605 q->indexes=p->indexes;
606 if (p->cache != (PixelPacket *) NULL)
607 {
608 status=AcquireCacheNexusPixels(source,q,exception);
609 if (status != MagickFalse)
610 {
611 (void) CopyMagickMemory(q->cache,p->cache,(size_t) p->length);
612 q->pixels=q->cache;
613 q->indexes=(IndexPacket *) NULL;
614 number_pixels=(MagickSizeType) q->region.width*q->region.height;
615 if (p->indexes != (IndexPacket *) NULL)
616 q->indexes=(IndexPacket *) (q->pixels+number_pixels);
617 }
618 }
619 }
620 return(status);
621}
622
623/*
624%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
625% %
626% %
627% %
cristy60c44a82009-10-07 00:58:49 +0000628+ 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 +0000629% %
630% %
631% %
632%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
633% ClonePixelCachePixels() clones the source pixel cache to the destination
634% cache.
635%
636% The format of the ClonePixelCachePixels() method is:
637%
638% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
639% CacheInfo *source_info,ExceptionInfo *exception)
640%
641% A description of each parameter follows:
642%
643% o cache_info: the pixel cache.
644%
645% o source_info: the source pixel cache.
646%
647% o exception: return any errors or warnings in this structure.
648%
649*/
650
651static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
652{
653 int
654 status;
655
cristy5ee247a2010-02-12 15:42:34 +0000656 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000657 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000658 if (cache_info->file != -1)
659 status=close(cache_info->file);
cristy3ed852e2009-09-05 21:47:34 +0000660 cache_info->file=(-1);
661 RelinquishMagickResource(FileResource,1);
cristyf84a1932010-01-03 18:00:18 +0000662 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000663 return(status == -1 ? MagickFalse : MagickTrue);
664}
665
666static void LimitPixelCacheDescriptors(void)
667{
668 register CacheInfo
669 *p,
670 *q;
671
672 /*
673 Limit # of open file descriptors.
674 */
675 if (GetMagickResource(FileResource) < GetMagickResourceLimit(FileResource))
676 return;
cristyf84a1932010-01-03 18:00:18 +0000677 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000678 if (cache_resources == (SplayTreeInfo *) NULL)
679 {
cristyf84a1932010-01-03 18:00:18 +0000680 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000681 return;
682 }
683 ResetSplayTreeIterator(cache_resources);
684 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
685 while (p != (CacheInfo *) NULL)
686 {
687 if ((p->type == DiskCache) && (p->file != -1))
cristy508d9312010-02-10 21:10:30 +0000688 break;
cristy3ed852e2009-09-05 21:47:34 +0000689 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
690 }
691 for (q=p; p != (CacheInfo *) NULL; )
692 {
693 if ((p->type == DiskCache) && (p->file != -1) &&
694 (p->timestamp < q->timestamp))
cristy508d9312010-02-10 21:10:30 +0000695 q=p;
cristy3ed852e2009-09-05 21:47:34 +0000696 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
697 }
698 if (q != (CacheInfo *) NULL)
cristy9e116922010-02-12 20:58:13 +0000699 {
700 /*
701 Close least recently used cache.
702 */
703 (void) close(q->file);
704 q->file=(-1);
705 }
cristyf84a1932010-01-03 18:00:18 +0000706 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000707}
708
709static inline MagickSizeType MagickMax(const MagickSizeType x,
710 const MagickSizeType y)
711{
712 if (x > y)
713 return(x);
714 return(y);
715}
716
717static inline MagickSizeType MagickMin(const MagickSizeType x,
718 const MagickSizeType y)
719{
720 if (x < y)
721 return(x);
722 return(y);
723}
724
725static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
726 const MapMode mode)
727{
728 int
729 file;
730
731 /*
732 Open pixel cache on disk.
733 */
cristyf84a1932010-01-03 18:00:18 +0000734 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000735 if (cache_info->file != -1)
736 {
cristyf84a1932010-01-03 18:00:18 +0000737 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000738 return(MagickTrue); /* cache already open */
739 }
740 LimitPixelCacheDescriptors();
741 if (*cache_info->cache_filename == '\0')
742 file=AcquireUniqueFileResource(cache_info->cache_filename);
743 else
744 switch (mode)
745 {
746 case ReadMode:
747 {
748 file=open(cache_info->cache_filename,O_RDONLY | O_BINARY);
749 break;
750 }
751 case WriteMode:
752 {
753 file=open(cache_info->cache_filename,O_WRONLY | O_CREAT | O_BINARY |
754 O_EXCL,S_MODE);
755 if (file == -1)
756 file=open(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
757 break;
758 }
759 case IOMode:
760 default:
761 {
762 file=open(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
763 O_EXCL,S_MODE);
764 if (file == -1)
765 file=open(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
766 break;
767 }
768 }
769 if (file == -1)
770 {
cristyf84a1932010-01-03 18:00:18 +0000771 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000772 return(MagickFalse);
773 }
774 (void) AcquireMagickResource(FileResource,1);
775 cache_info->file=file;
776 cache_info->timestamp=time(0);
cristyf84a1932010-01-03 18:00:18 +0000777 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000778 return(MagickTrue);
779}
780
781static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
782 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000783 unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000784{
785 register MagickOffsetType
786 i;
787
788 ssize_t
789 count;
790
cristy08a88202010-03-04 19:18:05 +0000791 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000792#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000793 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000794 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
795 {
cristyf84a1932010-01-03 18:00:18 +0000796 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000797 return((MagickOffsetType) -1);
798 }
799#endif
800 count=0;
801 for (i=0; i < (MagickOffsetType) length; i+=count)
802 {
803#if !defined(MAGICKCORE_HAVE_PREAD)
804 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
805 (MagickSizeType) SSIZE_MAX));
806#else
807 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
808 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
809#endif
810 if (count > 0)
811 continue;
812 count=0;
813 if (errno != EINTR)
814 {
815 i=(-1);
816 break;
817 }
818 }
819#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000820 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000821#endif
822 return(i);
823}
824
825static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
826 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000827 const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000828{
829 register MagickOffsetType
830 i;
831
832 ssize_t
833 count;
834
cristy08a88202010-03-04 19:18:05 +0000835 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000836#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000837 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000838 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
839 {
cristyf84a1932010-01-03 18:00:18 +0000840 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000841 return((MagickOffsetType) -1);
842 }
843#endif
844 count=0;
845 for (i=0; i < (MagickOffsetType) length; i+=count)
846 {
847#if !defined(MAGICKCORE_HAVE_PWRITE)
848 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
849 (MagickSizeType) SSIZE_MAX));
850#else
851 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
852 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
853#endif
854 if (count > 0)
855 continue;
856 count=0;
857 if (errno != EINTR)
858 {
859 i=(-1);
860 break;
861 }
862 }
863#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000864 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000865#endif
866 return(i);
867}
868
869static MagickBooleanType CloneDiskToDiskPixelCache(CacheInfo *clone_info,
870 CacheInfo *cache_info,ExceptionInfo *exception)
871{
872 MagickOffsetType
873 count,
874 offset,
875 source_offset;
876
877 MagickSizeType
878 length;
879
cristy3ed852e2009-09-05 21:47:34 +0000880 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000881 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +0000882
cristye076a6e2010-08-15 19:59:43 +0000883 register ssize_t
884 y;
885
cristybb503372010-05-27 20:51:26 +0000886 size_t
cristy3ed852e2009-09-05 21:47:34 +0000887 columns,
888 rows;
889
890 if (cache_info->debug != MagickFalse)
891 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
892 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
893 {
894 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
895 clone_info->cache_filename);
896 return(MagickFalse);
897 }
898 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
899 {
900 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
901 cache_info->cache_filename);
902 return(MagickFalse);
903 }
cristybb503372010-05-27 20:51:26 +0000904 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
905 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +0000906 if ((clone_info->active_index_channel != MagickFalse) &&
907 (cache_info->active_index_channel != MagickFalse))
908 {
909 register IndexPacket
910 *indexes;
911
912 /*
913 Clone cache indexes.
914 */
915 length=MagickMax(clone_info->columns,cache_info->columns)*
916 sizeof(*indexes);
917 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
918 if (indexes == (IndexPacket *) NULL)
919 {
920 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
921 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
922 return(MagickFalse);
923 }
924 (void) ResetMagickMemory(indexes,0,(size_t) length);
925 length=columns*sizeof(*indexes);
926 source_offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
927 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
928 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
929 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +0000930 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000931 {
932 source_offset-=cache_info->columns*sizeof(*indexes);
933 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
934 length,(unsigned char *) indexes);
935 if ((MagickSizeType) count != length)
936 break;
937 offset-=clone_info->columns*sizeof(*indexes);
938 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
939 (unsigned char *) indexes);
940 if ((MagickSizeType) count != length)
941 break;
942 }
cristybb503372010-05-27 20:51:26 +0000943 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000944 {
945 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
946 ThrowFileException(exception,CacheError,"UnableToCloneCache",
947 cache_info->cache_filename);
948 return(MagickFalse);
949 }
950 if (clone_info->columns > cache_info->columns)
951 {
952 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
953 (void) ResetMagickMemory(indexes,0,(size_t) length);
954 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
955 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +0000956 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000957 {
958 offset-=clone_info->columns*sizeof(*indexes);
959 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
960 length,(unsigned char *) indexes);
961 if ((MagickSizeType) count != length)
962 break;
963 }
cristybb503372010-05-27 20:51:26 +0000964 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000965 {
966 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
967 ThrowFileException(exception,CacheError,"UnableToCloneCache",
968 cache_info->cache_filename);
969 return(MagickFalse);
970 }
971 }
972 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
973 }
974 /*
975 Clone cache pixels.
976 */
977 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
978 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
979 if (pixels == (PixelPacket *) NULL)
980 {
981 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
982 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
983 return(MagickFalse);
984 }
985 (void) ResetMagickMemory(pixels,0,(size_t) length);
986 length=columns*sizeof(*pixels);
987 source_offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
988 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +0000989 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000990 {
991 source_offset-=cache_info->columns*sizeof(*pixels);
992 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
993 length,(unsigned char *) pixels);
994 if ((MagickSizeType) count != length)
995 break;
996 offset-=clone_info->columns*sizeof(*pixels);
997 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
998 (unsigned char *) pixels);
999 if ((MagickSizeType) count != length)
1000 break;
1001 }
cristybb503372010-05-27 20:51:26 +00001002 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001003 {
1004 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1005 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1006 cache_info->cache_filename);
1007 return(MagickFalse);
1008 }
1009 if (clone_info->columns > cache_info->columns)
1010 {
1011 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
1012 sizeof(*pixels);
1013 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1014 (void) ResetMagickMemory(pixels,0,(size_t) length);
cristybb503372010-05-27 20:51:26 +00001015 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001016 {
1017 offset-=clone_info->columns*sizeof(*pixels);
1018 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1019 (unsigned char *) pixels);
1020 if ((MagickSizeType) count != length)
1021 break;
1022 }
cristybb503372010-05-27 20:51:26 +00001023 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001024 {
1025 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1026 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1027 cache_info->cache_filename);
1028 return(MagickFalse);
1029 }
1030 }
1031 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1032 return(MagickTrue);
1033}
1034
1035static MagickBooleanType CloneDiskToMemoryPixelCache(CacheInfo *clone_info,
1036 CacheInfo *cache_info,ExceptionInfo *exception)
1037{
1038 MagickOffsetType
1039 count,
1040 offset;
1041
1042 MagickSizeType
1043 length;
1044
cristy3ed852e2009-09-05 21:47:34 +00001045 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001046 *restrict pixels,
1047 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00001048
cristye076a6e2010-08-15 19:59:43 +00001049 register ssize_t
1050 y;
1051
cristybb503372010-05-27 20:51:26 +00001052 size_t
cristy3ed852e2009-09-05 21:47:34 +00001053 columns,
1054 rows;
1055
1056 if (cache_info->debug != MagickFalse)
1057 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
1058 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
1059 {
1060 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1061 cache_info->cache_filename);
1062 return(MagickFalse);
1063 }
cristybb503372010-05-27 20:51:26 +00001064 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1065 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001066 if ((clone_info->active_index_channel != MagickFalse) &&
1067 (cache_info->active_index_channel != MagickFalse))
1068 {
1069 register IndexPacket
1070 *indexes,
1071 *q;
1072
1073 /*
1074 Clone cache indexes.
1075 */
1076 length=MagickMax(clone_info->columns,cache_info->columns)*
1077 sizeof(*indexes);
1078 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
1079 if (indexes == (IndexPacket *) NULL)
1080 {
1081 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1082 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1083 return(MagickFalse);
1084 }
1085 (void) ResetMagickMemory(indexes,0,(size_t) length);
1086 length=columns*sizeof(IndexPacket);
1087 offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
1088 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
1089 q=clone_info->indexes+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001090 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001091 {
1092 offset-=cache_info->columns*sizeof(IndexPacket);
1093 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,
1094 length,(unsigned char *) indexes);
1095 if ((MagickSizeType) count != length)
1096 break;
1097 q-=clone_info->columns;
1098 (void) CopyMagickMemory(q,indexes,(size_t) length);
1099 if ((MagickSizeType) count != length)
1100 break;
1101 }
cristybb503372010-05-27 20:51:26 +00001102 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001103 {
1104 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1105 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1106 cache_info->cache_filename);
1107 return(MagickFalse);
1108 }
1109 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1110 }
1111 /*
1112 Clone cache pixels.
1113 */
1114 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1115 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1116 if (pixels == (PixelPacket *) NULL)
1117 {
1118 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1119 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1120 return(MagickFalse);
1121 }
1122 (void) ResetMagickMemory(pixels,0,(size_t) length);
1123 length=columns*sizeof(*pixels);
1124 offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
1125 q=clone_info->pixels+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001126 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001127 {
1128 offset-=cache_info->columns*sizeof(*pixels);
1129 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,length,
1130 (unsigned char *) pixels);
1131 if ((MagickSizeType) count != length)
1132 break;
1133 q-=clone_info->columns;
1134 (void) CopyMagickMemory(q,pixels,(size_t) length);
1135 }
cristybb503372010-05-27 20:51:26 +00001136 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001137 {
1138 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1139 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1140 cache_info->cache_filename);
1141 return(MagickFalse);
1142 }
1143 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1144 return(MagickTrue);
1145}
1146
1147static MagickBooleanType CloneMemoryToDiskPixelCache(CacheInfo *clone_info,
1148 CacheInfo *cache_info,ExceptionInfo *exception)
1149{
1150 MagickOffsetType
1151 count,
1152 offset;
1153
1154 MagickSizeType
1155 length;
1156
cristy3ed852e2009-09-05 21:47:34 +00001157 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001158 *restrict p,
1159 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +00001160
cristye076a6e2010-08-15 19:59:43 +00001161 register ssize_t
1162 y;
1163
cristybb503372010-05-27 20:51:26 +00001164 size_t
cristy3ed852e2009-09-05 21:47:34 +00001165 columns,
1166 rows;
1167
1168 if (cache_info->debug != MagickFalse)
1169 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
1170 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
1171 {
1172 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1173 clone_info->cache_filename);
1174 return(MagickFalse);
1175 }
cristybb503372010-05-27 20:51:26 +00001176 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1177 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001178 if ((clone_info->active_index_channel != MagickFalse) &&
1179 (cache_info->active_index_channel != MagickFalse))
1180 {
1181 register IndexPacket
1182 *p,
1183 *indexes;
1184
1185 /*
1186 Clone cache indexes.
1187 */
1188 length=MagickMax(clone_info->columns,cache_info->columns)*
1189 sizeof(*indexes);
1190 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
1191 if (indexes == (IndexPacket *) NULL)
1192 {
1193 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1194 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1195 return(MagickFalse);
1196 }
1197 (void) ResetMagickMemory(indexes,0,(size_t) length);
1198 length=columns*sizeof(*indexes);
1199 p=cache_info->indexes+cache_info->columns*rows;
1200 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1201 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +00001202 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001203 {
1204 p-=cache_info->columns;
1205 (void) CopyMagickMemory(indexes,p,(size_t) length);
1206 offset-=clone_info->columns*sizeof(*indexes);
1207 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1208 (unsigned char *) indexes);
1209 if ((MagickSizeType) count != length)
1210 break;
1211 }
cristybb503372010-05-27 20:51:26 +00001212 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001213 {
1214 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1215 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1216 cache_info->cache_filename);
1217 return(MagickFalse);
1218 }
1219 if (clone_info->columns > cache_info->columns)
1220 {
1221 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
1222 (void) ResetMagickMemory(indexes,0,(size_t) length);
1223 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1224 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +00001225 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001226 {
1227 offset-=clone_info->columns*sizeof(*indexes);
1228 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
1229 length,(unsigned char *) indexes);
1230 if ((MagickSizeType) count != length)
1231 break;
1232 }
cristybb503372010-05-27 20:51:26 +00001233 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001234 {
1235 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1236 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1237 cache_info->cache_filename);
1238 return(MagickFalse);
1239 }
1240 }
1241 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1242 }
1243 /*
1244 Clone cache pixels.
1245 */
1246 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1247 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1248 if (pixels == (PixelPacket *) NULL)
1249 {
1250 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1251 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1252 return(MagickFalse);
1253 }
1254 (void) ResetMagickMemory(pixels,0,(size_t) length);
1255 length=columns*sizeof(*pixels);
1256 p=cache_info->pixels+cache_info->columns*rows;
1257 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +00001258 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001259 {
1260 p-=cache_info->columns;
1261 (void) CopyMagickMemory(pixels,p,(size_t) length);
1262 offset-=clone_info->columns*sizeof(*pixels);
1263 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1264 (unsigned char *) pixels);
1265 if ((MagickSizeType) count != length)
1266 break;
1267 }
cristybb503372010-05-27 20:51:26 +00001268 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001269 {
1270 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1271 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1272 cache_info->cache_filename);
1273 return(MagickFalse);
1274 }
1275 if (clone_info->columns > cache_info->columns)
1276 {
1277 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
1278 sizeof(*pixels);
1279 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1280 (void) ResetMagickMemory(pixels,0,(size_t) length);
cristybb503372010-05-27 20:51:26 +00001281 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001282 {
1283 offset-=clone_info->columns*sizeof(*pixels);
1284 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1285 (unsigned char *) pixels);
1286 if ((MagickSizeType) count != length)
1287 break;
1288 }
cristybb503372010-05-27 20:51:26 +00001289 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001290 {
1291 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1292 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1293 cache_info->cache_filename);
1294 return(MagickFalse);
1295 }
1296 }
1297 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1298 return(MagickTrue);
1299}
1300
1301static MagickBooleanType CloneMemoryToMemoryPixelCache(CacheInfo *clone_info,
1302 CacheInfo *cache_info,ExceptionInfo *magick_unused(exception))
1303{
cristy3ed852e2009-09-05 21:47:34 +00001304 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001305 *restrict pixels,
1306 *restrict source_pixels;
cristy3ed852e2009-09-05 21:47:34 +00001307
cristye076a6e2010-08-15 19:59:43 +00001308 register ssize_t
1309 y;
cristy3ed852e2009-09-05 21:47:34 +00001310
cristybb503372010-05-27 20:51:26 +00001311 size_t
cristy3ed852e2009-09-05 21:47:34 +00001312 columns,
cristye076a6e2010-08-15 19:59:43 +00001313 length,
cristy3ed852e2009-09-05 21:47:34 +00001314 rows;
1315
1316 if (cache_info->debug != MagickFalse)
1317 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
cristybb503372010-05-27 20:51:26 +00001318 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1319 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001320 if ((clone_info->active_index_channel != MagickFalse) &&
1321 (cache_info->active_index_channel != MagickFalse))
1322 {
1323 register IndexPacket
1324 *indexes,
1325 *source_indexes;
1326
1327 /*
1328 Clone cache indexes.
1329 */
1330 length=columns*sizeof(*indexes);
1331 if (clone_info->columns == cache_info->columns)
1332 (void) CopyMagickMemory(clone_info->indexes,cache_info->indexes,
1333 length*rows);
1334 else
1335 {
1336 source_indexes=cache_info->indexes+cache_info->columns*rows;
1337 indexes=clone_info->indexes+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001338 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001339 {
1340 source_indexes-=cache_info->columns;
1341 indexes-=clone_info->columns;
1342 (void) CopyMagickMemory(indexes,source_indexes,length);
1343 }
1344 if (clone_info->columns > cache_info->columns)
1345 {
1346 length=(clone_info->columns-cache_info->columns)*
1347 sizeof(*indexes);
1348 indexes=clone_info->indexes+clone_info->columns*rows+
1349 cache_info->columns;
cristybb503372010-05-27 20:51:26 +00001350 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001351 {
1352 indexes-=clone_info->columns;
1353 (void) ResetMagickMemory(indexes,0,length);
1354 }
1355 }
1356 }
1357 }
1358 /*
1359 Clone cache pixels.
1360 */
1361 length=columns*sizeof(*pixels);
1362 if (clone_info->columns == cache_info->columns)
1363 (void) CopyMagickMemory(clone_info->pixels,cache_info->pixels,length*rows);
1364 else
1365 {
1366 source_pixels=cache_info->pixels+cache_info->columns*rows;
1367 pixels=clone_info->pixels+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001368 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001369 {
1370 source_pixels-=cache_info->columns;
1371 pixels-=clone_info->columns;
1372 (void) CopyMagickMemory(pixels,source_pixels,length);
1373 }
1374 if (clone_info->columns > cache_info->columns)
1375 {
1376 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1377 pixels=clone_info->pixels+clone_info->columns*rows+
1378 cache_info->columns;
cristybb503372010-05-27 20:51:26 +00001379 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001380 {
1381 pixels-=clone_info->columns;
1382 (void) ResetMagickMemory(pixels,0,length);
1383 }
1384 }
1385 }
1386 return(MagickTrue);
1387}
1388
1389static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1390 CacheInfo *cache_info,ExceptionInfo *exception)
1391{
1392 if ((clone_info->type != DiskCache) && (cache_info->type != DiskCache))
1393 return(CloneMemoryToMemoryPixelCache(clone_info,cache_info,exception));
1394 if ((clone_info->type == DiskCache) && (cache_info->type == DiskCache))
1395 return(CloneDiskToDiskPixelCache(clone_info,cache_info,exception));
1396 if (cache_info->type == DiskCache)
1397 return(CloneDiskToMemoryPixelCache(clone_info,cache_info,exception));
1398 return(CloneMemoryToDiskPixelCache(clone_info,cache_info,exception));
1399}
1400
1401/*
1402%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1403% %
1404% %
1405% %
1406+ C l o n e P i x e l C a c h e M e t h o d s %
1407% %
1408% %
1409% %
1410%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1411%
1412% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1413% another.
1414%
1415% The format of the ClonePixelCacheMethods() method is:
1416%
1417% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1418%
1419% A description of each parameter follows:
1420%
1421% o clone: Specifies a pointer to a Cache structure.
1422%
1423% o cache: the pixel cache.
1424%
1425*/
1426MagickExport void ClonePixelCacheMethods(Cache clone,const Cache cache)
1427{
1428 CacheInfo
1429 *cache_info,
1430 *source_info;
1431
1432 assert(clone != (Cache) NULL);
1433 source_info=(CacheInfo *) clone;
1434 assert(source_info->signature == MagickSignature);
1435 if (source_info->debug != MagickFalse)
1436 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1437 source_info->filename);
1438 assert(cache != (Cache) NULL);
1439 cache_info=(CacheInfo *) cache;
1440 assert(cache_info->signature == MagickSignature);
1441 source_info->methods=cache_info->methods;
1442}
1443
1444/*
1445%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1446% %
1447% %
1448% %
1449+ D e s t r o y I m a g e P i x e l C a c h e %
1450% %
1451% %
1452% %
1453%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1454%
1455% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1456%
1457% The format of the DestroyImagePixelCache() method is:
1458%
1459% void DestroyImagePixelCache(Image *image)
1460%
1461% A description of each parameter follows:
1462%
1463% o image: the image.
1464%
1465*/
1466static void DestroyImagePixelCache(Image *image)
1467{
1468 assert(image != (Image *) NULL);
1469 assert(image->signature == MagickSignature);
1470 if (image->debug != MagickFalse)
1471 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1472 if (image->cache == (void *) NULL)
1473 return;
1474 image->cache=DestroyPixelCache(image->cache);
1475}
1476
1477/*
1478%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1479% %
1480% %
1481% %
1482+ D e s t r o y I m a g e P i x e l s %
1483% %
1484% %
1485% %
1486%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1487%
1488% DestroyImagePixels() deallocates memory associated with the pixel cache.
1489%
1490% The format of the DestroyImagePixels() method is:
1491%
1492% void DestroyImagePixels(Image *image)
1493%
1494% A description of each parameter follows:
1495%
1496% o image: the image.
1497%
1498*/
1499MagickExport void DestroyImagePixels(Image *image)
1500{
1501 CacheInfo
1502 *cache_info;
1503
1504 assert(image != (const Image *) NULL);
1505 assert(image->signature == MagickSignature);
1506 if (image->debug != MagickFalse)
1507 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1508 assert(image->cache != (Cache) NULL);
1509 cache_info=(CacheInfo *) image->cache;
1510 assert(cache_info->signature == MagickSignature);
1511 if (cache_info->methods.destroy_pixel_handler == (DestroyPixelHandler) NULL)
1512 return;
1513 cache_info->methods.destroy_pixel_handler(image);
1514}
1515
1516/*
1517%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1518% %
1519% %
1520% %
1521+ D e s t r o y P i x e l C a c h e %
1522% %
1523% %
1524% %
1525%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1526%
1527% DestroyPixelCache() deallocates memory associated with the pixel cache.
1528%
1529% The format of the DestroyPixelCache() method is:
1530%
1531% Cache DestroyPixelCache(Cache cache)
1532%
1533% A description of each parameter follows:
1534%
1535% o cache: the pixel cache.
1536%
1537*/
1538
1539static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1540{
1541 switch (cache_info->type)
1542 {
1543 case MemoryCache:
1544 {
1545 if (cache_info->mapped == MagickFalse)
1546 cache_info->pixels=(PixelPacket *) RelinquishMagickMemory(
1547 cache_info->pixels);
1548 else
1549 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,
1550 (size_t) cache_info->length);
1551 RelinquishMagickResource(MemoryResource,cache_info->length);
1552 break;
1553 }
1554 case MapCache:
1555 {
1556 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,(size_t)
1557 cache_info->length);
1558 RelinquishMagickResource(MapResource,cache_info->length);
1559 }
1560 case DiskCache:
1561 {
1562 if (cache_info->file != -1)
1563 (void) ClosePixelCacheOnDisk(cache_info);
1564 RelinquishMagickResource(DiskResource,cache_info->length);
1565 break;
1566 }
1567 default:
1568 break;
1569 }
1570 cache_info->type=UndefinedCache;
1571 cache_info->mapped=MagickFalse;
1572 cache_info->indexes=(IndexPacket *) NULL;
1573}
1574
1575MagickExport Cache DestroyPixelCache(Cache cache)
1576{
1577 CacheInfo
1578 *cache_info;
1579
cristy3ed852e2009-09-05 21:47:34 +00001580 assert(cache != (Cache) NULL);
1581 cache_info=(CacheInfo *) cache;
1582 assert(cache_info->signature == MagickSignature);
1583 if (cache_info->debug != MagickFalse)
1584 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1585 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001586 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001587 cache_info->reference_count--;
1588 if (cache_info->reference_count != 0)
1589 {
cristyf84a1932010-01-03 18:00:18 +00001590 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001591 return((Cache) NULL);
1592 }
cristyf84a1932010-01-03 18:00:18 +00001593 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001594 if (cache_resources != (SplayTreeInfo *) NULL)
1595 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
cristy5b8de732009-09-10 23:50:40 +00001596 if (cache_info->debug != MagickFalse)
1597 {
1598 char
1599 message[MaxTextExtent];
1600
1601 (void) FormatMagickString(message,MaxTextExtent,"destroy %s",
1602 cache_info->filename);
1603 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1604 }
cristyc2e1bdd2009-09-10 23:43:34 +00001605 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1606 (cache_info->type != DiskCache)))
1607 RelinquishPixelCachePixels(cache_info);
1608 else
1609 {
1610 RelinquishPixelCachePixels(cache_info);
1611 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1612 }
cristy3ed852e2009-09-05 21:47:34 +00001613 *cache_info->cache_filename='\0';
1614 if (cache_info->nexus_info != (NexusInfo **) NULL)
1615 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1616 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001617 if (cache_info->random_info != (RandomInfo *) NULL)
1618 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001619 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1620 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1621 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1622 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001623 cache_info->signature=(~MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001624 cache_info=(CacheInfo *) RelinquishAlignedMemory(cache_info);
1625 cache=(Cache) NULL;
1626 return(cache);
1627}
1628
1629/*
1630%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1631% %
1632% %
1633% %
1634+ D e s t r o y P i x e l C a c h e N e x u s %
1635% %
1636% %
1637% %
1638%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1639%
1640% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1641%
1642% The format of the DestroyPixelCacheNexus() method is:
1643%
1644% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001645% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001646%
1647% A description of each parameter follows:
1648%
1649% o nexus_info: the nexus to destroy.
1650%
1651% o number_threads: the number of nexus threads.
1652%
1653*/
1654
1655static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1656{
1657 if (nexus_info->mapped == MagickFalse)
1658 (void) RelinquishMagickMemory(nexus_info->cache);
1659 else
1660 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1661 nexus_info->cache=(PixelPacket *) NULL;
1662 nexus_info->pixels=(PixelPacket *) NULL;
1663 nexus_info->indexes=(IndexPacket *) NULL;
1664 nexus_info->length=0;
1665 nexus_info->mapped=MagickFalse;
1666}
1667
1668MagickExport NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001669 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001670{
cristybb503372010-05-27 20:51:26 +00001671 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001672 i;
1673
1674 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001675 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001676 {
1677 if (nexus_info[i]->cache != (PixelPacket *) NULL)
1678 RelinquishCacheNexusPixels(nexus_info[i]);
1679 nexus_info[i]->signature=(~MagickSignature);
1680 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
1681 }
1682 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
1683 return(nexus_info);
1684}
1685
1686/*
1687%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1688% %
1689% %
1690% %
cristy3ed852e2009-09-05 21:47:34 +00001691+ 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 %
1692% %
1693% %
1694% %
1695%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1696%
1697% GetAuthenticIndexesFromCache() returns the indexes associated with the last
1698% call to QueueAuthenticPixelsCache() or GetAuthenticPixelsCache().
1699%
1700% The format of the GetAuthenticIndexesFromCache() method is:
1701%
1702% IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1703%
1704% A description of each parameter follows:
1705%
1706% o image: the image.
1707%
1708*/
1709static IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1710{
1711 CacheInfo
1712 *cache_info;
1713
1714 IndexPacket
1715 *indexes;
1716
cristy6ebe97c2010-07-03 01:17:28 +00001717 int
cristy3ed852e2009-09-05 21:47:34 +00001718 id;
1719
cristy3ed852e2009-09-05 21:47:34 +00001720 cache_info=(CacheInfo *) image->cache;
1721 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00001722 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001723 indexes=GetPixelCacheNexusIndexes(image->cache,cache_info->nexus_info[id]);
1724 return(indexes);
1725}
1726
1727/*
1728%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1729% %
1730% %
1731% %
1732% G e t A u t h e n t i c I n d e x Q u e u e %
1733% %
1734% %
1735% %
1736%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1737%
1738% GetAuthenticIndexQueue() returns the authentic black channel or the colormap
1739% indexes associated with the last call to QueueAuthenticPixels() or
1740% GetVirtualPixels(). NULL is returned if the black channel or colormap
1741% indexes are not available.
1742%
1743% The format of the GetAuthenticIndexQueue() method is:
1744%
1745% IndexPacket *GetAuthenticIndexQueue(const Image *image)
1746%
1747% A description of each parameter follows:
1748%
1749% o image: the image.
1750%
1751*/
1752MagickExport IndexPacket *GetAuthenticIndexQueue(const Image *image)
1753{
1754 CacheInfo
1755 *cache_info;
1756
1757 assert(image != (const Image *) NULL);
1758 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001759 assert(image->cache != (Cache) NULL);
1760 cache_info=(CacheInfo *) image->cache;
1761 assert(cache_info->signature == MagickSignature);
1762 if (cache_info->methods.get_authentic_indexes_from_handler ==
1763 (GetAuthenticIndexesFromHandler) NULL)
1764 return((IndexPacket *) NULL);
1765 return(cache_info->methods.get_authentic_indexes_from_handler(image));
1766}
1767
1768/*
1769%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1770% %
1771% %
1772% %
1773+ 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 %
1774% %
1775% %
1776% %
1777%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1778%
1779% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1780% disk pixel cache as defined by the geometry parameters. A pointer to the
1781% pixels is returned if the pixels are transferred, otherwise a NULL is
1782% returned.
1783%
1784% The format of the GetAuthenticPixelCacheNexus() method is:
1785%
cristybb503372010-05-27 20:51:26 +00001786% PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1787% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001788% NexusInfo *nexus_info,ExceptionInfo *exception)
1789%
1790% A description of each parameter follows:
1791%
1792% o image: the image.
1793%
1794% o x,y,columns,rows: These values define the perimeter of a region of
1795% pixels.
1796%
1797% o nexus_info: the cache nexus to return.
1798%
1799% o exception: return any errors or warnings in this structure.
1800%
1801*/
1802
1803static inline MagickBooleanType IsNexusInCore(const CacheInfo *cache_info,
1804 NexusInfo *nexus_info)
1805{
1806 MagickOffsetType
1807 offset;
1808
cristy73724512010-04-12 14:43:14 +00001809 if (cache_info->type == PingCache)
1810 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001811 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1812 nexus_info->region.x;
1813 if (nexus_info->pixels != (cache_info->pixels+offset))
1814 return(MagickFalse);
1815 return(MagickTrue);
1816}
1817
cristye076a6e2010-08-15 19:59:43 +00001818MagickExport PixelPacket *GetAuthenticPixelCacheNexus(Image *image,
1819 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001820 NexusInfo *nexus_info,ExceptionInfo *exception)
1821{
1822 CacheInfo
1823 *cache_info;
1824
1825 PixelPacket
1826 *pixels;
1827
1828 /*
1829 Transfer pixels from the cache.
1830 */
1831 assert(image != (Image *) NULL);
1832 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001833 pixels=QueueAuthenticNexus(image,x,y,columns,rows,nexus_info,exception);
1834 if (pixels == (PixelPacket *) NULL)
1835 return((PixelPacket *) NULL);
1836 cache_info=(CacheInfo *) image->cache;
1837 assert(cache_info->signature == MagickSignature);
1838 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
1839 return(pixels);
1840 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1841 return((PixelPacket *) NULL);
1842 if (cache_info->active_index_channel != MagickFalse)
1843 if (ReadPixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse)
1844 return((PixelPacket *) NULL);
1845 return(pixels);
1846}
1847
1848/*
1849%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1850% %
1851% %
1852% %
1853+ 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 %
1854% %
1855% %
1856% %
1857%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1858%
1859% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1860% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1861%
1862% The format of the GetAuthenticPixelsFromCache() method is:
1863%
1864% PixelPacket *GetAuthenticPixelsFromCache(const Image image)
1865%
1866% A description of each parameter follows:
1867%
1868% o image: the image.
1869%
1870*/
1871static PixelPacket *GetAuthenticPixelsFromCache(const Image *image)
1872{
1873 CacheInfo
1874 *cache_info;
1875
cristy6ebe97c2010-07-03 01:17:28 +00001876 int
cristy3ed852e2009-09-05 21:47:34 +00001877 id;
1878
1879 PixelPacket
1880 *pixels;
1881
cristy3ed852e2009-09-05 21:47:34 +00001882 cache_info=(CacheInfo *) image->cache;
1883 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00001884 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001885 pixels=GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]);
1886 return(pixels);
1887}
1888
1889/*
1890%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1891% %
1892% %
1893% %
1894% G e t A u t h e n t i c P i x e l Q u e u e %
1895% %
1896% %
1897% %
1898%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1899%
1900% GetAuthenticPixelQueue() returns the authentic pixels associated with the
1901% last call to QueueAuthenticPixels() or GetAuthenticPixels().
1902%
1903% The format of the GetAuthenticPixelQueue() method is:
1904%
1905% PixelPacket *GetAuthenticPixelQueue(const Image image)
1906%
1907% A description of each parameter follows:
1908%
1909% o image: the image.
1910%
1911*/
1912MagickExport PixelPacket *GetAuthenticPixelQueue(const Image *image)
1913{
1914 CacheInfo
1915 *cache_info;
1916
1917 assert(image != (const Image *) NULL);
1918 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001919 assert(image->cache != (Cache) NULL);
1920 cache_info=(CacheInfo *) image->cache;
1921 assert(cache_info->signature == MagickSignature);
1922 if (cache_info->methods.get_authentic_pixels_from_handler ==
1923 (GetAuthenticPixelsFromHandler) NULL)
1924 return((PixelPacket *) NULL);
1925 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1926}
1927
1928/*
1929%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1930% %
1931% %
1932% %
1933% G e t A u t h e n t i c P i x e l s %
1934% %
1935% %
1936% %
1937%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1938%
1939% GetAuthenticPixels() obtains a pixel region for read/write access. If the
1940% region is successfully accessed, a pointer to a PixelPacket array
1941% representing the region is returned, otherwise NULL is returned.
1942%
1943% The returned pointer may point to a temporary working copy of the pixels
1944% or it may point to the original pixels in memory. Performance is maximized
1945% if the selected region is part of one row, or one or more full rows, since
1946% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001947% if the image is in memory, or in a memory-mapped file. The returned pointer
1948% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001949%
1950% Pixels accessed via the returned pointer represent a simple array of type
1951% PixelPacket. If the image type is CMYK or if the storage class is
1952% PseduoClass, call GetAuthenticIndexQueue() after invoking
1953% GetAuthenticPixels() to obtain the black color component or colormap indexes
1954% (of type IndexPacket) corresponding to the region. Once the PixelPacket
1955% (and/or IndexPacket) array has been updated, the changes must be saved back
1956% to the underlying image using SyncAuthenticPixels() or they may be lost.
1957%
1958% The format of the GetAuthenticPixels() method is:
1959%
cristy5f959472010-05-27 22:19:46 +00001960% PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1961% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001962% ExceptionInfo *exception)
1963%
1964% A description of each parameter follows:
1965%
1966% o image: the image.
1967%
1968% o x,y,columns,rows: These values define the perimeter of a region of
1969% pixels.
1970%
1971% o exception: return any errors or warnings in this structure.
1972%
1973*/
cristybb503372010-05-27 20:51:26 +00001974MagickExport PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1975 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001976 ExceptionInfo *exception)
1977{
1978 CacheInfo
1979 *cache_info;
1980
1981 PixelPacket
1982 *pixels;
1983
1984 assert(image != (Image *) NULL);
1985 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001986 assert(image->cache != (Cache) NULL);
1987 cache_info=(CacheInfo *) image->cache;
1988 assert(cache_info->signature == MagickSignature);
1989 if (cache_info->methods.get_authentic_pixels_handler ==
1990 (GetAuthenticPixelsHandler) NULL)
1991 return((PixelPacket *) NULL);
1992 pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1993 rows,exception);
1994 return(pixels);
1995}
1996
1997/*
1998%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1999% %
2000% %
2001% %
2002+ G e t A u t h e n t i c P i x e l s C a c h e %
2003% %
2004% %
2005% %
2006%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2007%
2008% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
2009% as defined by the geometry parameters. A pointer to the pixels is returned
2010% if the pixels are transferred, otherwise a NULL is returned.
2011%
2012% The format of the GetAuthenticPixelsCache() method is:
2013%
cristybb503372010-05-27 20:51:26 +00002014% PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
2015% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00002016% ExceptionInfo *exception)
2017%
2018% A description of each parameter follows:
2019%
2020% o image: the image.
2021%
2022% o x,y,columns,rows: These values define the perimeter of a region of
2023% pixels.
2024%
2025% o exception: return any errors or warnings in this structure.
2026%
2027*/
cristybb503372010-05-27 20:51:26 +00002028static PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
2029 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00002030 ExceptionInfo *exception)
2031{
2032 CacheInfo
2033 *cache_info;
2034
cristy6ebe97c2010-07-03 01:17:28 +00002035 int
cristy3ed852e2009-09-05 21:47:34 +00002036 id;
2037
2038 PixelPacket
2039 *pixels;
2040
2041 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
2042 if (cache_info == (Cache) NULL)
2043 return((PixelPacket *) NULL);
2044 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00002045 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00002046 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
2047 cache_info->nexus_info[id],exception);
2048 return(pixels);
2049}
2050
2051/*
2052%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2053% %
2054% %
2055% %
2056+ G e t I m a g e E x t e n t %
2057% %
2058% %
2059% %
2060%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2061%
2062% GetImageExtent() returns the extent of the pixels associated with the
2063% last call to QueueAuthenticPixels() or GetAuthenticPixels().
2064%
2065% The format of the GetImageExtent() method is:
2066%
2067% MagickSizeType GetImageExtent(const Image *image)
2068%
2069% A description of each parameter follows:
2070%
2071% o image: the image.
2072%
2073*/
2074MagickExport MagickSizeType GetImageExtent(const Image *image)
2075{
2076 CacheInfo
2077 *cache_info;
2078
cristy6ebe97c2010-07-03 01:17:28 +00002079 int
cristy3ed852e2009-09-05 21:47:34 +00002080 id;
2081
2082 MagickSizeType
2083 extent;
2084
2085 assert(image != (Image *) NULL);
2086 assert(image->signature == MagickSignature);
2087 if (image->debug != MagickFalse)
2088 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2089 assert(image->cache != (Cache) NULL);
2090 cache_info=(CacheInfo *) image->cache;
2091 assert(cache_info->signature == MagickSignature);
2092 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00002093 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00002094 extent=GetPixelCacheNexusExtent(image->cache,cache_info->nexus_info[id]);
2095 return(extent);
2096}
2097
2098/*
2099%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2100% %
2101% %
2102% %
2103+ G e t I m a g e P i x e l C a c h e %
2104% %
2105% %
2106% %
2107%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2108%
2109% GetImagePixelCache() ensures that there is only a single reference to the
2110% pixel cache to be modified, updating the provided cache pointer to point to
2111% a clone of the original pixel cache if necessary.
2112%
2113% The format of the GetImagePixelCache method is:
2114%
2115% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2116% ExceptionInfo *exception)
2117%
2118% A description of each parameter follows:
2119%
2120% o image: the image.
2121%
2122% o clone: any value other than MagickFalse clones the cache pixels.
2123%
2124% o exception: return any errors or warnings in this structure.
2125%
2126*/
cristy3ed852e2009-09-05 21:47:34 +00002127static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
2128{
2129 CacheInfo
2130 *cache_info;
2131
2132 /*
2133 Does the image match the pixel cache morphology?
2134 */
2135 cache_info=(CacheInfo *) image->cache;
2136 if ((image->storage_class != cache_info->storage_class) ||
2137 (image->colorspace != cache_info->colorspace) ||
2138 (image->columns != cache_info->columns) ||
2139 (image->rows != cache_info->rows) ||
2140 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2141 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2142 return(MagickFalse);
2143 return(MagickTrue);
2144}
2145
2146MagickExport Cache GetImagePixelCache(Image *image,
2147 const MagickBooleanType clone,ExceptionInfo *exception)
2148{
2149 CacheInfo
2150 *cache_info;
2151
cristy3ed852e2009-09-05 21:47:34 +00002152 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00002153 destroy,
cristy3ed852e2009-09-05 21:47:34 +00002154 status;
2155
cristy50a10922010-02-15 18:35:25 +00002156 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00002157 cpu_throttle = 0,
2158 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00002159 time_limit = 0;
2160
cristy1ea34962010-07-01 19:49:21 +00002161 static time_t
cristya21afde2010-07-02 00:45:40 +00002162 cache_genesis = 0;
cristy1ea34962010-07-01 19:49:21 +00002163
cristyc4f9f132010-03-04 18:50:01 +00002164 status=MagickTrue;
2165 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00002166 if (cpu_throttle == 0)
2167 {
2168 char
2169 *limit;
2170
2171 /*
2172 Set CPU throttle in milleseconds.
2173 */
2174 cpu_throttle=MagickResourceInfinity;
2175 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2176 if (limit == (char *) NULL)
2177 limit=GetPolicyValue("throttle");
2178 if (limit != (char *) NULL)
2179 {
2180 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2181 limit=DestroyString(limit);
2182 }
2183 }
2184 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2185 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00002186 if (time_limit == 0)
2187 {
cristy6ebe97c2010-07-03 01:17:28 +00002188 /*
2189 Set the exire time in seconds.
2190 */
cristy1ea34962010-07-01 19:49:21 +00002191 time_limit=GetMagickResourceLimit(TimeResource);
cristya21afde2010-07-02 00:45:40 +00002192 cache_genesis=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00002193 }
2194 if ((time_limit != MagickResourceInfinity) &&
cristya21afde2010-07-02 00:45:40 +00002195 ((MagickSizeType) (time((time_t *) NULL)-cache_genesis) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00002196 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00002197 assert(image->cache != (Cache) NULL);
2198 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002199 destroy=MagickFalse;
cristy01b7eb02009-09-10 23:10:14 +00002200 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002201 {
cristyaaa0cb62010-02-15 17:47:27 +00002202 LockSemaphoreInfo(cache_info->semaphore);
2203 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002204 {
cristyaaa0cb62010-02-15 17:47:27 +00002205 Image
2206 clone_image;
2207
2208 CacheInfo
2209 *clone_info;
2210
2211 /*
2212 Clone pixel cache.
2213 */
2214 clone_image=(*image);
cristy93505cf2010-08-10 21:37:49 +00002215 clone_image.semaphore=AllocateSemaphoreInfo();
2216 clone_image.reference_count=1;
cristyaaa0cb62010-02-15 17:47:27 +00002217 clone_image.cache=ClonePixelCache(cache_info);
2218 clone_info=(CacheInfo *) clone_image.cache;
2219 status=ClonePixelCacheNexus(cache_info,clone_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00002220 if (status != MagickFalse)
2221 {
cristyaaa0cb62010-02-15 17:47:27 +00002222 status=OpenPixelCache(&clone_image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00002223 if (status != MagickFalse)
2224 {
cristyaaa0cb62010-02-15 17:47:27 +00002225 if (clone != MagickFalse)
2226 status=ClonePixelCachePixels(clone_info,cache_info,
2227 exception);
2228 if (status != MagickFalse)
2229 {
2230 destroy=MagickTrue;
2231 image->cache=clone_image.cache;
2232 }
cristy3ed852e2009-09-05 21:47:34 +00002233 }
2234 }
cristy93505cf2010-08-10 21:37:49 +00002235 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002236 }
cristyaaa0cb62010-02-15 17:47:27 +00002237 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002238 }
cristy4320e0e2009-09-10 15:00:08 +00002239 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002240 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002241 if (status != MagickFalse)
2242 {
2243 /*
2244 Ensure the image matches the pixel cache morphology.
2245 */
2246 image->taint=MagickTrue;
2247 image->type=UndefinedType;
cristydd438462010-05-06 13:44:04 +00002248 if (image->colorspace == GRAYColorspace)
2249 image->colorspace=RGBColorspace;
cristy3ed852e2009-09-05 21:47:34 +00002250 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2251 status=OpenPixelCache(image,IOMode,exception);
2252 }
cristyf84a1932010-01-03 18:00:18 +00002253 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002254 if (status == MagickFalse)
2255 return((Cache) NULL);
2256 return(image->cache);
2257}
2258
2259/*
2260%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2261% %
2262% %
2263% %
2264% G e t O n e A u t h e n t i c P i x e l %
2265% %
2266% %
2267% %
2268%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2269%
2270% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2271% location. The image background color is returned if an error occurs.
2272%
2273% The format of the GetOneAuthenticPixel() method is:
2274%
cristybb503372010-05-27 20:51:26 +00002275% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2276% const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002277%
2278% A description of each parameter follows:
2279%
2280% o image: the image.
2281%
2282% o x,y: These values define the location of the pixel to return.
2283%
2284% o pixel: return a pixel at the specified (x,y) location.
2285%
2286% o exception: return any errors or warnings in this structure.
2287%
2288*/
cristyacbbb7c2010-06-30 18:56:48 +00002289MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2290 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002291{
2292 CacheInfo
2293 *cache_info;
2294
2295 GetOneAuthenticPixelFromHandler
2296 get_one_authentic_pixel_from_handler;
2297
2298 MagickBooleanType
2299 status;
2300
2301 assert(image != (Image *) NULL);
2302 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002303 assert(image->cache != (Cache) NULL);
2304 cache_info=(CacheInfo *) image->cache;
2305 assert(cache_info->signature == MagickSignature);
2306 *pixel=image->background_color;
2307 get_one_authentic_pixel_from_handler=
2308 cache_info->methods.get_one_authentic_pixel_from_handler;
2309 if (get_one_authentic_pixel_from_handler ==
2310 (GetOneAuthenticPixelFromHandler) NULL)
2311 return(MagickFalse);
2312 status=cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2313 pixel,exception);
2314 return(status);
2315}
2316
2317/*
2318%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2319% %
2320% %
2321% %
2322+ 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 %
2323% %
2324% %
2325% %
2326%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2327%
2328% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2329% location. The image background color is returned if an error occurs.
2330%
2331% The format of the GetOneAuthenticPixelFromCache() method is:
2332%
2333% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy5f959472010-05-27 22:19:46 +00002334% const ssize_t x,const ssize_t y,PixelPacket *pixel,
2335% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002336%
2337% A description of each parameter follows:
2338%
2339% o image: the image.
2340%
2341% o x,y: These values define the location of the pixel to return.
2342%
2343% o pixel: return a pixel at the specified (x,y) location.
2344%
2345% o exception: return any errors or warnings in this structure.
2346%
2347*/
2348static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristybb503372010-05-27 20:51:26 +00002349 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002350{
2351 PixelPacket
2352 *pixels;
2353
cristy3ed852e2009-09-05 21:47:34 +00002354 *pixel=image->background_color;
2355 pixels=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2356 if (pixels == (PixelPacket *) NULL)
2357 return(MagickFalse);
2358 *pixel=(*pixels);
2359 return(MagickTrue);
2360}
2361
2362/*
2363%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2364% %
2365% %
2366% %
2367% G e t O n e V i r t u a l M a g i c k P i x e l %
2368% %
2369% %
2370% %
2371%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2372%
2373% GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2374% location. The image background color is returned if an error occurs. If
2375% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2376%
2377% The format of the GetOneVirtualMagickPixel() method is:
2378%
2379% MagickBooleanType GetOneVirtualMagickPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002380% const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
cristy3ed852e2009-09-05 21:47:34 +00002381% ExceptionInfo exception)
2382%
2383% A description of each parameter follows:
2384%
2385% o image: the image.
2386%
2387% o x,y: these values define the location of the pixel to return.
2388%
2389% o pixel: return a pixel at the specified (x,y) location.
2390%
2391% o exception: return any errors or warnings in this structure.
2392%
2393*/
2394MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
cristyacbbb7c2010-06-30 18:56:48 +00002395 const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
2396 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002397{
2398 CacheInfo
2399 *cache_info;
2400
2401 register const IndexPacket
2402 *indexes;
2403
2404 register const PixelPacket
2405 *p;
2406
2407 assert(image != (const Image *) NULL);
2408 assert(image->signature == MagickSignature);
2409 assert(image->cache != (Cache) NULL);
2410 cache_info=(CacheInfo *) image->cache;
2411 assert(cache_info->signature == MagickSignature);
2412 GetMagickPixelPacket(image,pixel);
2413 p=GetVirtualPixelCache(image,GetPixelCacheVirtualMethod(image),x,y,1,1,
2414 exception);
2415 if (p == (const PixelPacket *) NULL)
2416 return(MagickFalse);
2417 indexes=GetVirtualIndexQueue(image);
2418 SetMagickPixelPacket(image,p,indexes,pixel);
2419 return(MagickTrue);
2420}
2421
2422/*
2423%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2424% %
2425% %
2426% %
2427% G e t O n e V i r t u a l M e t h o d P i x e l %
2428% %
2429% %
2430% %
2431%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2432%
2433% GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2434% location as defined by specified pixel method. The image background color
2435% is returned if an error occurs. If you plan to modify the pixel, use
2436% GetOneAuthenticPixel() instead.
2437%
2438% The format of the GetOneVirtualMethodPixel() method is:
2439%
2440% MagickBooleanType GetOneVirtualMethodPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002441% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2442% const ssize_t y,Pixelpacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002443%
2444% A description of each parameter follows:
2445%
2446% o image: the image.
2447%
2448% o virtual_pixel_method: the virtual pixel method.
2449%
2450% o x,y: These values define the location of the pixel to return.
2451%
2452% o pixel: return a pixel at the specified (x,y) location.
2453%
2454% o exception: return any errors or warnings in this structure.
2455%
2456*/
2457MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002458 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002459 PixelPacket *pixel,ExceptionInfo *exception)
2460{
2461 GetOneVirtualPixelFromHandler
2462 get_one_virtual_pixel_from_handler;
2463
2464 CacheInfo
2465 *cache_info;
2466
2467 MagickBooleanType
2468 status;
2469
2470 assert(image != (const Image *) NULL);
2471 assert(image->signature == MagickSignature);
2472 assert(image->cache != (Cache) NULL);
2473 cache_info=(CacheInfo *) image->cache;
2474 assert(cache_info->signature == MagickSignature);
2475 *pixel=image->background_color;
2476 get_one_virtual_pixel_from_handler=
2477 cache_info->methods.get_one_virtual_pixel_from_handler;
2478 if (get_one_virtual_pixel_from_handler ==
2479 (GetOneVirtualPixelFromHandler) NULL)
2480 return(MagickFalse);
2481 status=get_one_virtual_pixel_from_handler(image,virtual_pixel_method,x,y,
2482 pixel,exception);
2483 return(status);
2484}
2485
2486/*
2487%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2488% %
2489% %
2490% %
2491% G e t O n e V i r t u a l P i x e l %
2492% %
2493% %
2494% %
2495%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2496%
2497% GetOneVirtualPixel() returns a single virtual pixel at the specified
2498% (x,y) location. The image background color is returned if an error occurs.
2499% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2500%
2501% The format of the GetOneVirtualPixel() method is:
2502%
cristybb503372010-05-27 20:51:26 +00002503% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2504% const ssize_t y,PixelPacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002505%
2506% A description of each parameter follows:
2507%
2508% o image: the image.
2509%
2510% o x,y: These values define the location of the pixel to return.
2511%
2512% o pixel: return a pixel at the specified (x,y) location.
2513%
2514% o exception: return any errors or warnings in this structure.
2515%
2516*/
2517MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002518 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002519{
2520 GetOneVirtualPixelFromHandler
2521 get_one_virtual_pixel_from_handler;
2522
2523 CacheInfo
2524 *cache_info;
2525
2526 MagickBooleanType
2527 status;
2528
2529 assert(image != (const Image *) NULL);
2530 assert(image->signature == MagickSignature);
2531 assert(image->cache != (Cache) NULL);
2532 cache_info=(CacheInfo *) image->cache;
2533 assert(cache_info->signature == MagickSignature);
2534 *pixel=image->background_color;
2535 get_one_virtual_pixel_from_handler=
2536 cache_info->methods.get_one_virtual_pixel_from_handler;
2537 if (get_one_virtual_pixel_from_handler ==
2538 (GetOneVirtualPixelFromHandler) NULL)
2539 return(MagickFalse);
2540 status=get_one_virtual_pixel_from_handler(image,GetPixelCacheVirtualMethod(
2541 image),x,y,pixel,exception);
2542 return(status);
2543}
2544
2545/*
2546%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2547% %
2548% %
2549% %
2550+ 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 %
2551% %
2552% %
2553% %
2554%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2555%
2556% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2557% specified (x,y) location. The image background color is returned if an
2558% error occurs.
2559%
2560% The format of the GetOneVirtualPixelFromCache() method is:
2561%
2562% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristybb503372010-05-27 20:51:26 +00002563% const VirtualPixelPacket method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002564% PixelPacket *pixel,ExceptionInfo *exception)
2565%
2566% A description of each parameter follows:
2567%
2568% o image: the image.
2569%
2570% o virtual_pixel_method: the virtual pixel method.
2571%
2572% o x,y: These values define the location of the pixel to return.
2573%
2574% o pixel: return a pixel at the specified (x,y) location.
2575%
2576% o exception: return any errors or warnings in this structure.
2577%
2578*/
2579static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002580 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002581 PixelPacket *pixel,ExceptionInfo *exception)
2582{
2583 const PixelPacket
2584 *pixels;
2585
2586 *pixel=image->background_color;
2587 pixels=GetVirtualPixelCache(image,virtual_pixel_method,x,y,1UL,1UL,exception);
2588 if (pixels == (const PixelPacket *) NULL)
2589 return(MagickFalse);
2590 *pixel=(*pixels);
2591 return(MagickTrue);
2592}
2593
2594/*
2595%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2596% %
2597% %
2598% %
2599+ G e t P i x e l C a c h e C o l o r s p a c e %
2600% %
2601% %
2602% %
2603%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2604%
2605% GetPixelCacheColorspace() returns the class type of the pixel cache.
2606%
2607% The format of the GetPixelCacheColorspace() method is:
2608%
2609% Colorspace GetPixelCacheColorspace(Cache cache)
2610%
2611% A description of each parameter follows:
2612%
2613% o cache: the pixel cache.
2614%
2615*/
2616MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
2617{
2618 CacheInfo
2619 *cache_info;
2620
2621 assert(cache != (Cache) NULL);
2622 cache_info=(CacheInfo *) cache;
2623 assert(cache_info->signature == MagickSignature);
2624 if (cache_info->debug != MagickFalse)
2625 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2626 cache_info->filename);
2627 return(cache_info->colorspace);
2628}
2629
2630/*
2631%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2632% %
2633% %
2634% %
2635+ G e t P i x e l C a c h e M e t h o d s %
2636% %
2637% %
2638% %
2639%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2640%
2641% GetPixelCacheMethods() initializes the CacheMethods structure.
2642%
2643% The format of the GetPixelCacheMethods() method is:
2644%
2645% void GetPixelCacheMethods(CacheMethods *cache_methods)
2646%
2647% A description of each parameter follows:
2648%
2649% o cache_methods: Specifies a pointer to a CacheMethods structure.
2650%
2651*/
2652MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
2653{
2654 assert(cache_methods != (CacheMethods *) NULL);
2655 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2656 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2657 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2658 cache_methods->get_virtual_indexes_from_handler=GetVirtualIndexesFromCache;
2659 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2660 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2661 cache_methods->get_authentic_indexes_from_handler=
2662 GetAuthenticIndexesFromCache;
2663 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2664 cache_methods->get_one_authentic_pixel_from_handler=
2665 GetOneAuthenticPixelFromCache;
2666 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2667 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2668 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2669}
2670
2671/*
2672%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2673% %
2674% %
2675% %
2676+ G e t P i x e l C a c h e N e x u s E x t e n t %
2677% %
2678% %
2679% %
2680%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2681%
2682% GetPixelCacheNexusExtent() returns the extent of the pixels associated with
2683% the last call to SetPixelCacheNexusPixels() or GetPixelCacheNexusPixels().
2684%
2685% The format of the GetPixelCacheNexusExtent() method is:
2686%
2687% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2688% NexusInfo *nexus_info)
2689%
2690% A description of each parameter follows:
2691%
2692% o nexus_info: the nexus info.
2693%
2694*/
2695MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2696 NexusInfo *nexus_info)
2697{
2698 CacheInfo
2699 *cache_info;
2700
2701 MagickSizeType
2702 extent;
2703
2704 if (cache == (Cache) NULL)
2705 return(0);
2706 cache_info=(CacheInfo *) cache;
2707 assert(cache_info->signature == MagickSignature);
2708 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2709 if (extent == 0)
2710 return((MagickSizeType) cache_info->columns*cache_info->rows);
2711 return(extent);
2712}
2713
2714/*
2715%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2716% %
2717% %
2718% %
2719+ 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 %
2720% %
2721% %
2722% %
2723%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2724%
2725% GetPixelCacheNexusIndexes() returns the indexes associated with the
2726% specified cache nexus.
2727%
2728% The format of the GetPixelCacheNexusIndexes() method is:
2729%
2730% IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2731% NexusInfo *nexus_info)
2732%
2733% A description of each parameter follows:
2734%
2735% o cache: the pixel cache.
2736%
2737% o nexus_info: the cache nexus to return the colormap indexes.
2738%
2739*/
2740MagickExport IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2741 NexusInfo *nexus_info)
2742{
2743 CacheInfo
2744 *cache_info;
2745
2746 if (cache == (Cache) NULL)
2747 return((IndexPacket *) NULL);
2748 cache_info=(CacheInfo *) cache;
2749 assert(cache_info->signature == MagickSignature);
2750 if (cache_info->storage_class == UndefinedClass)
2751 return((IndexPacket *) NULL);
2752 return(nexus_info->indexes);
2753}
2754
2755/*
2756%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2757% %
2758% %
2759% %
2760+ G e t P i x e l C a c h e N e x u s P i x e l s %
2761% %
2762% %
2763% %
2764%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2765%
2766% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2767% cache nexus.
2768%
2769% The format of the GetPixelCacheNexusPixels() method is:
2770%
2771% PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2772% NexusInfo *nexus_info)
2773%
2774% A description of each parameter follows:
2775%
2776% o cache: the pixel cache.
2777%
2778% o nexus_info: the cache nexus to return the pixels.
2779%
2780*/
2781MagickExport PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2782 NexusInfo *nexus_info)
2783{
2784 CacheInfo
2785 *cache_info;
2786
2787 if (cache == (Cache) NULL)
2788 return((PixelPacket *) NULL);
2789 cache_info=(CacheInfo *) cache;
2790 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002791 if (cache_info->storage_class == UndefinedClass)
2792 return((PixelPacket *) NULL);
2793 return(nexus_info->pixels);
2794}
2795
2796/*
2797%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2798% %
2799% %
2800% %
cristy056ba772010-01-02 23:33:54 +00002801+ G e t P i x e l C a c h e P i x e l s %
2802% %
2803% %
2804% %
2805%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2806%
2807% GetPixelCachePixels() returns the pixels associated with the specified image.
2808%
2809% The format of the GetPixelCachePixels() method is:
2810%
cristyf84a1932010-01-03 18:00:18 +00002811% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2812% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002813%
2814% A description of each parameter follows:
2815%
2816% o image: the image.
2817%
2818% o length: the pixel cache length.
2819%
cristyf84a1932010-01-03 18:00:18 +00002820% o exception: return any errors or warnings in this structure.
2821%
cristy056ba772010-01-02 23:33:54 +00002822*/
cristyf84a1932010-01-03 18:00:18 +00002823MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2824 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002825{
2826 CacheInfo
2827 *cache_info;
2828
2829 assert(image != (const Image *) NULL);
2830 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002831 assert(image->cache != (Cache) NULL);
cristyc4c8d132010-01-07 01:58:38 +00002832 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
cristy056ba772010-01-02 23:33:54 +00002833 assert(cache_info->signature == MagickSignature);
2834 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002835 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002836 return((void *) NULL);
2837 *length=cache_info->length;
2838 return((void *) cache_info->pixels);
2839}
2840
2841/*
2842%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2843% %
2844% %
2845% %
cristyb32b90a2009-09-07 21:45:48 +00002846+ 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 +00002847% %
2848% %
2849% %
2850%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2851%
2852% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2853%
2854% The format of the GetPixelCacheStorageClass() method is:
2855%
2856% ClassType GetPixelCacheStorageClass(Cache cache)
2857%
2858% A description of each parameter follows:
2859%
2860% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2861%
2862% o cache: the pixel cache.
2863%
2864*/
2865MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
2866{
2867 CacheInfo
2868 *cache_info;
2869
2870 assert(cache != (Cache) NULL);
2871 cache_info=(CacheInfo *) cache;
2872 assert(cache_info->signature == MagickSignature);
2873 if (cache_info->debug != MagickFalse)
2874 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2875 cache_info->filename);
2876 return(cache_info->storage_class);
2877}
2878
2879/*
2880%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2881% %
2882% %
2883% %
cristyb32b90a2009-09-07 21:45:48 +00002884+ G e t P i x e l C a c h e T i l e S i z e %
2885% %
2886% %
2887% %
2888%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2889%
2890% GetPixelCacheTileSize() returns the pixel cache tile size.
2891%
2892% The format of the GetPixelCacheTileSize() method is:
2893%
cristybb503372010-05-27 20:51:26 +00002894% void GetPixelCacheTileSize(const Image *image,size_t *width,
2895% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002896%
2897% A description of each parameter follows:
2898%
2899% o image: the image.
2900%
2901% o width: the optimize cache tile width in pixels.
2902%
2903% o height: the optimize cache tile height in pixels.
2904%
2905*/
cristybb503372010-05-27 20:51:26 +00002906MagickExport void GetPixelCacheTileSize(const Image *image,size_t *width,
2907 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002908{
2909 CacheInfo
2910 *cache_info;
2911
2912 assert(image != (Image *) NULL);
2913 assert(image->signature == MagickSignature);
2914 if (image->debug != MagickFalse)
2915 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2916 assert(image->cache != (Cache) NULL);
2917 cache_info=(CacheInfo *) image->cache;
2918 assert(cache_info->signature == MagickSignature);
2919 *width=2048UL/sizeof(PixelPacket);
2920 if (GetPixelCacheType(image) == DiskCache)
cristydaa97692009-09-13 02:10:35 +00002921 *width=8192UL/sizeof(PixelPacket);
cristyb32b90a2009-09-07 21:45:48 +00002922 *height=(*width);
2923}
2924
2925/*
2926%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2927% %
2928% %
2929% %
2930+ G e t P i x e l C a c h e T y p e %
2931% %
2932% %
2933% %
2934%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2935%
2936% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2937%
2938% The format of the GetPixelCacheType() method is:
2939%
2940% CacheType GetPixelCacheType(const Image *image)
2941%
2942% A description of each parameter follows:
2943%
2944% o image: the image.
2945%
2946*/
2947MagickExport CacheType GetPixelCacheType(const Image *image)
2948{
2949 CacheInfo
2950 *cache_info;
2951
2952 assert(image != (Image *) NULL);
2953 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002954 assert(image->cache != (Cache) NULL);
2955 cache_info=(CacheInfo *) image->cache;
2956 assert(cache_info->signature == MagickSignature);
2957 return(cache_info->type);
2958}
2959
2960/*
2961%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2962% %
2963% %
2964% %
cristy3ed852e2009-09-05 21:47:34 +00002965+ 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 %
2966% %
2967% %
2968% %
2969%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2970%
2971% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2972% pixel cache. A virtual pixel is any pixel access that is outside the
2973% boundaries of the image cache.
2974%
2975% The format of the GetPixelCacheVirtualMethod() method is:
2976%
2977% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2978%
2979% A description of each parameter follows:
2980%
2981% o image: the image.
2982%
2983*/
2984MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2985{
2986 CacheInfo
2987 *cache_info;
2988
2989 assert(image != (Image *) NULL);
2990 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002991 assert(image->cache != (Cache) NULL);
2992 cache_info=(CacheInfo *) image->cache;
2993 assert(cache_info->signature == MagickSignature);
2994 return(cache_info->virtual_pixel_method);
2995}
2996
2997/*
2998%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2999% %
3000% %
3001% %
3002+ 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 %
3003% %
3004% %
3005% %
3006%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3007%
3008% GetVirtualIndexesFromCache() returns the indexes associated with the last
3009% call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3010%
3011% The format of the GetVirtualIndexesFromCache() method is:
3012%
3013% IndexPacket *GetVirtualIndexesFromCache(const Image *image)
3014%
3015% A description of each parameter follows:
3016%
3017% o image: the image.
3018%
3019*/
3020static const IndexPacket *GetVirtualIndexesFromCache(const Image *image)
3021{
3022 CacheInfo
3023 *cache_info;
3024
3025 const IndexPacket
3026 *indexes;
3027
cristy6ebe97c2010-07-03 01:17:28 +00003028 int
cristy3ed852e2009-09-05 21:47:34 +00003029 id;
3030
cristy3ed852e2009-09-05 21:47:34 +00003031 cache_info=(CacheInfo *) image->cache;
3032 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00003033 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00003034 indexes=GetVirtualIndexesFromNexus(image->cache,cache_info->nexus_info[id]);
3035 return(indexes);
3036}
3037
3038/*
3039%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3040% %
3041% %
3042% %
3043+ 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 %
3044% %
3045% %
3046% %
3047%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3048%
3049% GetVirtualIndexesFromNexus() returns the indexes associated with the
3050% specified cache nexus.
3051%
3052% The format of the GetVirtualIndexesFromNexus() method is:
3053%
3054% const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
3055% NexusInfo *nexus_info)
3056%
3057% A description of each parameter follows:
3058%
3059% o cache: the pixel cache.
3060%
3061% o nexus_info: the cache nexus to return the colormap indexes.
3062%
3063*/
3064MagickExport const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
3065 NexusInfo *nexus_info)
3066{
3067 CacheInfo
3068 *cache_info;
3069
3070 if (cache == (Cache) NULL)
3071 return((IndexPacket *) NULL);
3072 cache_info=(CacheInfo *) cache;
3073 assert(cache_info->signature == MagickSignature);
3074 if (cache_info->storage_class == UndefinedClass)
3075 return((IndexPacket *) NULL);
3076 return(nexus_info->indexes);
3077}
3078
3079/*
3080%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3081% %
3082% %
3083% %
3084% G e t V i r t u a l I n d e x Q u e u e %
3085% %
3086% %
3087% %
3088%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3089%
3090% GetVirtualIndexQueue() returns the virtual black channel or the
3091% colormap indexes associated with the last call to QueueAuthenticPixels() or
3092% GetVirtualPixels(). NULL is returned if the black channel or colormap
3093% indexes are not available.
3094%
3095% The format of the GetVirtualIndexQueue() method is:
3096%
3097% const IndexPacket *GetVirtualIndexQueue(const Image *image)
3098%
3099% A description of each parameter follows:
3100%
3101% o image: the image.
3102%
3103*/
3104MagickExport const IndexPacket *GetVirtualIndexQueue(const Image *image)
3105{
3106 CacheInfo
3107 *cache_info;
3108
3109 assert(image != (const Image *) NULL);
3110 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003111 assert(image->cache != (Cache) NULL);
3112 cache_info=(CacheInfo *) image->cache;
3113 assert(cache_info->signature == MagickSignature);
3114 if (cache_info->methods.get_virtual_indexes_from_handler ==
3115 (GetVirtualIndexesFromHandler) NULL)
3116 return((IndexPacket *) NULL);
3117 return(cache_info->methods.get_virtual_indexes_from_handler(image));
3118}
3119
3120/*
3121%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3122% %
3123% %
3124% %
3125+ 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 %
3126% %
3127% %
3128% %
3129%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3130%
3131% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3132% pixel cache as defined by the geometry parameters. A pointer to the pixels
3133% is returned if the pixels are transferred, otherwise a NULL is returned.
3134%
3135% The format of the GetVirtualPixelsFromNexus() method is:
3136%
3137% PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003138% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00003139% const size_t columns,const size_t rows,NexusInfo *nexus_info,
3140% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003141%
3142% A description of each parameter follows:
3143%
3144% o image: the image.
3145%
3146% o virtual_pixel_method: the virtual pixel method.
3147%
3148% o x,y,columns,rows: These values define the perimeter of a region of
3149% pixels.
3150%
3151% o nexus_info: the cache nexus to acquire.
3152%
3153% o exception: return any errors or warnings in this structure.
3154%
3155*/
3156
cristybb503372010-05-27 20:51:26 +00003157static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003158 DitherMatrix[64] =
3159 {
3160 0, 48, 12, 60, 3, 51, 15, 63,
3161 32, 16, 44, 28, 35, 19, 47, 31,
3162 8, 56, 4, 52, 11, 59, 7, 55,
3163 40, 24, 36, 20, 43, 27, 39, 23,
3164 2, 50, 14, 62, 1, 49, 13, 61,
3165 34, 18, 46, 30, 33, 17, 45, 29,
3166 10, 58, 6, 54, 9, 57, 5, 53,
3167 42, 26, 38, 22, 41, 25, 37, 21
3168 };
3169
cristybb503372010-05-27 20:51:26 +00003170static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003171{
cristybb503372010-05-27 20:51:26 +00003172 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003173 index;
3174
3175 index=x+DitherMatrix[x & 0x07]-32L;
3176 if (index < 0L)
3177 return(0L);
cristybb503372010-05-27 20:51:26 +00003178 if (index >= (ssize_t) columns)
3179 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00003180 return(index);
3181}
3182
cristybb503372010-05-27 20:51:26 +00003183static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003184{
cristybb503372010-05-27 20:51:26 +00003185 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003186 index;
3187
3188 index=y+DitherMatrix[y & 0x07]-32L;
3189 if (index < 0L)
3190 return(0L);
cristybb503372010-05-27 20:51:26 +00003191 if (index >= (ssize_t) rows)
3192 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00003193 return(index);
3194}
3195
cristybb503372010-05-27 20:51:26 +00003196static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003197{
3198 if (x < 0L)
3199 return(0L);
cristybb503372010-05-27 20:51:26 +00003200 if (x >= (ssize_t) columns)
3201 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003202 return(x);
3203}
3204
cristybb503372010-05-27 20:51:26 +00003205static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003206{
3207 if (y < 0L)
3208 return(0L);
cristybb503372010-05-27 20:51:26 +00003209 if (y >= (ssize_t) rows)
3210 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003211 return(y);
3212}
3213
cristybb503372010-05-27 20:51:26 +00003214static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003215{
cristybb503372010-05-27 20:51:26 +00003216 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003217}
3218
cristybb503372010-05-27 20:51:26 +00003219static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003220{
cristybb503372010-05-27 20:51:26 +00003221 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003222}
3223
3224/*
3225 VirtualPixelModulo() computes the remainder of dividing offset by extent. It
3226 returns not only the quotient (tile the offset falls in) but also the positive
3227 remainer within that tile such that 0 <= remainder < extent. This method is
3228 essentially a ldiv() using a floored modulo division rather than the normal
3229 default truncated modulo division.
3230*/
cristybb503372010-05-27 20:51:26 +00003231static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3232 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003233{
3234 MagickModulo
3235 modulo;
3236
cristybb503372010-05-27 20:51:26 +00003237 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003238 if (offset < 0L)
3239 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003240 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003241 return(modulo);
3242}
3243
3244MagickExport const PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003245 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3246 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003247 ExceptionInfo *exception)
3248{
3249 CacheInfo
3250 *cache_info;
3251
cristyc3ec0d42010-04-07 01:18:08 +00003252 IndexPacket
3253 virtual_index;
3254
cristy3ed852e2009-09-05 21:47:34 +00003255 MagickOffsetType
3256 offset;
3257
3258 MagickSizeType
3259 length,
3260 number_pixels;
3261
3262 NexusInfo
3263 **virtual_nexus;
3264
3265 PixelPacket
3266 *pixels,
3267 virtual_pixel;
3268
3269 RectangleInfo
3270 region;
3271
3272 register const IndexPacket
cristyc3ec0d42010-04-07 01:18:08 +00003273 *restrict virtual_indexes;
cristy3ed852e2009-09-05 21:47:34 +00003274
3275 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003276 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003277
3278 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003279 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003280
cristye076a6e2010-08-15 19:59:43 +00003281 register PixelPacket
3282 *restrict q;
3283
cristybb503372010-05-27 20:51:26 +00003284 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003285 u,
3286 v;
3287
cristy3ed852e2009-09-05 21:47:34 +00003288 /*
3289 Acquire pixels.
3290 */
cristy3ed852e2009-09-05 21:47:34 +00003291 cache_info=(CacheInfo *) image->cache;
cristy4cfbb3f2010-03-14 20:40:23 +00003292 if (cache_info->type == UndefinedCache)
cristy3ed852e2009-09-05 21:47:34 +00003293 return((const PixelPacket *) NULL);
3294 region.x=x;
3295 region.y=y;
3296 region.width=columns;
3297 region.height=rows;
3298 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
3299 if (pixels == (PixelPacket *) NULL)
3300 return((const PixelPacket *) NULL);
cristydf415c82010-03-11 16:47:50 +00003301 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3302 nexus_info->region.x;
3303 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3304 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003305 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3306 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003307 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3308 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003309 {
3310 MagickBooleanType
3311 status;
3312
3313 /*
3314 Pixel request is inside cache extents.
3315 */
3316 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
3317 return(pixels);
3318 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3319 if (status == MagickFalse)
3320 return((const PixelPacket *) NULL);
3321 if ((cache_info->storage_class == PseudoClass) ||
3322 (cache_info->colorspace == CMYKColorspace))
3323 {
3324 status=ReadPixelCacheIndexes(cache_info,nexus_info,exception);
3325 if (status == MagickFalse)
3326 return((const PixelPacket *) NULL);
3327 }
3328 return(pixels);
3329 }
3330 /*
3331 Pixel request is outside cache extents.
3332 */
3333 q=pixels;
3334 indexes=GetPixelCacheNexusIndexes(cache_info,nexus_info);
3335 virtual_nexus=AcquirePixelCacheNexus(1);
3336 if (virtual_nexus == (NexusInfo **) NULL)
3337 {
3338 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3339 "UnableToGetCacheNexus","`%s'",image->filename);
3340 return((const PixelPacket *) NULL);
3341 }
3342 switch (virtual_pixel_method)
3343 {
3344 case BlackVirtualPixelMethod:
3345 {
cristy4789f0d2010-01-10 00:01:06 +00003346 SetRedPixelComponent(&virtual_pixel,0);
3347 SetGreenPixelComponent(&virtual_pixel,0);
3348 SetBluePixelComponent(&virtual_pixel,0);
3349 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003350 break;
3351 }
3352 case GrayVirtualPixelMethod:
3353 {
cristy4789f0d2010-01-10 00:01:06 +00003354 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3355 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3356 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3357 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003358 break;
3359 }
3360 case TransparentVirtualPixelMethod:
3361 {
cristy4789f0d2010-01-10 00:01:06 +00003362 SetRedPixelComponent(&virtual_pixel,0);
3363 SetGreenPixelComponent(&virtual_pixel,0);
3364 SetBluePixelComponent(&virtual_pixel,0);
3365 SetOpacityPixelComponent(&virtual_pixel,TransparentOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003366 break;
3367 }
3368 case MaskVirtualPixelMethod:
3369 case WhiteVirtualPixelMethod:
3370 {
cristy4789f0d2010-01-10 00:01:06 +00003371 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3372 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3373 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3374 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003375 break;
3376 }
3377 default:
3378 {
3379 virtual_pixel=image->background_color;
3380 break;
3381 }
3382 }
cristyc3ec0d42010-04-07 01:18:08 +00003383 virtual_index=0;
cristybb503372010-05-27 20:51:26 +00003384 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003385 {
cristybb503372010-05-27 20:51:26 +00003386 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003387 {
3388 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003389 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003390 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3391 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003392 {
3393 MagickModulo
3394 x_modulo,
3395 y_modulo;
3396
3397 /*
3398 Transfer a single pixel.
3399 */
3400 length=(MagickSizeType) 1;
3401 switch (virtual_pixel_method)
3402 {
3403 case BackgroundVirtualPixelMethod:
3404 case ConstantVirtualPixelMethod:
3405 case BlackVirtualPixelMethod:
3406 case GrayVirtualPixelMethod:
3407 case TransparentVirtualPixelMethod:
3408 case MaskVirtualPixelMethod:
3409 case WhiteVirtualPixelMethod:
3410 {
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 case EdgeVirtualPixelMethod:
3416 default:
3417 {
3418 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003419 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003420 1UL,1UL,virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003421 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3422 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003423 break;
3424 }
3425 case RandomVirtualPixelMethod:
3426 {
3427 if (cache_info->random_info == (RandomInfo *) NULL)
3428 cache_info->random_info=AcquireRandomInfo();
3429 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003430 RandomX(cache_info->random_info,cache_info->columns),
3431 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003432 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003433 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3434 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003435 break;
3436 }
3437 case DitherVirtualPixelMethod:
3438 {
3439 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003440 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003441 1UL,1UL,virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003442 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3443 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003444 break;
3445 }
3446 case TileVirtualPixelMethod:
3447 {
3448 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3449 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3450 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3451 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3452 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003453 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3454 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003455 break;
3456 }
3457 case MirrorVirtualPixelMethod:
3458 {
3459 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3460 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003461 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003462 x_modulo.remainder-1L;
3463 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3464 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003465 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003466 y_modulo.remainder-1L;
3467 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3468 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3469 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003470 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3471 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003472 break;
3473 }
3474 case CheckerTileVirtualPixelMethod:
3475 {
3476 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3477 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3478 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3479 {
3480 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003481 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003482 break;
3483 }
3484 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3485 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3486 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003487 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3488 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003489 break;
3490 }
3491 case HorizontalTileVirtualPixelMethod:
3492 {
cristybb503372010-05-27 20:51:26 +00003493 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003494 {
3495 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003496 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003497 break;
3498 }
3499 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3500 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3501 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3502 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3503 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003504 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3505 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003506 break;
3507 }
3508 case VerticalTileVirtualPixelMethod:
3509 {
cristybb503372010-05-27 20:51:26 +00003510 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
cristy3ed852e2009-09-05 21:47:34 +00003511 {
3512 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003513 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003514 break;
3515 }
3516 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3517 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3518 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3519 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3520 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003521 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3522 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003523 break;
3524 }
3525 case HorizontalTileEdgeVirtualPixelMethod:
3526 {
3527 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3528 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003529 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003530 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003531 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3532 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003533 break;
3534 }
3535 case VerticalTileEdgeVirtualPixelMethod:
3536 {
3537 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3538 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003539 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003540 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003541 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3542 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003543 break;
3544 }
3545 }
3546 if (p == (const PixelPacket *) NULL)
3547 break;
3548 *q++=(*p);
cristyc3ec0d42010-04-07 01:18:08 +00003549 if ((indexes != (IndexPacket *) NULL) &&
3550 (virtual_indexes != (const IndexPacket *) NULL))
3551 *indexes++=(*virtual_indexes);
cristy3ed852e2009-09-05 21:47:34 +00003552 continue;
3553 }
3554 /*
3555 Transfer a run of pixels.
3556 */
3557 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,
cristybb503372010-05-27 20:51:26 +00003558 (size_t) length,1UL,virtual_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003559 if (p == (const PixelPacket *) NULL)
3560 break;
cristyc3ec0d42010-04-07 01:18:08 +00003561 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003562 (void) CopyMagickMemory(q,p,(size_t) length*sizeof(*p));
3563 q+=length;
cristyc3ec0d42010-04-07 01:18:08 +00003564 if ((indexes != (IndexPacket *) NULL) &&
3565 (virtual_indexes != (const IndexPacket *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003566 {
cristyc3ec0d42010-04-07 01:18:08 +00003567 (void) CopyMagickMemory(indexes,virtual_indexes,(size_t) length*
3568 sizeof(*virtual_indexes));
3569 indexes+=length;
cristy3ed852e2009-09-05 21:47:34 +00003570 }
3571 }
3572 }
3573 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3574 return(pixels);
3575}
3576
3577/*
3578%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3579% %
3580% %
3581% %
3582+ G e t V i r t u a l P i x e l C a c h e %
3583% %
3584% %
3585% %
3586%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3587%
3588% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3589% cache as defined by the geometry parameters. A pointer to the pixels
3590% is returned if the pixels are transferred, otherwise a NULL is returned.
3591%
3592% The format of the GetVirtualPixelCache() method is:
3593%
3594% const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003595% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3596% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003597% ExceptionInfo *exception)
3598%
3599% A description of each parameter follows:
3600%
3601% o image: the image.
3602%
3603% o virtual_pixel_method: the virtual pixel method.
3604%
3605% o x,y,columns,rows: These values define the perimeter of a region of
3606% pixels.
3607%
3608% o exception: return any errors or warnings in this structure.
3609%
3610*/
3611static const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003612 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3613 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003614{
3615 CacheInfo
3616 *cache_info;
3617
3618 const PixelPacket
3619 *pixels;
3620
cristy6ebe97c2010-07-03 01:17:28 +00003621 int
cristy3ed852e2009-09-05 21:47:34 +00003622 id;
3623
cristy3ed852e2009-09-05 21:47:34 +00003624 cache_info=(CacheInfo *) image->cache;
3625 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00003626 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00003627 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3628 cache_info->nexus_info[id],exception);
3629 return(pixels);
3630}
3631
3632/*
3633%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3634% %
3635% %
3636% %
3637% G e t V i r t u a l P i x e l Q u e u e %
3638% %
3639% %
3640% %
3641%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3642%
3643% GetVirtualPixelQueue() returns the virtual pixels associated with the
3644% last call to QueueAuthenticPixels() or GetVirtualPixels().
3645%
3646% The format of the GetVirtualPixelQueue() method is:
3647%
3648% const PixelPacket *GetVirtualPixelQueue(const Image image)
3649%
3650% A description of each parameter follows:
3651%
3652% o image: the image.
3653%
3654*/
3655MagickExport const PixelPacket *GetVirtualPixelQueue(const Image *image)
3656{
3657 CacheInfo
3658 *cache_info;
3659
3660 assert(image != (const Image *) NULL);
3661 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003662 assert(image->cache != (Cache) NULL);
3663 cache_info=(CacheInfo *) image->cache;
3664 assert(cache_info->signature == MagickSignature);
3665 if (cache_info->methods.get_virtual_pixels_handler ==
3666 (GetVirtualPixelsHandler) NULL)
3667 return((PixelPacket *) NULL);
3668 return(cache_info->methods.get_virtual_pixels_handler(image));
3669}
3670
3671/*
3672%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3673% %
3674% %
3675% %
3676% G e t V i r t u a l P i x e l s %
3677% %
3678% %
3679% %
3680%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3681%
3682% GetVirtualPixels() returns an immutable pixel region. If the
3683% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003684% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003685% copy of the pixels or it may point to the original pixels in memory.
3686% Performance is maximized if the selected region is part of one row, or one
3687% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003688% (without a copy) if the image is in memory, or in a memory-mapped file. The
3689% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003690%
3691% Pixels accessed via the returned pointer represent a simple array of type
3692% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
3693% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to access
3694% the black color component or to obtain the colormap indexes (of type
3695% IndexPacket) corresponding to the region.
3696%
3697% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3698%
3699% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3700% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3701% GetCacheViewAuthenticPixels() instead.
3702%
3703% The format of the GetVirtualPixels() method is:
3704%
cristybb503372010-05-27 20:51:26 +00003705% const PixelPacket *GetVirtualPixels(const Image *image,const ssize_t x,
3706% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003707% ExceptionInfo *exception)
3708%
3709% A description of each parameter follows:
3710%
3711% o image: the image.
3712%
3713% o x,y,columns,rows: These values define the perimeter of a region of
3714% pixels.
3715%
3716% o exception: return any errors or warnings in this structure.
3717%
3718*/
3719MagickExport const PixelPacket *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003720 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3721 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003722{
3723 CacheInfo
3724 *cache_info;
3725
3726 const PixelPacket
3727 *pixels;
3728
3729 assert(image != (const Image *) NULL);
3730 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003731 assert(image->cache != (Cache) NULL);
3732 cache_info=(CacheInfo *) image->cache;
3733 assert(cache_info->signature == MagickSignature);
3734 if (cache_info->methods.get_virtual_pixel_handler ==
3735 (GetVirtualPixelHandler) NULL)
3736 return((const PixelPacket *) NULL);
3737 pixels=cache_info->methods.get_virtual_pixel_handler(image,
3738 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception);
3739 return(pixels);
3740}
3741
3742/*
3743%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3744% %
3745% %
3746% %
3747+ 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 %
3748% %
3749% %
3750% %
3751%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3752%
3753% GetVirtualPixelsCache() returns the pixels associated with the last call
3754% to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3755%
3756% The format of the GetVirtualPixelsCache() method is:
3757%
3758% PixelPacket *GetVirtualPixelsCache(const Image *image)
3759%
3760% A description of each parameter follows:
3761%
3762% o image: the image.
3763%
3764*/
3765static const PixelPacket *GetVirtualPixelsCache(const Image *image)
3766{
3767 CacheInfo
3768 *cache_info;
3769
3770 const PixelPacket
3771 *pixels;
3772
cristy6ebe97c2010-07-03 01:17:28 +00003773 int
cristy3ed852e2009-09-05 21:47:34 +00003774 id;
3775
cristy3ed852e2009-09-05 21:47:34 +00003776 cache_info=(CacheInfo *) image->cache;
3777 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00003778 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00003779 pixels=GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]);
3780 return(pixels);
3781}
3782
3783/*
3784%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3785% %
3786% %
3787% %
3788+ G e t V i r t u a l P i x e l s N e x u s %
3789% %
3790% %
3791% %
3792%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3793%
3794% GetVirtualPixelsNexus() returns the pixels associated with the specified
3795% cache nexus.
3796%
3797% The format of the GetVirtualPixelsNexus() method is:
3798%
3799% const IndexPacket *GetVirtualPixelsNexus(const Cache cache,
3800% NexusInfo *nexus_info)
3801%
3802% A description of each parameter follows:
3803%
3804% o cache: the pixel cache.
3805%
3806% o nexus_info: the cache nexus to return the colormap pixels.
3807%
3808*/
3809MagickExport const PixelPacket *GetVirtualPixelsNexus(const Cache cache,
3810 NexusInfo *nexus_info)
3811{
3812 CacheInfo
3813 *cache_info;
3814
3815 if (cache == (Cache) NULL)
3816 return((PixelPacket *) NULL);
3817 cache_info=(CacheInfo *) cache;
3818 assert(cache_info->signature == MagickSignature);
3819 if (cache_info->storage_class == UndefinedClass)
3820 return((PixelPacket *) NULL);
3821 return((const PixelPacket *) nexus_info->pixels);
3822}
3823
3824/*
3825%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3826% %
3827% %
3828% %
3829+ M a s k P i x e l C a c h e N e x u s %
3830% %
3831% %
3832% %
3833%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3834%
3835% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3836% The method returns MagickTrue if the pixel region is masked, otherwise
3837% MagickFalse.
3838%
3839% The format of the MaskPixelCacheNexus() method is:
3840%
3841% MagickBooleanType MaskPixelCacheNexus(Image *image,
3842% NexusInfo *nexus_info,ExceptionInfo *exception)
3843%
3844% A description of each parameter follows:
3845%
3846% o image: the image.
3847%
3848% o nexus_info: the cache nexus to clip.
3849%
3850% o exception: return any errors or warnings in this structure.
3851%
3852*/
3853
3854static inline void MagickPixelCompositeMask(const MagickPixelPacket *p,
3855 const MagickRealType alpha,const MagickPixelPacket *q,
3856 const MagickRealType beta,MagickPixelPacket *composite)
3857{
3858 MagickRealType
3859 gamma;
3860
3861 if (alpha == TransparentOpacity)
3862 {
3863 *composite=(*q);
3864 return;
3865 }
3866 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3867 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3868 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3869 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3870 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3871 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3872 composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
3873}
3874
3875static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3876 ExceptionInfo *exception)
3877{
3878 CacheInfo
3879 *cache_info;
3880
3881 MagickPixelPacket
3882 alpha,
3883 beta;
3884
3885 MagickSizeType
3886 number_pixels;
3887
3888 NexusInfo
3889 **clip_nexus,
3890 **image_nexus;
3891
3892 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003893 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003894
3895 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003896 *restrict nexus_indexes,
3897 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003898
cristy3ed852e2009-09-05 21:47:34 +00003899 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003900 *restrict p,
3901 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003902
cristye076a6e2010-08-15 19:59:43 +00003903 register ssize_t
3904 i;
3905
cristy3ed852e2009-09-05 21:47:34 +00003906 /*
3907 Apply clip mask.
3908 */
3909 if (image->debug != MagickFalse)
3910 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3911 if (image->mask == (Image *) NULL)
3912 return(MagickFalse);
3913 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
3914 if (cache_info == (Cache) NULL)
3915 return(MagickFalse);
3916 image_nexus=AcquirePixelCacheNexus(1);
3917 clip_nexus=AcquirePixelCacheNexus(1);
3918 if ((image_nexus == (NexusInfo **) NULL) ||
3919 (clip_nexus == (NexusInfo **) NULL))
3920 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy09449f72010-01-23 03:08:36 +00003921 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,
3922 nexus_info->region.y,nexus_info->region.width,nexus_info->region.height,
3923 image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003924 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
3925 q=nexus_info->pixels;
3926 nexus_indexes=nexus_info->indexes;
3927 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3928 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3929 nexus_info->region.height,clip_nexus[0],&image->exception);
3930 GetMagickPixelPacket(image,&alpha);
3931 GetMagickPixelPacket(image,&beta);
3932 number_pixels=(MagickSizeType) nexus_info->region.width*
3933 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +00003934 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +00003935 {
3936 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
3937 break;
3938 SetMagickPixelPacket(image,p,indexes+i,&alpha);
3939 SetMagickPixelPacket(image,q,nexus_indexes+i,&beta);
3940 MagickPixelCompositeMask(&beta,(MagickRealType) PixelIntensityToQuantum(r),
3941 &alpha,alpha.opacity,&beta);
cristyce70c172010-01-07 17:15:30 +00003942 q->red=ClampToQuantum(beta.red);
3943 q->green=ClampToQuantum(beta.green);
3944 q->blue=ClampToQuantum(beta.blue);
3945 q->opacity=ClampToQuantum(beta.opacity);
cristy3ed852e2009-09-05 21:47:34 +00003946 if (cache_info->active_index_channel != MagickFalse)
3947 nexus_indexes[i]=indexes[i];
3948 p++;
3949 q++;
3950 r++;
3951 }
3952 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3953 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +00003954 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003955 return(MagickFalse);
3956 return(MagickTrue);
3957}
3958
3959/*
3960%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3961% %
3962% %
3963% %
3964+ O p e n P i x e l C a c h e %
3965% %
3966% %
3967% %
3968%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3969%
3970% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3971% dimensions, allocating space for the image pixels and optionally the
3972% colormap indexes, and memory mapping the cache if it is disk based. The
3973% cache nexus array is initialized as well.
3974%
3975% The format of the OpenPixelCache() method is:
3976%
3977% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3978% ExceptionInfo *exception)
3979%
3980% A description of each parameter follows:
3981%
3982% o image: the image.
3983%
3984% o mode: ReadMode, WriteMode, or IOMode.
3985%
3986% o exception: return any errors or warnings in this structure.
3987%
3988*/
3989
cristyd43a46b2010-01-21 02:13:41 +00003990static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003991{
3992 cache_info->mapped=MagickFalse;
3993 cache_info->pixels=(PixelPacket *) AcquireMagickMemory((size_t)
3994 cache_info->length);
3995 if (cache_info->pixels == (PixelPacket *) NULL)
3996 {
3997 cache_info->mapped=MagickTrue;
3998 cache_info->pixels=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
3999 cache_info->length);
4000 }
4001}
4002
4003static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
4004{
4005 CacheInfo
4006 *cache_info;
4007
4008 MagickOffsetType
4009 count,
4010 extent,
4011 offset;
4012
4013 cache_info=(CacheInfo *) image->cache;
4014 if (image->debug != MagickFalse)
4015 {
4016 char
4017 format[MaxTextExtent],
4018 message[MaxTextExtent];
4019
cristyb9080c92009-12-01 20:13:26 +00004020 (void) FormatMagickSize(length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00004021 (void) FormatMagickString(message,MaxTextExtent,
cristy2ce15c92010-03-12 14:03:41 +00004022 "extend %s (%s[%d], disk, %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00004023 cache_info->cache_filename,cache_info->file,format);
4024 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4025 }
4026 if (length != (MagickSizeType) ((MagickOffsetType) length))
4027 return(MagickFalse);
4028 extent=(MagickOffsetType) MagickSeek(cache_info->file,0,SEEK_END);
4029 if (extent < 0)
4030 return(MagickFalse);
4031 if ((MagickSizeType) extent >= length)
4032 return(MagickTrue);
4033 offset=(MagickOffsetType) length-1;
4034 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
4035 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
4036}
4037
4038static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
4039 ExceptionInfo *exception)
4040{
4041 char
4042 format[MaxTextExtent],
4043 message[MaxTextExtent];
4044
4045 CacheInfo
4046 *cache_info,
4047 source_info;
4048
4049 MagickSizeType
4050 length,
4051 number_pixels;
4052
4053 MagickStatusType
4054 status;
4055
4056 size_t
cristye076a6e2010-08-15 19:59:43 +00004057 columns,
cristy3ed852e2009-09-05 21:47:34 +00004058 packet_size;
4059
cristy3ed852e2009-09-05 21:47:34 +00004060 if (image->debug != MagickFalse)
4061 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4062 if ((image->columns == 0) || (image->rows == 0))
4063 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
4064 cache_info=(CacheInfo *) image->cache;
4065 source_info=(*cache_info);
4066 source_info.file=(-1);
cristye8c25f92010-06-03 00:53:06 +00004067 (void) FormatMagickString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
4068 image->filename,(double) GetImageIndexInList(image));
cristy87528ea2009-09-10 14:53:56 +00004069 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +00004070 cache_info->rows=image->rows;
4071 cache_info->columns=image->columns;
4072 cache_info->active_index_channel=((image->storage_class == PseudoClass) ||
4073 (image->colorspace == CMYKColorspace)) ? MagickTrue : MagickFalse;
cristy73724512010-04-12 14:43:14 +00004074 if (image->ping != MagickFalse)
4075 {
4076 cache_info->storage_class=image->storage_class;
4077 cache_info->colorspace=image->colorspace;
4078 cache_info->type=PingCache;
4079 cache_info->pixels=(PixelPacket *) NULL;
4080 cache_info->indexes=(IndexPacket *) NULL;
4081 cache_info->length=0;
4082 return(MagickTrue);
4083 }
cristy3ed852e2009-09-05 21:47:34 +00004084 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4085 packet_size=sizeof(PixelPacket);
4086 if (cache_info->active_index_channel != MagickFalse)
4087 packet_size+=sizeof(IndexPacket);
4088 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00004089 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00004090 if (cache_info->columns != columns)
4091 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4092 image->filename);
4093 cache_info->length=length;
4094 status=AcquireMagickResource(AreaResource,cache_info->length);
4095 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4096 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4097 {
4098 status=AcquireMagickResource(MemoryResource,cache_info->length);
4099 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4100 (cache_info->type == MemoryCache))
4101 {
cristyd43a46b2010-01-21 02:13:41 +00004102 AllocatePixelCachePixels(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004103 if (cache_info->pixels == (PixelPacket *) NULL)
4104 cache_info->pixels=source_info.pixels;
4105 else
4106 {
4107 /*
4108 Create memory pixel cache.
4109 */
4110 if (image->debug != MagickFalse)
4111 {
cristy97e7a572009-12-05 15:07:53 +00004112 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004113 format);
cristy3ed852e2009-09-05 21:47:34 +00004114 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004115 "open %s (%s memory, %.20gx%.20g %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00004116 cache_info->mapped != MagickFalse ? "anonymous" : "heap",
cristye8c25f92010-06-03 00:53:06 +00004117 (double) cache_info->columns,(double) cache_info->rows,
4118 format);
cristy3ed852e2009-09-05 21:47:34 +00004119 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4120 message);
4121 }
4122 cache_info->storage_class=image->storage_class;
4123 cache_info->colorspace=image->colorspace;
4124 cache_info->type=MemoryCache;
4125 cache_info->indexes=(IndexPacket *) NULL;
4126 if (cache_info->active_index_channel != MagickFalse)
4127 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4128 number_pixels);
4129 if (source_info.storage_class != UndefinedClass)
4130 {
4131 status|=ClonePixelCachePixels(cache_info,&source_info,
4132 exception);
4133 RelinquishPixelCachePixels(&source_info);
4134 }
4135 return(MagickTrue);
4136 }
4137 }
4138 RelinquishMagickResource(MemoryResource,cache_info->length);
4139 }
4140 /*
4141 Create pixel cache on disk.
4142 */
4143 status=AcquireMagickResource(DiskResource,cache_info->length);
4144 if (status == MagickFalse)
4145 {
4146 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4147 "CacheResourcesExhausted","`%s'",image->filename);
4148 return(MagickFalse);
4149 }
4150 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4151 {
4152 RelinquishMagickResource(DiskResource,cache_info->length);
4153 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4154 image->filename);
4155 return(MagickFalse);
4156 }
4157 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4158 cache_info->length);
4159 if (status == MagickFalse)
4160 {
4161 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4162 image->filename);
4163 return(MagickFalse);
4164 }
4165 cache_info->storage_class=image->storage_class;
4166 cache_info->colorspace=image->colorspace;
4167 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4168 status=AcquireMagickResource(AreaResource,cache_info->length);
4169 if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4170 cache_info->type=DiskCache;
4171 else
4172 {
4173 status=AcquireMagickResource(MapResource,cache_info->length);
4174 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4175 (cache_info->type != MemoryCache))
4176 cache_info->type=DiskCache;
4177 else
4178 {
4179 cache_info->pixels=(PixelPacket *) MapBlob(cache_info->file,mode,
4180 cache_info->offset,(size_t) cache_info->length);
4181 if (cache_info->pixels == (PixelPacket *) NULL)
4182 {
4183 cache_info->pixels=source_info.pixels;
4184 cache_info->type=DiskCache;
4185 }
4186 else
4187 {
4188 /*
4189 Create file-backed memory-mapped pixel cache.
4190 */
4191 (void) ClosePixelCacheOnDisk(cache_info);
4192 cache_info->type=MapCache;
4193 cache_info->mapped=MagickTrue;
4194 cache_info->indexes=(IndexPacket *) NULL;
4195 if (cache_info->active_index_channel != MagickFalse)
4196 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4197 number_pixels);
4198 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4199 {
4200 status=ClonePixelCachePixels(cache_info,&source_info,
4201 exception);
4202 RelinquishPixelCachePixels(&source_info);
4203 }
4204 if (image->debug != MagickFalse)
4205 {
cristy97e7a572009-12-05 15:07:53 +00004206 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004207 format);
cristy3ed852e2009-09-05 21:47:34 +00004208 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004209 "open %s (%s[%d], memory-mapped, %.20gx%.20g %sB)",
cristy3ed852e2009-09-05 21:47:34 +00004210 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004211 cache_info->file,(double) cache_info->columns,(double)
4212 cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004213 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4214 message);
4215 }
4216 return(MagickTrue);
4217 }
4218 }
4219 RelinquishMagickResource(MapResource,cache_info->length);
4220 }
4221 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4222 {
4223 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4224 RelinquishPixelCachePixels(&source_info);
4225 }
4226 if (image->debug != MagickFalse)
4227 {
cristyb9080c92009-12-01 20:13:26 +00004228 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00004229 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004230 "open %s (%s[%d], disk, %.20gx%.20g %sB)",cache_info->filename,
4231 cache_info->cache_filename,cache_info->file,(double)
4232 cache_info->columns,(double) cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004233 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4234 }
4235 return(MagickTrue);
4236}
4237
4238/*
4239%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4240% %
4241% %
4242% %
4243+ P e r s i s t P i x e l C a c h e %
4244% %
4245% %
4246% %
4247%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4248%
4249% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4250% persistent pixel cache is one that resides on disk and is not destroyed
4251% when the program exits.
4252%
4253% The format of the PersistPixelCache() method is:
4254%
4255% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4256% const MagickBooleanType attach,MagickOffsetType *offset,
4257% ExceptionInfo *exception)
4258%
4259% A description of each parameter follows:
4260%
4261% o image: the image.
4262%
4263% o filename: the persistent pixel cache filename.
4264%
cristy01b7eb02009-09-10 23:10:14 +00004265% o attach: A value other than zero initializes the persistent pixel
4266% cache.
4267%
cristy3ed852e2009-09-05 21:47:34 +00004268% o initialize: A value other than zero initializes the persistent pixel
4269% cache.
4270%
4271% o offset: the offset in the persistent cache to store pixels.
4272%
4273% o exception: return any errors or warnings in this structure.
4274%
4275*/
4276MagickExport MagickBooleanType PersistPixelCache(Image *image,
4277 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4278 ExceptionInfo *exception)
4279{
4280 CacheInfo
4281 *cache_info,
4282 *clone_info;
4283
4284 Image
4285 clone_image;
4286
cristy3ed852e2009-09-05 21:47:34 +00004287 MagickBooleanType
4288 status;
4289
cristye076a6e2010-08-15 19:59:43 +00004290 ssize_t
4291 page_size;
4292
cristy3ed852e2009-09-05 21:47:34 +00004293 assert(image != (Image *) NULL);
4294 assert(image->signature == MagickSignature);
4295 if (image->debug != MagickFalse)
4296 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4297 assert(image->cache != (void *) NULL);
4298 assert(filename != (const char *) NULL);
4299 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004300 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004301 cache_info=(CacheInfo *) image->cache;
4302 assert(cache_info->signature == MagickSignature);
4303 if (attach != MagickFalse)
4304 {
4305 /*
cristy01b7eb02009-09-10 23:10:14 +00004306 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004307 */
4308 if (image->debug != MagickFalse)
4309 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4310 "attach persistent cache");
4311 (void) CopyMagickString(cache_info->cache_filename,filename,
4312 MaxTextExtent);
4313 cache_info->type=DiskCache;
4314 cache_info->offset=(*offset);
4315 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4316 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004317 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004318 return(MagickTrue);
4319 }
cristy01b7eb02009-09-10 23:10:14 +00004320 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4321 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004322 {
cristyf84a1932010-01-03 18:00:18 +00004323 LockSemaphoreInfo(cache_info->semaphore);
cristy09449f72010-01-23 03:08:36 +00004324 if ((cache_info->mode != ReadMode) &&
4325 (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004326 (cache_info->reference_count == 1))
4327 {
4328 int
4329 status;
4330
4331 /*
cristy01b7eb02009-09-10 23:10:14 +00004332 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004333 */
4334 status=rename(cache_info->cache_filename,filename);
4335 if (status == 0)
4336 {
4337 (void) CopyMagickString(cache_info->cache_filename,filename,
4338 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004339 *offset+=cache_info->length+page_size-(cache_info->length %
4340 page_size);
cristyf84a1932010-01-03 18:00:18 +00004341 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004342 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004343 if (image->debug != MagickFalse)
4344 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4345 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004346 return(MagickTrue);
4347 }
4348 }
cristyf84a1932010-01-03 18:00:18 +00004349 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004350 }
4351 /*
cristy01b7eb02009-09-10 23:10:14 +00004352 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004353 */
4354 clone_image=(*image);
4355 clone_info=(CacheInfo *) clone_image.cache;
4356 image->cache=ClonePixelCache(cache_info);
4357 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4358 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4359 cache_info->type=DiskCache;
4360 cache_info->offset=(*offset);
4361 cache_info=(CacheInfo *) image->cache;
4362 status=ClonePixelCacheNexus(cache_info,clone_info,exception);
4363 if (status != MagickFalse)
4364 {
4365 status=OpenPixelCache(image,IOMode,exception);
4366 if (status != MagickFalse)
4367 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
4368 }
cristy688f07b2009-09-27 15:19:13 +00004369 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004370 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4371 return(status);
4372}
4373
4374/*
4375%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4376% %
4377% %
4378% %
4379+ Q u e u e A u t h e n t i c N e x u s %
4380% %
4381% %
4382% %
4383%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4384%
4385% QueueAuthenticNexus() allocates an region to store image pixels as defined
4386% by the region rectangle and returns a pointer to the region. This region is
4387% subsequently transferred from the pixel cache with
4388% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4389% pixels are transferred, otherwise a NULL is returned.
4390%
4391% The format of the QueueAuthenticNexus() method is:
4392%
cristy5f959472010-05-27 22:19:46 +00004393% PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
4394% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004395% NexusInfo *nexus_info,ExceptionInfo *exception)
4396%
4397% A description of each parameter follows:
4398%
4399% o image: the image.
4400%
4401% o x,y,columns,rows: These values define the perimeter of a region of
4402% pixels.
4403%
4404% o nexus_info: the cache nexus to set.
4405%
4406% o exception: return any errors or warnings in this structure.
4407%
4408*/
cristybb503372010-05-27 20:51:26 +00004409MagickExport PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy30097232010-07-01 02:16:30 +00004410 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
4411 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004412{
4413 CacheInfo
4414 *cache_info;
4415
4416 MagickOffsetType
4417 offset;
4418
4419 MagickSizeType
4420 number_pixels;
4421
4422 RectangleInfo
4423 region;
4424
4425 /*
4426 Validate pixel cache geometry.
4427 */
4428 cache_info=(CacheInfo *) image->cache;
4429 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4430 {
4431 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4432 "NoPixelsDefinedInCache","`%s'",image->filename);
4433 return((PixelPacket *) NULL);
4434 }
cristybb503372010-05-27 20:51:26 +00004435 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4436 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004437 {
4438 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4439 "PixelsAreNotAuthentic","`%s'",image->filename);
4440 return((PixelPacket *) NULL);
4441 }
4442 offset=(MagickOffsetType) y*cache_info->columns+x;
4443 if (offset < 0)
4444 return((PixelPacket *) NULL);
4445 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4446 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4447 if ((MagickSizeType) offset >= number_pixels)
4448 return((PixelPacket *) NULL);
4449 /*
4450 Return pixel cache.
4451 */
4452 region.x=x;
4453 region.y=y;
4454 region.width=columns;
4455 region.height=rows;
4456 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4457}
4458
4459/*
4460%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4461% %
4462% %
4463% %
4464+ 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 %
4465% %
4466% %
4467% %
4468%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4469%
4470% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4471% defined by the region rectangle and returns a pointer to the region. This
4472% region is subsequently transferred from the pixel cache with
4473% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4474% pixels are transferred, otherwise a NULL is returned.
4475%
4476% The format of the QueueAuthenticPixelsCache() method is:
4477%
cristybb503372010-05-27 20:51:26 +00004478% PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4479% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004480% ExceptionInfo *exception)
4481%
4482% A description of each parameter follows:
4483%
4484% o image: the image.
4485%
4486% o x,y,columns,rows: These values define the perimeter of a region of
4487% pixels.
4488%
4489% o exception: return any errors or warnings in this structure.
4490%
4491*/
cristybb503372010-05-27 20:51:26 +00004492static PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4493 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004494 ExceptionInfo *exception)
4495{
4496 CacheInfo
4497 *cache_info;
4498
cristy6ebe97c2010-07-03 01:17:28 +00004499 int
cristy3ed852e2009-09-05 21:47:34 +00004500 id;
4501
4502 PixelPacket
4503 *pixels;
4504
4505 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickFalse,exception);
4506 if (cache_info == (Cache) NULL)
4507 return((PixelPacket *) NULL);
4508 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00004509 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00004510 pixels=QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4511 exception);
4512 return(pixels);
4513}
4514
4515/*
4516%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4517% %
4518% %
4519% %
4520% Q u e u e A u t h e n t i c P i x e l s %
4521% %
4522% %
4523% %
4524%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4525%
4526% QueueAuthenticPixels() queues a mutable pixel region. If the region is
4527% successfully intialized a pointer to a PixelPacket array representing the
4528% region is returned, otherwise NULL is returned. The returned pointer may
4529% point to a temporary working buffer for the pixels or it may point to the
4530% final location of the pixels in memory.
4531%
4532% Write-only access means that any existing pixel values corresponding to
4533% the region are ignored. This is useful if the initial image is being
4534% created from scratch, or if the existing pixel values are to be
4535% completely replaced without need to refer to their pre-existing values.
4536% The application is free to read and write the pixel buffer returned by
4537% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4538% initialize the pixel array values. Initializing pixel array values is the
4539% application's responsibility.
4540%
4541% Performance is maximized if the selected region is part of one row, or
4542% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004543% pixels in-place (without a copy) if the image is in memory, or in a
4544% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004545% by the user.
4546%
4547% Pixels accessed via the returned pointer represent a simple array of type
4548% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
4549% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
4550% the black color component or the colormap indexes (of type IndexPacket)
4551% corresponding to the region. Once the PixelPacket (and/or IndexPacket)
4552% array has been updated, the changes must be saved back to the underlying
4553% image using SyncAuthenticPixels() or they may be lost.
4554%
4555% The format of the QueueAuthenticPixels() method is:
4556%
cristy5f959472010-05-27 22:19:46 +00004557% PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4558% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004559% ExceptionInfo *exception)
4560%
4561% A description of each parameter follows:
4562%
4563% o image: the image.
4564%
4565% o x,y,columns,rows: These values define the perimeter of a region of
4566% pixels.
4567%
4568% o exception: return any errors or warnings in this structure.
4569%
4570*/
cristybb503372010-05-27 20:51:26 +00004571MagickExport PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4572 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004573 ExceptionInfo *exception)
4574{
4575 CacheInfo
4576 *cache_info;
4577
4578 PixelPacket
4579 *pixels;
4580
4581 assert(image != (Image *) NULL);
4582 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004583 assert(image->cache != (Cache) NULL);
4584 cache_info=(CacheInfo *) image->cache;
4585 assert(cache_info->signature == MagickSignature);
4586 if (cache_info->methods.queue_authentic_pixels_handler ==
4587 (QueueAuthenticPixelsHandler) NULL)
4588 return((PixelPacket *) NULL);
4589 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4590 rows,exception);
4591 return(pixels);
4592}
4593
4594/*
4595%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4596% %
4597% %
4598% %
4599+ R e a d P i x e l C a c h e I n d e x e s %
4600% %
4601% %
4602% %
4603%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4604%
4605% ReadPixelCacheIndexes() reads colormap indexes from the specified region of
4606% the pixel cache.
4607%
4608% The format of the ReadPixelCacheIndexes() method is:
4609%
4610% MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4611% NexusInfo *nexus_info,ExceptionInfo *exception)
4612%
4613% A description of each parameter follows:
4614%
4615% o cache_info: the pixel cache.
4616%
4617% o nexus_info: the cache nexus to read the colormap indexes.
4618%
4619% o exception: return any errors or warnings in this structure.
4620%
4621*/
4622static MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4623 NexusInfo *nexus_info,ExceptionInfo *exception)
4624{
4625 MagickOffsetType
4626 count,
4627 offset;
4628
4629 MagickSizeType
4630 length,
4631 number_pixels;
4632
4633 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004634 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004635
cristybb503372010-05-27 20:51:26 +00004636 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004637 y;
4638
cristybb503372010-05-27 20:51:26 +00004639 size_t
cristy3ed852e2009-09-05 21:47:34 +00004640 rows;
4641
cristy3ed852e2009-09-05 21:47:34 +00004642 if (cache_info->active_index_channel == MagickFalse)
4643 return(MagickFalse);
4644 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4645 return(MagickTrue);
4646 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4647 nexus_info->region.x;
4648 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
4649 rows=nexus_info->region.height;
4650 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004651 q=nexus_info->indexes;
4652 switch (cache_info->type)
4653 {
4654 case MemoryCache:
4655 case MapCache:
4656 {
4657 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004658 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004659
4660 /*
4661 Read indexes from memory.
4662 */
cristydd341db2010-03-04 19:06:38 +00004663 if ((cache_info->columns == nexus_info->region.width) &&
4664 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4665 {
4666 length=number_pixels;
4667 rows=1UL;
4668 }
cristy3ed852e2009-09-05 21:47:34 +00004669 p=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00004670 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004671 {
4672 (void) CopyMagickMemory(q,p,(size_t) length);
4673 p+=cache_info->columns;
4674 q+=nexus_info->region.width;
4675 }
4676 break;
4677 }
4678 case DiskCache:
4679 {
4680 /*
4681 Read indexes from disk.
4682 */
4683 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4684 {
4685 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4686 cache_info->cache_filename);
4687 return(MagickFalse);
4688 }
cristydd341db2010-03-04 19:06:38 +00004689 if ((cache_info->columns == nexus_info->region.width) &&
4690 (number_pixels < MagickMaxBufferExtent))
4691 {
4692 length=number_pixels;
4693 rows=1UL;
4694 }
cristy3ed852e2009-09-05 21:47:34 +00004695 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004696 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004697 {
4698 count=ReadPixelCacheRegion(cache_info,cache_info->offset+number_pixels*
4699 sizeof(PixelPacket)+offset*sizeof(*q),length,(unsigned char *) q);
4700 if ((MagickSizeType) count < length)
4701 break;
4702 offset+=cache_info->columns;
4703 q+=nexus_info->region.width;
4704 }
cristybb503372010-05-27 20:51:26 +00004705 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004706 {
4707 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4708 cache_info->cache_filename);
4709 return(MagickFalse);
4710 }
4711 break;
4712 }
4713 default:
4714 break;
4715 }
4716 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004717 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004718 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004719 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004720 nexus_info->region.width,(double) nexus_info->region.height,(double)
4721 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004722 return(MagickTrue);
4723}
4724
4725/*
4726%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4727% %
4728% %
4729% %
4730+ R e a d P i x e l C a c h e P i x e l s %
4731% %
4732% %
4733% %
4734%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4735%
4736% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4737% cache.
4738%
4739% The format of the ReadPixelCachePixels() method is:
4740%
4741% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4742% NexusInfo *nexus_info,ExceptionInfo *exception)
4743%
4744% A description of each parameter follows:
4745%
4746% o cache_info: the pixel cache.
4747%
4748% o nexus_info: the cache nexus to read the pixels.
4749%
4750% o exception: return any errors or warnings in this structure.
4751%
4752*/
4753static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4754 NexusInfo *nexus_info,ExceptionInfo *exception)
4755{
4756 MagickOffsetType
4757 count,
4758 offset;
4759
4760 MagickSizeType
4761 length,
4762 number_pixels;
4763
cristy3ed852e2009-09-05 21:47:34 +00004764 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004765 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004766
cristye076a6e2010-08-15 19:59:43 +00004767 register ssize_t
4768 y;
4769
cristybb503372010-05-27 20:51:26 +00004770 size_t
cristy3ed852e2009-09-05 21:47:34 +00004771 rows;
4772
cristy3ed852e2009-09-05 21:47:34 +00004773 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4774 return(MagickTrue);
4775 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4776 nexus_info->region.x;
4777 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
4778 rows=nexus_info->region.height;
4779 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004780 q=nexus_info->pixels;
4781 switch (cache_info->type)
4782 {
4783 case MemoryCache:
4784 case MapCache:
4785 {
4786 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004787 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004788
4789 /*
4790 Read pixels from memory.
4791 */
cristydd341db2010-03-04 19:06:38 +00004792 if ((cache_info->columns == nexus_info->region.width) &&
4793 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4794 {
4795 length=number_pixels;
4796 rows=1UL;
4797 }
cristy3ed852e2009-09-05 21:47:34 +00004798 p=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00004799 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004800 {
4801 (void) CopyMagickMemory(q,p,(size_t) length);
4802 p+=cache_info->columns;
4803 q+=nexus_info->region.width;
4804 }
4805 break;
4806 }
4807 case DiskCache:
4808 {
4809 /*
4810 Read pixels from disk.
4811 */
4812 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4813 {
4814 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4815 cache_info->cache_filename);
4816 return(MagickFalse);
4817 }
cristydd341db2010-03-04 19:06:38 +00004818 if ((cache_info->columns == nexus_info->region.width) &&
4819 (number_pixels < MagickMaxBufferExtent))
4820 {
4821 length=number_pixels;
4822 rows=1UL;
4823 }
cristybb503372010-05-27 20:51:26 +00004824 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004825 {
4826 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4827 sizeof(*q),length,(unsigned char *) q);
4828 if ((MagickSizeType) count < length)
4829 break;
4830 offset+=cache_info->columns;
4831 q+=nexus_info->region.width;
4832 }
cristybb503372010-05-27 20:51:26 +00004833 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004834 {
4835 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4836 cache_info->cache_filename);
4837 return(MagickFalse);
4838 }
4839 break;
4840 }
4841 default:
4842 break;
4843 }
4844 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004845 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004846 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004847 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004848 nexus_info->region.width,(double) nexus_info->region.height,(double)
4849 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004850 return(MagickTrue);
4851}
4852
4853/*
4854%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4855% %
4856% %
4857% %
4858+ R e f e r e n c e P i x e l C a c h e %
4859% %
4860% %
4861% %
4862%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4863%
4864% ReferencePixelCache() increments the reference count associated with the
4865% pixel cache returning a pointer to the cache.
4866%
4867% The format of the ReferencePixelCache method is:
4868%
4869% Cache ReferencePixelCache(Cache cache_info)
4870%
4871% A description of each parameter follows:
4872%
4873% o cache_info: the pixel cache.
4874%
4875*/
4876MagickExport Cache ReferencePixelCache(Cache cache)
4877{
4878 CacheInfo
4879 *cache_info;
4880
4881 assert(cache != (Cache *) NULL);
4882 cache_info=(CacheInfo *) cache;
4883 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004884 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004885 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004886 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004887 return(cache_info);
4888}
4889
4890/*
4891%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4892% %
4893% %
4894% %
4895+ S e t P i x e l C a c h e M e t h o d s %
4896% %
4897% %
4898% %
4899%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4900%
4901% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4902%
4903% The format of the SetPixelCacheMethods() method is:
4904%
4905% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4906%
4907% A description of each parameter follows:
4908%
4909% o cache: the pixel cache.
4910%
4911% o cache_methods: Specifies a pointer to a CacheMethods structure.
4912%
4913*/
4914MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4915{
4916 CacheInfo
4917 *cache_info;
4918
4919 GetOneAuthenticPixelFromHandler
4920 get_one_authentic_pixel_from_handler;
4921
4922 GetOneVirtualPixelFromHandler
4923 get_one_virtual_pixel_from_handler;
4924
4925 /*
4926 Set cache pixel methods.
4927 */
4928 assert(cache != (Cache) NULL);
4929 assert(cache_methods != (CacheMethods *) NULL);
4930 cache_info=(CacheInfo *) cache;
4931 assert(cache_info->signature == MagickSignature);
4932 if (cache_info->debug != MagickFalse)
4933 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4934 cache_info->filename);
4935 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4936 cache_info->methods.get_virtual_pixel_handler=
4937 cache_methods->get_virtual_pixel_handler;
4938 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4939 cache_info->methods.destroy_pixel_handler=
4940 cache_methods->destroy_pixel_handler;
4941 if (cache_methods->get_virtual_indexes_from_handler !=
4942 (GetVirtualIndexesFromHandler) NULL)
4943 cache_info->methods.get_virtual_indexes_from_handler=
4944 cache_methods->get_virtual_indexes_from_handler;
4945 if (cache_methods->get_authentic_pixels_handler !=
4946 (GetAuthenticPixelsHandler) NULL)
4947 cache_info->methods.get_authentic_pixels_handler=
4948 cache_methods->get_authentic_pixels_handler;
4949 if (cache_methods->queue_authentic_pixels_handler !=
4950 (QueueAuthenticPixelsHandler) NULL)
4951 cache_info->methods.queue_authentic_pixels_handler=
4952 cache_methods->queue_authentic_pixels_handler;
4953 if (cache_methods->sync_authentic_pixels_handler !=
4954 (SyncAuthenticPixelsHandler) NULL)
4955 cache_info->methods.sync_authentic_pixels_handler=
4956 cache_methods->sync_authentic_pixels_handler;
4957 if (cache_methods->get_authentic_pixels_from_handler !=
4958 (GetAuthenticPixelsFromHandler) NULL)
4959 cache_info->methods.get_authentic_pixels_from_handler=
4960 cache_methods->get_authentic_pixels_from_handler;
4961 if (cache_methods->get_authentic_indexes_from_handler !=
4962 (GetAuthenticIndexesFromHandler) NULL)
4963 cache_info->methods.get_authentic_indexes_from_handler=
4964 cache_methods->get_authentic_indexes_from_handler;
4965 get_one_virtual_pixel_from_handler=
4966 cache_info->methods.get_one_virtual_pixel_from_handler;
4967 if (get_one_virtual_pixel_from_handler !=
4968 (GetOneVirtualPixelFromHandler) NULL)
4969 cache_info->methods.get_one_virtual_pixel_from_handler=
4970 cache_methods->get_one_virtual_pixel_from_handler;
4971 get_one_authentic_pixel_from_handler=
4972 cache_methods->get_one_authentic_pixel_from_handler;
4973 if (get_one_authentic_pixel_from_handler !=
4974 (GetOneAuthenticPixelFromHandler) NULL)
4975 cache_info->methods.get_one_authentic_pixel_from_handler=
4976 cache_methods->get_one_authentic_pixel_from_handler;
4977}
4978
4979/*
4980%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4981% %
4982% %
4983% %
4984+ S e t P i x e l C a c h e N e x u s P i x e l s %
4985% %
4986% %
4987% %
4988%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4989%
4990% SetPixelCacheNexusPixels() defines the region of the cache for the
4991% specified cache nexus.
4992%
4993% The format of the SetPixelCacheNexusPixels() method is:
4994%
4995% PixelPacket SetPixelCacheNexusPixels(const Image *image,
4996% const RectangleInfo *region,NexusInfo *nexus_info,
4997% ExceptionInfo *exception)
4998%
4999% A description of each parameter follows:
5000%
5001% o image: the image.
5002%
5003% o region: A pointer to the RectangleInfo structure that defines the
5004% region of this particular cache nexus.
5005%
5006% o nexus_info: the cache nexus to set.
5007%
5008% o exception: return any errors or warnings in this structure.
5009%
5010*/
5011static PixelPacket *SetPixelCacheNexusPixels(const Image *image,
5012 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
5013{
5014 CacheInfo
5015 *cache_info;
5016
5017 MagickBooleanType
5018 status;
5019
cristy3ed852e2009-09-05 21:47:34 +00005020 MagickSizeType
5021 length,
5022 number_pixels;
5023
cristy3ed852e2009-09-05 21:47:34 +00005024 cache_info=(CacheInfo *) image->cache;
5025 assert(cache_info->signature == MagickSignature);
5026 if (cache_info->type == UndefinedCache)
5027 return((PixelPacket *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00005028 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00005029 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
5030 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00005031 {
cristybb503372010-05-27 20:51:26 +00005032 ssize_t
cristybad067a2010-02-15 17:20:55 +00005033 x,
5034 y;
cristy3ed852e2009-09-05 21:47:34 +00005035
cristyeaedf062010-05-29 22:36:02 +00005036 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
5037 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00005038 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5039 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristy731c3532010-02-15 15:40:03 +00005040 ((nexus_info->region.height == 1UL) ||
5041 ((nexus_info->region.x == 0) &&
5042 ((nexus_info->region.width == cache_info->columns) ||
5043 ((nexus_info->region.width % cache_info->columns) == 0)))))
5044 {
5045 MagickOffsetType
5046 offset;
5047
5048 /*
5049 Pixels are accessed directly from memory.
5050 */
5051 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5052 nexus_info->region.x;
5053 nexus_info->pixels=cache_info->pixels+offset;
5054 nexus_info->indexes=(IndexPacket *) NULL;
5055 if (cache_info->active_index_channel != MagickFalse)
5056 nexus_info->indexes=cache_info->indexes+offset;
5057 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00005058 }
5059 }
5060 /*
5061 Pixels are stored in a cache region until they are synced to the cache.
5062 */
5063 number_pixels=(MagickSizeType) nexus_info->region.width*
5064 nexus_info->region.height;
5065 length=number_pixels*sizeof(PixelPacket);
5066 if (cache_info->active_index_channel != MagickFalse)
5067 length+=number_pixels*sizeof(IndexPacket);
5068 if (nexus_info->cache == (PixelPacket *) NULL)
5069 {
5070 nexus_info->length=length;
5071 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5072 if (status == MagickFalse)
5073 return((PixelPacket *) NULL);
5074 }
5075 else
5076 if (nexus_info->length != length)
5077 {
5078 RelinquishCacheNexusPixels(nexus_info);
5079 nexus_info->length=length;
5080 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5081 if (status == MagickFalse)
5082 return((PixelPacket *) NULL);
5083 }
5084 nexus_info->pixels=nexus_info->cache;
5085 nexus_info->indexes=(IndexPacket *) NULL;
5086 if (cache_info->active_index_channel != MagickFalse)
5087 nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
5088 return(nexus_info->pixels);
5089}
5090
5091/*
5092%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5093% %
5094% %
5095% %
5096% 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 %
5097% %
5098% %
5099% %
5100%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5101%
5102% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5103% pixel cache and returns the previous setting. A virtual pixel is any pixel
5104% access that is outside the boundaries of the image cache.
5105%
5106% The format of the SetPixelCacheVirtualMethod() method is:
5107%
5108% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5109% const VirtualPixelMethod virtual_pixel_method)
5110%
5111% A description of each parameter follows:
5112%
5113% o image: the image.
5114%
5115% o virtual_pixel_method: choose the type of virtual pixel.
5116%
5117*/
5118MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5119 const VirtualPixelMethod virtual_pixel_method)
5120{
5121 CacheInfo
5122 *cache_info;
5123
5124 VirtualPixelMethod
5125 method;
5126
5127 assert(image != (Image *) NULL);
5128 assert(image->signature == MagickSignature);
5129 if (image->debug != MagickFalse)
5130 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5131 assert(image->cache != (Cache) NULL);
5132 cache_info=(CacheInfo *) image->cache;
5133 assert(cache_info->signature == MagickSignature);
5134 method=cache_info->virtual_pixel_method;
5135 cache_info->virtual_pixel_method=virtual_pixel_method;
5136 return(method);
5137}
5138
5139/*
5140%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5141% %
5142% %
5143% %
5144+ 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 %
5145% %
5146% %
5147% %
5148%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5149%
5150% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5151% in-memory or disk cache. The method returns MagickTrue if the pixel region
5152% is synced, otherwise MagickFalse.
5153%
5154% The format of the SyncAuthenticPixelCacheNexus() method is:
5155%
5156% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5157% NexusInfo *nexus_info,ExceptionInfo *exception)
5158%
5159% A description of each parameter follows:
5160%
5161% o image: the image.
5162%
5163% o nexus_info: the cache nexus to sync.
5164%
5165% o exception: return any errors or warnings in this structure.
5166%
5167*/
5168MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5169 NexusInfo *nexus_info,ExceptionInfo *exception)
5170{
5171 CacheInfo
5172 *cache_info;
5173
5174 MagickBooleanType
5175 status;
5176
5177 /*
5178 Transfer pixels to the cache.
5179 */
5180 assert(image != (Image *) NULL);
5181 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005182 if (image->cache == (Cache) NULL)
5183 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5184 cache_info=(CacheInfo *) image->cache;
5185 if (cache_info->type == UndefinedCache)
5186 return(MagickFalse);
5187 if ((image->clip_mask != (Image *) NULL) &&
5188 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5189 return(MagickFalse);
5190 if ((image->mask != (Image *) NULL) &&
5191 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5192 return(MagickFalse);
5193 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5194 return(MagickTrue);
5195 assert(cache_info->signature == MagickSignature);
5196 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5197 if ((cache_info->active_index_channel != MagickFalse) &&
5198 (WritePixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse))
5199 return(MagickFalse);
5200 return(status);
5201}
5202
5203/*
5204%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5205% %
5206% %
5207% %
5208+ S y n c A u t h e n t i c P i x e l C a c h e %
5209% %
5210% %
5211% %
5212%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5213%
5214% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5215% or disk cache. The method returns MagickTrue if the pixel region is synced,
5216% otherwise MagickFalse.
5217%
5218% The format of the SyncAuthenticPixelsCache() method is:
5219%
5220% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5221% ExceptionInfo *exception)
5222%
5223% A description of each parameter follows:
5224%
5225% o image: the image.
5226%
5227% o exception: return any errors or warnings in this structure.
5228%
5229*/
5230static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5231 ExceptionInfo *exception)
5232{
5233 CacheInfo
5234 *cache_info;
5235
cristy6ebe97c2010-07-03 01:17:28 +00005236 int
cristy3ed852e2009-09-05 21:47:34 +00005237 id;
5238
5239 MagickBooleanType
5240 status;
5241
5242 cache_info=(CacheInfo *) image->cache;
5243 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00005244 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00005245 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5246 exception);
5247 return(status);
5248}
5249
5250/*
5251%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5252% %
5253% %
5254% %
5255% S y n c A u t h e n t i c P i x e l s %
5256% %
5257% %
5258% %
5259%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5260%
5261% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5262% The method returns MagickTrue if the pixel region is flushed, otherwise
5263% MagickFalse.
5264%
5265% The format of the SyncAuthenticPixels() method is:
5266%
5267% MagickBooleanType SyncAuthenticPixels(Image *image,
5268% ExceptionInfo *exception)
5269%
5270% A description of each parameter follows:
5271%
5272% o image: the image.
5273%
5274% o exception: return any errors or warnings in this structure.
5275%
5276*/
5277MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5278 ExceptionInfo *exception)
5279{
5280 CacheInfo
5281 *cache_info;
5282
5283 assert(image != (Image *) NULL);
5284 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005285 assert(image->cache != (Cache) NULL);
5286 cache_info=(CacheInfo *) image->cache;
5287 assert(cache_info->signature == MagickSignature);
5288 if (cache_info->methods.sync_authentic_pixels_handler ==
5289 (SyncAuthenticPixelsHandler) NULL)
5290 return(MagickFalse);
5291 return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
5292}
5293
5294/*
5295%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5296% %
5297% %
5298% %
5299+ W r i t e P i x e l C a c h e I n d e x e s %
5300% %
5301% %
5302% %
5303%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5304%
5305% WritePixelCacheIndexes() writes the colormap indexes to the specified
5306% region of the pixel cache.
5307%
5308% The format of the WritePixelCacheIndexes() method is:
5309%
5310% MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5311% NexusInfo *nexus_info,ExceptionInfo *exception)
5312%
5313% A description of each parameter follows:
5314%
5315% o cache_info: the pixel cache.
5316%
5317% o nexus_info: the cache nexus to write the colormap indexes.
5318%
5319% o exception: return any errors or warnings in this structure.
5320%
5321*/
5322static MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5323 NexusInfo *nexus_info,ExceptionInfo *exception)
5324{
5325 MagickOffsetType
5326 count,
5327 offset;
5328
5329 MagickSizeType
5330 length,
5331 number_pixels;
5332
5333 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005334 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005335
cristybb503372010-05-27 20:51:26 +00005336 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005337 y;
5338
cristybb503372010-05-27 20:51:26 +00005339 size_t
cristy3ed852e2009-09-05 21:47:34 +00005340 rows;
5341
cristy3ed852e2009-09-05 21:47:34 +00005342 if (cache_info->active_index_channel == MagickFalse)
5343 return(MagickFalse);
5344 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5345 return(MagickTrue);
5346 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5347 nexus_info->region.x;
5348 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
5349 rows=nexus_info->region.height;
5350 number_pixels=(MagickSizeType) length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005351 p=nexus_info->indexes;
5352 switch (cache_info->type)
5353 {
5354 case MemoryCache:
5355 case MapCache:
5356 {
5357 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005358 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005359
5360 /*
5361 Write indexes to memory.
5362 */
cristydd341db2010-03-04 19:06:38 +00005363 if ((cache_info->columns == nexus_info->region.width) &&
5364 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5365 {
5366 length=number_pixels;
5367 rows=1UL;
5368 }
cristy3ed852e2009-09-05 21:47:34 +00005369 q=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00005370 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005371 {
5372 (void) CopyMagickMemory(q,p,(size_t) length);
5373 p+=nexus_info->region.width;
5374 q+=cache_info->columns;
5375 }
5376 break;
5377 }
5378 case DiskCache:
5379 {
5380 /*
5381 Write indexes to disk.
5382 */
5383 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5384 {
5385 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5386 cache_info->cache_filename);
5387 return(MagickFalse);
5388 }
cristydd341db2010-03-04 19:06:38 +00005389 if ((cache_info->columns == nexus_info->region.width) &&
5390 (number_pixels < MagickMaxBufferExtent))
5391 {
5392 length=number_pixels;
5393 rows=1UL;
5394 }
cristy3ed852e2009-09-05 21:47:34 +00005395 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005396 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005397 {
5398 count=WritePixelCacheRegion(cache_info,cache_info->offset+number_pixels*
5399 sizeof(PixelPacket)+offset*sizeof(*p),length,
5400 (const unsigned char *) p);
5401 if ((MagickSizeType) count < length)
5402 break;
5403 p+=nexus_info->region.width;
5404 offset+=cache_info->columns;
5405 }
cristybb503372010-05-27 20:51:26 +00005406 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005407 {
5408 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5409 cache_info->cache_filename);
5410 return(MagickFalse);
5411 }
5412 break;
5413 }
5414 default:
5415 break;
5416 }
5417 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005418 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005419 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005420 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005421 nexus_info->region.width,(double) nexus_info->region.height,(double)
5422 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005423 return(MagickTrue);
5424}
5425
5426/*
5427%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5428% %
5429% %
5430% %
5431+ W r i t e C a c h e P i x e l s %
5432% %
5433% %
5434% %
5435%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5436%
5437% WritePixelCachePixels() writes image pixels to the specified region of the
5438% pixel cache.
5439%
5440% The format of the WritePixelCachePixels() method is:
5441%
5442% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5443% NexusInfo *nexus_info,ExceptionInfo *exception)
5444%
5445% A description of each parameter follows:
5446%
5447% o cache_info: the pixel cache.
5448%
5449% o nexus_info: the cache nexus to write the pixels.
5450%
5451% o exception: return any errors or warnings in this structure.
5452%
5453*/
5454static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5455 NexusInfo *nexus_info,ExceptionInfo *exception)
5456{
5457 MagickOffsetType
5458 count,
5459 offset;
5460
5461 MagickSizeType
5462 length,
5463 number_pixels;
5464
cristy3ed852e2009-09-05 21:47:34 +00005465 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005466 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005467
cristybb503372010-05-27 20:51:26 +00005468 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005469 y;
5470
cristybb503372010-05-27 20:51:26 +00005471 size_t
cristy3ed852e2009-09-05 21:47:34 +00005472 rows;
5473
cristy3ed852e2009-09-05 21:47:34 +00005474 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5475 return(MagickTrue);
5476 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5477 nexus_info->region.x;
5478 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
5479 rows=nexus_info->region.height;
5480 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005481 p=nexus_info->pixels;
5482 switch (cache_info->type)
5483 {
5484 case MemoryCache:
5485 case MapCache:
5486 {
5487 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005488 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005489
5490 /*
5491 Write pixels to memory.
5492 */
cristydd341db2010-03-04 19:06:38 +00005493 if ((cache_info->columns == nexus_info->region.width) &&
5494 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5495 {
5496 length=number_pixels;
5497 rows=1UL;
5498 }
cristy3ed852e2009-09-05 21:47:34 +00005499 q=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00005500 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005501 {
5502 (void) CopyMagickMemory(q,p,(size_t) length);
5503 p+=nexus_info->region.width;
5504 q+=cache_info->columns;
5505 }
5506 break;
5507 }
5508 case DiskCache:
5509 {
5510 /*
5511 Write pixels to disk.
5512 */
5513 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5514 {
5515 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5516 cache_info->cache_filename);
5517 return(MagickFalse);
5518 }
cristydd341db2010-03-04 19:06:38 +00005519 if ((cache_info->columns == nexus_info->region.width) &&
5520 (number_pixels < MagickMaxBufferExtent))
5521 {
5522 length=number_pixels;
5523 rows=1UL;
5524 }
cristybb503372010-05-27 20:51:26 +00005525 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005526 {
5527 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5528 sizeof(*p),length,(const unsigned char *) p);
5529 if ((MagickSizeType) count < length)
5530 break;
5531 p+=nexus_info->region.width;
5532 offset+=cache_info->columns;
5533 }
cristybb503372010-05-27 20:51:26 +00005534 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005535 {
5536 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5537 cache_info->cache_filename);
5538 return(MagickFalse);
5539 }
5540 break;
5541 }
5542 default:
5543 break;
5544 }
5545 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005546 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005547 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005548 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005549 nexus_info->region.width,(double) nexus_info->region.height,(double)
5550 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005551 return(MagickTrue);
5552}