blob: 6712e187c3222408c2fac6bcd054a6c478173579 [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);
cristy77ff0282010-09-13 00:51:10 +0000438 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +0000439 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% %
cristy60c44a82009-10-07 00:58:49 +0000529+ 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 +0000530% %
531% %
532% %
533%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
534% ClonePixelCachePixels() clones the source pixel cache to the destination
535% cache.
536%
537% The format of the ClonePixelCachePixels() method is:
538%
539% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
540% CacheInfo *source_info,ExceptionInfo *exception)
541%
542% A description of each parameter follows:
543%
544% o cache_info: the pixel cache.
545%
546% o source_info: the source pixel cache.
547%
548% o exception: return any errors or warnings in this structure.
549%
550*/
551
552static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
553{
554 int
555 status;
556
cristy5ee247a2010-02-12 15:42:34 +0000557 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000558 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000559 if (cache_info->file != -1)
560 status=close(cache_info->file);
cristy3ed852e2009-09-05 21:47:34 +0000561 cache_info->file=(-1);
562 RelinquishMagickResource(FileResource,1);
cristyf84a1932010-01-03 18:00:18 +0000563 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000564 return(status == -1 ? MagickFalse : MagickTrue);
565}
566
567static void LimitPixelCacheDescriptors(void)
568{
569 register CacheInfo
570 *p,
571 *q;
572
573 /*
574 Limit # of open file descriptors.
575 */
576 if (GetMagickResource(FileResource) < GetMagickResourceLimit(FileResource))
577 return;
cristyf84a1932010-01-03 18:00:18 +0000578 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000579 if (cache_resources == (SplayTreeInfo *) NULL)
580 {
cristyf84a1932010-01-03 18:00:18 +0000581 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000582 return;
583 }
584 ResetSplayTreeIterator(cache_resources);
585 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
586 while (p != (CacheInfo *) NULL)
587 {
588 if ((p->type == DiskCache) && (p->file != -1))
cristy508d9312010-02-10 21:10:30 +0000589 break;
cristy3ed852e2009-09-05 21:47:34 +0000590 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
591 }
592 for (q=p; p != (CacheInfo *) NULL; )
593 {
594 if ((p->type == DiskCache) && (p->file != -1) &&
595 (p->timestamp < q->timestamp))
cristy508d9312010-02-10 21:10:30 +0000596 q=p;
cristy3ed852e2009-09-05 21:47:34 +0000597 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
598 }
599 if (q != (CacheInfo *) NULL)
cristy9e116922010-02-12 20:58:13 +0000600 {
601 /*
602 Close least recently used cache.
603 */
604 (void) close(q->file);
605 q->file=(-1);
606 }
cristyf84a1932010-01-03 18:00:18 +0000607 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000608}
609
610static inline MagickSizeType MagickMax(const MagickSizeType x,
611 const MagickSizeType y)
612{
613 if (x > y)
614 return(x);
615 return(y);
616}
617
618static inline MagickSizeType MagickMin(const MagickSizeType x,
619 const MagickSizeType y)
620{
621 if (x < y)
622 return(x);
623 return(y);
624}
625
626static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
627 const MapMode mode)
628{
629 int
630 file;
631
632 /*
633 Open pixel cache on disk.
634 */
cristyf84a1932010-01-03 18:00:18 +0000635 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000636 if (cache_info->file != -1)
637 {
cristyf84a1932010-01-03 18:00:18 +0000638 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000639 return(MagickTrue); /* cache already open */
640 }
641 LimitPixelCacheDescriptors();
642 if (*cache_info->cache_filename == '\0')
643 file=AcquireUniqueFileResource(cache_info->cache_filename);
644 else
645 switch (mode)
646 {
647 case ReadMode:
648 {
649 file=open(cache_info->cache_filename,O_RDONLY | O_BINARY);
650 break;
651 }
652 case WriteMode:
653 {
654 file=open(cache_info->cache_filename,O_WRONLY | O_CREAT | O_BINARY |
655 O_EXCL,S_MODE);
656 if (file == -1)
657 file=open(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
658 break;
659 }
660 case IOMode:
661 default:
662 {
663 file=open(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
664 O_EXCL,S_MODE);
665 if (file == -1)
666 file=open(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
667 break;
668 }
669 }
670 if (file == -1)
671 {
cristyf84a1932010-01-03 18:00:18 +0000672 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000673 return(MagickFalse);
674 }
675 (void) AcquireMagickResource(FileResource,1);
676 cache_info->file=file;
677 cache_info->timestamp=time(0);
cristyf84a1932010-01-03 18:00:18 +0000678 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000679 return(MagickTrue);
680}
681
682static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
683 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000684 unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000685{
686 register MagickOffsetType
687 i;
688
689 ssize_t
690 count;
691
cristy08a88202010-03-04 19:18:05 +0000692 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000693#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000694 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000695 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
696 {
cristyf84a1932010-01-03 18:00:18 +0000697 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000698 return((MagickOffsetType) -1);
699 }
700#endif
701 count=0;
702 for (i=0; i < (MagickOffsetType) length; i+=count)
703 {
704#if !defined(MAGICKCORE_HAVE_PREAD)
705 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
706 (MagickSizeType) SSIZE_MAX));
707#else
708 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
709 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
710#endif
711 if (count > 0)
712 continue;
713 count=0;
714 if (errno != EINTR)
715 {
716 i=(-1);
717 break;
718 }
719 }
720#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000721 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000722#endif
723 return(i);
724}
725
726static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
727 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000728 const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000729{
730 register MagickOffsetType
731 i;
732
733 ssize_t
734 count;
735
cristy08a88202010-03-04 19:18:05 +0000736 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000737#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000738 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000739 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
740 {
cristyf84a1932010-01-03 18:00:18 +0000741 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000742 return((MagickOffsetType) -1);
743 }
744#endif
745 count=0;
746 for (i=0; i < (MagickOffsetType) length; i+=count)
747 {
748#if !defined(MAGICKCORE_HAVE_PWRITE)
749 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
750 (MagickSizeType) SSIZE_MAX));
751#else
752 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
753 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
754#endif
755 if (count > 0)
756 continue;
757 count=0;
758 if (errno != EINTR)
759 {
760 i=(-1);
761 break;
762 }
763 }
764#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000765 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000766#endif
767 return(i);
768}
769
770static MagickBooleanType CloneDiskToDiskPixelCache(CacheInfo *clone_info,
771 CacheInfo *cache_info,ExceptionInfo *exception)
772{
773 MagickOffsetType
774 count,
775 offset,
776 source_offset;
777
778 MagickSizeType
779 length;
780
cristy3ed852e2009-09-05 21:47:34 +0000781 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000782 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +0000783
cristye076a6e2010-08-15 19:59:43 +0000784 register ssize_t
785 y;
786
cristybb503372010-05-27 20:51:26 +0000787 size_t
cristy3ed852e2009-09-05 21:47:34 +0000788 columns,
789 rows;
790
791 if (cache_info->debug != MagickFalse)
792 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
793 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
794 {
795 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
796 clone_info->cache_filename);
797 return(MagickFalse);
798 }
799 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
800 {
801 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
802 cache_info->cache_filename);
803 return(MagickFalse);
804 }
cristybb503372010-05-27 20:51:26 +0000805 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
806 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +0000807 if ((clone_info->active_index_channel != MagickFalse) &&
808 (cache_info->active_index_channel != MagickFalse))
809 {
810 register IndexPacket
811 *indexes;
812
813 /*
814 Clone cache indexes.
815 */
816 length=MagickMax(clone_info->columns,cache_info->columns)*
817 sizeof(*indexes);
818 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
819 if (indexes == (IndexPacket *) NULL)
820 {
821 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
822 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
823 return(MagickFalse);
824 }
825 (void) ResetMagickMemory(indexes,0,(size_t) length);
826 length=columns*sizeof(*indexes);
827 source_offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
828 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
829 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
830 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +0000831 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000832 {
833 source_offset-=cache_info->columns*sizeof(*indexes);
834 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
835 length,(unsigned char *) indexes);
836 if ((MagickSizeType) count != length)
837 break;
838 offset-=clone_info->columns*sizeof(*indexes);
839 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
840 (unsigned char *) indexes);
841 if ((MagickSizeType) count != length)
842 break;
843 }
cristybb503372010-05-27 20:51:26 +0000844 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000845 {
846 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
847 ThrowFileException(exception,CacheError,"UnableToCloneCache",
848 cache_info->cache_filename);
849 return(MagickFalse);
850 }
851 if (clone_info->columns > cache_info->columns)
852 {
853 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
854 (void) ResetMagickMemory(indexes,0,(size_t) length);
855 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
856 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +0000857 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000858 {
859 offset-=clone_info->columns*sizeof(*indexes);
860 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
861 length,(unsigned char *) indexes);
862 if ((MagickSizeType) count != length)
863 break;
864 }
cristybb503372010-05-27 20:51:26 +0000865 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000866 {
867 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
868 ThrowFileException(exception,CacheError,"UnableToCloneCache",
869 cache_info->cache_filename);
870 return(MagickFalse);
871 }
872 }
873 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
874 }
875 /*
876 Clone cache pixels.
877 */
878 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
879 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
880 if (pixels == (PixelPacket *) NULL)
881 {
882 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
883 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
884 return(MagickFalse);
885 }
886 (void) ResetMagickMemory(pixels,0,(size_t) length);
887 length=columns*sizeof(*pixels);
888 source_offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
889 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +0000890 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000891 {
892 source_offset-=cache_info->columns*sizeof(*pixels);
893 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
894 length,(unsigned char *) pixels);
895 if ((MagickSizeType) count != length)
896 break;
897 offset-=clone_info->columns*sizeof(*pixels);
898 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
899 (unsigned char *) pixels);
900 if ((MagickSizeType) count != length)
901 break;
902 }
cristybb503372010-05-27 20:51:26 +0000903 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000904 {
905 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
906 ThrowFileException(exception,CacheError,"UnableToCloneCache",
907 cache_info->cache_filename);
908 return(MagickFalse);
909 }
910 if (clone_info->columns > cache_info->columns)
911 {
912 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
913 sizeof(*pixels);
914 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
915 (void) ResetMagickMemory(pixels,0,(size_t) length);
cristybb503372010-05-27 20:51:26 +0000916 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000917 {
918 offset-=clone_info->columns*sizeof(*pixels);
919 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
920 (unsigned char *) pixels);
921 if ((MagickSizeType) count != length)
922 break;
923 }
cristybb503372010-05-27 20:51:26 +0000924 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000925 {
926 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
927 ThrowFileException(exception,CacheError,"UnableToCloneCache",
928 cache_info->cache_filename);
929 return(MagickFalse);
930 }
931 }
932 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
933 return(MagickTrue);
934}
935
936static MagickBooleanType CloneDiskToMemoryPixelCache(CacheInfo *clone_info,
937 CacheInfo *cache_info,ExceptionInfo *exception)
938{
939 MagickOffsetType
940 count,
941 offset;
942
943 MagickSizeType
944 length;
945
cristy3ed852e2009-09-05 21:47:34 +0000946 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000947 *restrict pixels,
948 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000949
cristye076a6e2010-08-15 19:59:43 +0000950 register ssize_t
951 y;
952
cristybb503372010-05-27 20:51:26 +0000953 size_t
cristy3ed852e2009-09-05 21:47:34 +0000954 columns,
955 rows;
956
957 if (cache_info->debug != MagickFalse)
958 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
959 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
960 {
961 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
962 cache_info->cache_filename);
963 return(MagickFalse);
964 }
cristybb503372010-05-27 20:51:26 +0000965 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
966 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +0000967 if ((clone_info->active_index_channel != MagickFalse) &&
968 (cache_info->active_index_channel != MagickFalse))
969 {
970 register IndexPacket
971 *indexes,
972 *q;
973
974 /*
975 Clone cache indexes.
976 */
977 length=MagickMax(clone_info->columns,cache_info->columns)*
978 sizeof(*indexes);
979 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
980 if (indexes == (IndexPacket *) NULL)
981 {
982 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
983 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
984 return(MagickFalse);
985 }
986 (void) ResetMagickMemory(indexes,0,(size_t) length);
987 length=columns*sizeof(IndexPacket);
988 offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
989 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
990 q=clone_info->indexes+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +0000991 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000992 {
993 offset-=cache_info->columns*sizeof(IndexPacket);
994 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,
995 length,(unsigned char *) indexes);
996 if ((MagickSizeType) count != length)
997 break;
998 q-=clone_info->columns;
999 (void) CopyMagickMemory(q,indexes,(size_t) length);
1000 if ((MagickSizeType) count != length)
1001 break;
1002 }
cristybb503372010-05-27 20:51:26 +00001003 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001004 {
1005 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1006 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1007 cache_info->cache_filename);
1008 return(MagickFalse);
1009 }
1010 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1011 }
1012 /*
1013 Clone cache pixels.
1014 */
1015 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1016 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1017 if (pixels == (PixelPacket *) NULL)
1018 {
1019 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1020 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1021 return(MagickFalse);
1022 }
1023 (void) ResetMagickMemory(pixels,0,(size_t) length);
1024 length=columns*sizeof(*pixels);
1025 offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
1026 q=clone_info->pixels+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001027 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001028 {
1029 offset-=cache_info->columns*sizeof(*pixels);
1030 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,length,
1031 (unsigned char *) pixels);
1032 if ((MagickSizeType) count != length)
1033 break;
1034 q-=clone_info->columns;
1035 (void) CopyMagickMemory(q,pixels,(size_t) length);
1036 }
cristybb503372010-05-27 20:51:26 +00001037 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001038 {
1039 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1040 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1041 cache_info->cache_filename);
1042 return(MagickFalse);
1043 }
1044 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1045 return(MagickTrue);
1046}
1047
1048static MagickBooleanType CloneMemoryToDiskPixelCache(CacheInfo *clone_info,
1049 CacheInfo *cache_info,ExceptionInfo *exception)
1050{
1051 MagickOffsetType
1052 count,
1053 offset;
1054
1055 MagickSizeType
1056 length;
1057
cristy3ed852e2009-09-05 21:47:34 +00001058 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001059 *restrict p,
1060 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +00001061
cristye076a6e2010-08-15 19:59:43 +00001062 register ssize_t
1063 y;
1064
cristybb503372010-05-27 20:51:26 +00001065 size_t
cristy3ed852e2009-09-05 21:47:34 +00001066 columns,
1067 rows;
1068
1069 if (cache_info->debug != MagickFalse)
1070 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
1071 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
1072 {
1073 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1074 clone_info->cache_filename);
1075 return(MagickFalse);
1076 }
cristybb503372010-05-27 20:51:26 +00001077 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1078 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001079 if ((clone_info->active_index_channel != MagickFalse) &&
1080 (cache_info->active_index_channel != MagickFalse))
1081 {
1082 register IndexPacket
1083 *p,
1084 *indexes;
1085
1086 /*
1087 Clone cache indexes.
1088 */
1089 length=MagickMax(clone_info->columns,cache_info->columns)*
1090 sizeof(*indexes);
1091 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
1092 if (indexes == (IndexPacket *) NULL)
1093 {
1094 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1095 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1096 return(MagickFalse);
1097 }
1098 (void) ResetMagickMemory(indexes,0,(size_t) length);
1099 length=columns*sizeof(*indexes);
1100 p=cache_info->indexes+cache_info->columns*rows;
1101 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1102 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +00001103 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001104 {
1105 p-=cache_info->columns;
1106 (void) CopyMagickMemory(indexes,p,(size_t) length);
1107 offset-=clone_info->columns*sizeof(*indexes);
1108 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1109 (unsigned char *) indexes);
1110 if ((MagickSizeType) count != length)
1111 break;
1112 }
cristybb503372010-05-27 20:51:26 +00001113 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001114 {
1115 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1116 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1117 cache_info->cache_filename);
1118 return(MagickFalse);
1119 }
1120 if (clone_info->columns > cache_info->columns)
1121 {
1122 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
1123 (void) ResetMagickMemory(indexes,0,(size_t) length);
1124 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1125 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +00001126 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001127 {
1128 offset-=clone_info->columns*sizeof(*indexes);
1129 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
1130 length,(unsigned char *) indexes);
1131 if ((MagickSizeType) count != length)
1132 break;
1133 }
cristybb503372010-05-27 20:51:26 +00001134 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001135 {
1136 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1137 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1138 cache_info->cache_filename);
1139 return(MagickFalse);
1140 }
1141 }
1142 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1143 }
1144 /*
1145 Clone cache pixels.
1146 */
1147 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1148 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1149 if (pixels == (PixelPacket *) NULL)
1150 {
1151 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1152 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1153 return(MagickFalse);
1154 }
1155 (void) ResetMagickMemory(pixels,0,(size_t) length);
1156 length=columns*sizeof(*pixels);
1157 p=cache_info->pixels+cache_info->columns*rows;
1158 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +00001159 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001160 {
1161 p-=cache_info->columns;
1162 (void) CopyMagickMemory(pixels,p,(size_t) length);
1163 offset-=clone_info->columns*sizeof(*pixels);
1164 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1165 (unsigned char *) pixels);
1166 if ((MagickSizeType) count != length)
1167 break;
1168 }
cristybb503372010-05-27 20:51:26 +00001169 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001170 {
1171 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1172 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1173 cache_info->cache_filename);
1174 return(MagickFalse);
1175 }
1176 if (clone_info->columns > cache_info->columns)
1177 {
1178 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
1179 sizeof(*pixels);
1180 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1181 (void) ResetMagickMemory(pixels,0,(size_t) length);
cristybb503372010-05-27 20:51:26 +00001182 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001183 {
1184 offset-=clone_info->columns*sizeof(*pixels);
1185 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1186 (unsigned char *) pixels);
1187 if ((MagickSizeType) count != length)
1188 break;
1189 }
cristybb503372010-05-27 20:51:26 +00001190 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001191 {
1192 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1193 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1194 cache_info->cache_filename);
1195 return(MagickFalse);
1196 }
1197 }
1198 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1199 return(MagickTrue);
1200}
1201
1202static MagickBooleanType CloneMemoryToMemoryPixelCache(CacheInfo *clone_info,
1203 CacheInfo *cache_info,ExceptionInfo *magick_unused(exception))
1204{
cristy3ed852e2009-09-05 21:47:34 +00001205 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001206 *restrict pixels,
1207 *restrict source_pixels;
cristy3ed852e2009-09-05 21:47:34 +00001208
cristye076a6e2010-08-15 19:59:43 +00001209 register ssize_t
1210 y;
cristy3ed852e2009-09-05 21:47:34 +00001211
cristybb503372010-05-27 20:51:26 +00001212 size_t
cristy3ed852e2009-09-05 21:47:34 +00001213 columns,
cristye076a6e2010-08-15 19:59:43 +00001214 length,
cristy3ed852e2009-09-05 21:47:34 +00001215 rows;
1216
1217 if (cache_info->debug != MagickFalse)
1218 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
cristybb503372010-05-27 20:51:26 +00001219 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1220 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001221 if ((clone_info->active_index_channel != MagickFalse) &&
1222 (cache_info->active_index_channel != MagickFalse))
1223 {
1224 register IndexPacket
1225 *indexes,
1226 *source_indexes;
1227
1228 /*
1229 Clone cache indexes.
1230 */
1231 length=columns*sizeof(*indexes);
1232 if (clone_info->columns == cache_info->columns)
1233 (void) CopyMagickMemory(clone_info->indexes,cache_info->indexes,
1234 length*rows);
1235 else
1236 {
1237 source_indexes=cache_info->indexes+cache_info->columns*rows;
1238 indexes=clone_info->indexes+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001239 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001240 {
1241 source_indexes-=cache_info->columns;
1242 indexes-=clone_info->columns;
1243 (void) CopyMagickMemory(indexes,source_indexes,length);
1244 }
1245 if (clone_info->columns > cache_info->columns)
1246 {
1247 length=(clone_info->columns-cache_info->columns)*
1248 sizeof(*indexes);
1249 indexes=clone_info->indexes+clone_info->columns*rows+
1250 cache_info->columns;
cristybb503372010-05-27 20:51:26 +00001251 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001252 {
1253 indexes-=clone_info->columns;
1254 (void) ResetMagickMemory(indexes,0,length);
1255 }
1256 }
1257 }
1258 }
1259 /*
1260 Clone cache pixels.
1261 */
1262 length=columns*sizeof(*pixels);
1263 if (clone_info->columns == cache_info->columns)
1264 (void) CopyMagickMemory(clone_info->pixels,cache_info->pixels,length*rows);
1265 else
1266 {
1267 source_pixels=cache_info->pixels+cache_info->columns*rows;
1268 pixels=clone_info->pixels+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001269 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001270 {
1271 source_pixels-=cache_info->columns;
1272 pixels-=clone_info->columns;
1273 (void) CopyMagickMemory(pixels,source_pixels,length);
1274 }
1275 if (clone_info->columns > cache_info->columns)
1276 {
1277 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1278 pixels=clone_info->pixels+clone_info->columns*rows+
1279 cache_info->columns;
cristybb503372010-05-27 20:51:26 +00001280 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001281 {
1282 pixels-=clone_info->columns;
1283 (void) ResetMagickMemory(pixels,0,length);
1284 }
1285 }
1286 }
1287 return(MagickTrue);
1288}
1289
1290static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1291 CacheInfo *cache_info,ExceptionInfo *exception)
1292{
1293 if ((clone_info->type != DiskCache) && (cache_info->type != DiskCache))
1294 return(CloneMemoryToMemoryPixelCache(clone_info,cache_info,exception));
1295 if ((clone_info->type == DiskCache) && (cache_info->type == DiskCache))
1296 return(CloneDiskToDiskPixelCache(clone_info,cache_info,exception));
1297 if (cache_info->type == DiskCache)
1298 return(CloneDiskToMemoryPixelCache(clone_info,cache_info,exception));
1299 return(CloneMemoryToDiskPixelCache(clone_info,cache_info,exception));
1300}
1301
1302/*
1303%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1304% %
1305% %
1306% %
1307+ C l o n e P i x e l C a c h e M e t h o d s %
1308% %
1309% %
1310% %
1311%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1312%
1313% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1314% another.
1315%
1316% The format of the ClonePixelCacheMethods() method is:
1317%
1318% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1319%
1320% A description of each parameter follows:
1321%
1322% o clone: Specifies a pointer to a Cache structure.
1323%
1324% o cache: the pixel cache.
1325%
1326*/
1327MagickExport void ClonePixelCacheMethods(Cache clone,const Cache cache)
1328{
1329 CacheInfo
1330 *cache_info,
1331 *source_info;
1332
1333 assert(clone != (Cache) NULL);
1334 source_info=(CacheInfo *) clone;
1335 assert(source_info->signature == MagickSignature);
1336 if (source_info->debug != MagickFalse)
1337 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1338 source_info->filename);
1339 assert(cache != (Cache) NULL);
1340 cache_info=(CacheInfo *) cache;
1341 assert(cache_info->signature == MagickSignature);
1342 source_info->methods=cache_info->methods;
1343}
1344
1345/*
1346%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1347% %
1348% %
1349% %
1350+ D e s t r o y I m a g e P i x e l C a c h e %
1351% %
1352% %
1353% %
1354%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1355%
1356% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1357%
1358% The format of the DestroyImagePixelCache() method is:
1359%
1360% void DestroyImagePixelCache(Image *image)
1361%
1362% A description of each parameter follows:
1363%
1364% o image: the image.
1365%
1366*/
1367static void DestroyImagePixelCache(Image *image)
1368{
1369 assert(image != (Image *) NULL);
1370 assert(image->signature == MagickSignature);
1371 if (image->debug != MagickFalse)
1372 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1373 if (image->cache == (void *) NULL)
1374 return;
1375 image->cache=DestroyPixelCache(image->cache);
1376}
1377
1378/*
1379%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1380% %
1381% %
1382% %
1383+ D e s t r o y I m a g e P i x e l s %
1384% %
1385% %
1386% %
1387%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1388%
1389% DestroyImagePixels() deallocates memory associated with the pixel cache.
1390%
1391% The format of the DestroyImagePixels() method is:
1392%
1393% void DestroyImagePixels(Image *image)
1394%
1395% A description of each parameter follows:
1396%
1397% o image: the image.
1398%
1399*/
1400MagickExport void DestroyImagePixels(Image *image)
1401{
1402 CacheInfo
1403 *cache_info;
1404
1405 assert(image != (const Image *) NULL);
1406 assert(image->signature == MagickSignature);
1407 if (image->debug != MagickFalse)
1408 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1409 assert(image->cache != (Cache) NULL);
1410 cache_info=(CacheInfo *) image->cache;
1411 assert(cache_info->signature == MagickSignature);
1412 if (cache_info->methods.destroy_pixel_handler == (DestroyPixelHandler) NULL)
1413 return;
1414 cache_info->methods.destroy_pixel_handler(image);
1415}
1416
1417/*
1418%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1419% %
1420% %
1421% %
1422+ D e s t r o y P i x e l C a c h e %
1423% %
1424% %
1425% %
1426%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1427%
1428% DestroyPixelCache() deallocates memory associated with the pixel cache.
1429%
1430% The format of the DestroyPixelCache() method is:
1431%
1432% Cache DestroyPixelCache(Cache cache)
1433%
1434% A description of each parameter follows:
1435%
1436% o cache: the pixel cache.
1437%
1438*/
1439
1440static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1441{
1442 switch (cache_info->type)
1443 {
1444 case MemoryCache:
1445 {
1446 if (cache_info->mapped == MagickFalse)
1447 cache_info->pixels=(PixelPacket *) RelinquishMagickMemory(
1448 cache_info->pixels);
1449 else
1450 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,
1451 (size_t) cache_info->length);
1452 RelinquishMagickResource(MemoryResource,cache_info->length);
1453 break;
1454 }
1455 case MapCache:
1456 {
1457 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,(size_t)
1458 cache_info->length);
1459 RelinquishMagickResource(MapResource,cache_info->length);
1460 }
1461 case DiskCache:
1462 {
1463 if (cache_info->file != -1)
1464 (void) ClosePixelCacheOnDisk(cache_info);
1465 RelinquishMagickResource(DiskResource,cache_info->length);
1466 break;
1467 }
1468 default:
1469 break;
1470 }
1471 cache_info->type=UndefinedCache;
1472 cache_info->mapped=MagickFalse;
1473 cache_info->indexes=(IndexPacket *) NULL;
1474}
1475
1476MagickExport Cache DestroyPixelCache(Cache cache)
1477{
1478 CacheInfo
1479 *cache_info;
1480
cristy3ed852e2009-09-05 21:47:34 +00001481 assert(cache != (Cache) NULL);
1482 cache_info=(CacheInfo *) cache;
1483 assert(cache_info->signature == MagickSignature);
1484 if (cache_info->debug != MagickFalse)
1485 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1486 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001487 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001488 cache_info->reference_count--;
1489 if (cache_info->reference_count != 0)
1490 {
cristyf84a1932010-01-03 18:00:18 +00001491 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001492 return((Cache) NULL);
1493 }
cristyf84a1932010-01-03 18:00:18 +00001494 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001495 if (cache_resources != (SplayTreeInfo *) NULL)
1496 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
cristy5b8de732009-09-10 23:50:40 +00001497 if (cache_info->debug != MagickFalse)
1498 {
1499 char
1500 message[MaxTextExtent];
1501
1502 (void) FormatMagickString(message,MaxTextExtent,"destroy %s",
1503 cache_info->filename);
1504 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1505 }
cristyc2e1bdd2009-09-10 23:43:34 +00001506 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1507 (cache_info->type != DiskCache)))
1508 RelinquishPixelCachePixels(cache_info);
1509 else
1510 {
1511 RelinquishPixelCachePixels(cache_info);
1512 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1513 }
cristy3ed852e2009-09-05 21:47:34 +00001514 *cache_info->cache_filename='\0';
1515 if (cache_info->nexus_info != (NexusInfo **) NULL)
1516 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1517 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001518 if (cache_info->random_info != (RandomInfo *) NULL)
1519 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001520 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1521 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1522 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1523 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001524 cache_info->signature=(~MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001525 cache_info=(CacheInfo *) RelinquishAlignedMemory(cache_info);
1526 cache=(Cache) NULL;
1527 return(cache);
1528}
1529
1530/*
1531%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1532% %
1533% %
1534% %
1535+ D e s t r o y P i x e l C a c h e N e x u s %
1536% %
1537% %
1538% %
1539%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1540%
1541% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1542%
1543% The format of the DestroyPixelCacheNexus() method is:
1544%
1545% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001546% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001547%
1548% A description of each parameter follows:
1549%
1550% o nexus_info: the nexus to destroy.
1551%
1552% o number_threads: the number of nexus threads.
1553%
1554*/
1555
1556static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1557{
1558 if (nexus_info->mapped == MagickFalse)
1559 (void) RelinquishMagickMemory(nexus_info->cache);
1560 else
1561 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1562 nexus_info->cache=(PixelPacket *) NULL;
1563 nexus_info->pixels=(PixelPacket *) NULL;
1564 nexus_info->indexes=(IndexPacket *) NULL;
1565 nexus_info->length=0;
1566 nexus_info->mapped=MagickFalse;
1567}
1568
1569MagickExport NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001570 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001571{
cristybb503372010-05-27 20:51:26 +00001572 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001573 i;
1574
1575 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001576 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001577 {
1578 if (nexus_info[i]->cache != (PixelPacket *) NULL)
1579 RelinquishCacheNexusPixels(nexus_info[i]);
1580 nexus_info[i]->signature=(~MagickSignature);
1581 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
1582 }
1583 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
1584 return(nexus_info);
1585}
1586
1587/*
1588%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1589% %
1590% %
1591% %
cristy3ed852e2009-09-05 21:47:34 +00001592+ 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 %
1593% %
1594% %
1595% %
1596%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1597%
1598% GetAuthenticIndexesFromCache() returns the indexes associated with the last
1599% call to QueueAuthenticPixelsCache() or GetAuthenticPixelsCache().
1600%
1601% The format of the GetAuthenticIndexesFromCache() method is:
1602%
1603% IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1604%
1605% A description of each parameter follows:
1606%
1607% o image: the image.
1608%
1609*/
1610static IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1611{
1612 CacheInfo
1613 *cache_info;
1614
cristy5c9e6f22010-09-17 17:31:01 +00001615 const int
1616 id = GetOpenMPThreadId();
1617
cristy3ed852e2009-09-05 21:47:34 +00001618 IndexPacket
1619 *indexes;
1620
cristy3ed852e2009-09-05 21:47:34 +00001621 cache_info=(CacheInfo *) image->cache;
cristy6ebe97c2010-07-03 01:17:28 +00001622 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001623 indexes=GetPixelCacheNexusIndexes(image->cache,cache_info->nexus_info[id]);
1624 return(indexes);
1625}
1626
1627/*
1628%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1629% %
1630% %
1631% %
1632% G e t A u t h e n t i c I n d e x Q u e u e %
1633% %
1634% %
1635% %
1636%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1637%
1638% GetAuthenticIndexQueue() returns the authentic black channel or the colormap
1639% indexes associated with the last call to QueueAuthenticPixels() or
1640% GetVirtualPixels(). NULL is returned if the black channel or colormap
1641% indexes are not available.
1642%
1643% The format of the GetAuthenticIndexQueue() method is:
1644%
1645% IndexPacket *GetAuthenticIndexQueue(const Image *image)
1646%
1647% A description of each parameter follows:
1648%
1649% o image: the image.
1650%
1651*/
1652MagickExport IndexPacket *GetAuthenticIndexQueue(const Image *image)
1653{
1654 CacheInfo
1655 *cache_info;
1656
1657 assert(image != (const Image *) NULL);
1658 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001659 assert(image->cache != (Cache) NULL);
1660 cache_info=(CacheInfo *) image->cache;
1661 assert(cache_info->signature == MagickSignature);
1662 if (cache_info->methods.get_authentic_indexes_from_handler ==
1663 (GetAuthenticIndexesFromHandler) NULL)
1664 return((IndexPacket *) NULL);
1665 return(cache_info->methods.get_authentic_indexes_from_handler(image));
1666}
1667
1668/*
1669%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1670% %
1671% %
1672% %
1673+ 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 %
1674% %
1675% %
1676% %
1677%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1678%
1679% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1680% disk pixel cache as defined by the geometry parameters. A pointer to the
1681% pixels is returned if the pixels are transferred, otherwise a NULL is
1682% returned.
1683%
1684% The format of the GetAuthenticPixelCacheNexus() method is:
1685%
cristybb503372010-05-27 20:51:26 +00001686% PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1687% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001688% NexusInfo *nexus_info,ExceptionInfo *exception)
1689%
1690% A description of each parameter follows:
1691%
1692% o image: the image.
1693%
1694% o x,y,columns,rows: These values define the perimeter of a region of
1695% pixels.
1696%
1697% o nexus_info: the cache nexus to return.
1698%
1699% o exception: return any errors or warnings in this structure.
1700%
1701*/
1702
1703static inline MagickBooleanType IsNexusInCore(const CacheInfo *cache_info,
1704 NexusInfo *nexus_info)
1705{
1706 MagickOffsetType
1707 offset;
1708
cristy73724512010-04-12 14:43:14 +00001709 if (cache_info->type == PingCache)
1710 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001711 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1712 nexus_info->region.x;
1713 if (nexus_info->pixels != (cache_info->pixels+offset))
1714 return(MagickFalse);
1715 return(MagickTrue);
1716}
1717
cristye076a6e2010-08-15 19:59:43 +00001718MagickExport PixelPacket *GetAuthenticPixelCacheNexus(Image *image,
1719 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001720 NexusInfo *nexus_info,ExceptionInfo *exception)
1721{
1722 CacheInfo
1723 *cache_info;
1724
1725 PixelPacket
1726 *pixels;
1727
1728 /*
1729 Transfer pixels from the cache.
1730 */
1731 assert(image != (Image *) NULL);
1732 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001733 pixels=QueueAuthenticNexus(image,x,y,columns,rows,nexus_info,exception);
1734 if (pixels == (PixelPacket *) NULL)
1735 return((PixelPacket *) NULL);
1736 cache_info=(CacheInfo *) image->cache;
1737 assert(cache_info->signature == MagickSignature);
1738 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
1739 return(pixels);
1740 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1741 return((PixelPacket *) NULL);
1742 if (cache_info->active_index_channel != MagickFalse)
1743 if (ReadPixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse)
1744 return((PixelPacket *) NULL);
1745 return(pixels);
1746}
1747
1748/*
1749%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1750% %
1751% %
1752% %
1753+ 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 %
1754% %
1755% %
1756% %
1757%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1758%
1759% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1760% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1761%
1762% The format of the GetAuthenticPixelsFromCache() method is:
1763%
1764% PixelPacket *GetAuthenticPixelsFromCache(const Image image)
1765%
1766% A description of each parameter follows:
1767%
1768% o image: the image.
1769%
1770*/
1771static PixelPacket *GetAuthenticPixelsFromCache(const Image *image)
1772{
1773 CacheInfo
1774 *cache_info;
1775
cristy5c9e6f22010-09-17 17:31:01 +00001776 const int
1777 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001778
1779 PixelPacket
1780 *pixels;
1781
cristy3ed852e2009-09-05 21:47:34 +00001782 cache_info=(CacheInfo *) image->cache;
cristy6ebe97c2010-07-03 01:17:28 +00001783 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001784 pixels=GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]);
1785 return(pixels);
1786}
1787
1788/*
1789%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1790% %
1791% %
1792% %
1793% G e t A u t h e n t i c P i x e l Q u e u e %
1794% %
1795% %
1796% %
1797%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1798%
1799% GetAuthenticPixelQueue() returns the authentic pixels associated with the
1800% last call to QueueAuthenticPixels() or GetAuthenticPixels().
1801%
1802% The format of the GetAuthenticPixelQueue() method is:
1803%
1804% PixelPacket *GetAuthenticPixelQueue(const Image image)
1805%
1806% A description of each parameter follows:
1807%
1808% o image: the image.
1809%
1810*/
1811MagickExport PixelPacket *GetAuthenticPixelQueue(const Image *image)
1812{
1813 CacheInfo
1814 *cache_info;
1815
1816 assert(image != (const Image *) NULL);
1817 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001818 assert(image->cache != (Cache) NULL);
1819 cache_info=(CacheInfo *) image->cache;
1820 assert(cache_info->signature == MagickSignature);
1821 if (cache_info->methods.get_authentic_pixels_from_handler ==
1822 (GetAuthenticPixelsFromHandler) NULL)
1823 return((PixelPacket *) NULL);
1824 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1825}
1826
1827/*
1828%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1829% %
1830% %
1831% %
1832% G e t A u t h e n t i c P i x e l s %
1833% %
1834% %
1835% %
1836%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1837%
1838% GetAuthenticPixels() obtains a pixel region for read/write access. If the
1839% region is successfully accessed, a pointer to a PixelPacket array
1840% representing the region is returned, otherwise NULL is returned.
1841%
1842% The returned pointer may point to a temporary working copy of the pixels
1843% or it may point to the original pixels in memory. Performance is maximized
1844% if the selected region is part of one row, or one or more full rows, since
1845% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001846% if the image is in memory, or in a memory-mapped file. The returned pointer
1847% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001848%
1849% Pixels accessed via the returned pointer represent a simple array of type
1850% PixelPacket. If the image type is CMYK or if the storage class is
1851% PseduoClass, call GetAuthenticIndexQueue() after invoking
1852% GetAuthenticPixels() to obtain the black color component or colormap indexes
1853% (of type IndexPacket) corresponding to the region. Once the PixelPacket
1854% (and/or IndexPacket) array has been updated, the changes must be saved back
1855% to the underlying image using SyncAuthenticPixels() or they may be lost.
1856%
1857% The format of the GetAuthenticPixels() method is:
1858%
cristy5f959472010-05-27 22:19:46 +00001859% PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1860% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001861% ExceptionInfo *exception)
1862%
1863% A description of each parameter follows:
1864%
1865% o image: the image.
1866%
1867% o x,y,columns,rows: These values define the perimeter of a region of
1868% pixels.
1869%
1870% o exception: return any errors or warnings in this structure.
1871%
1872*/
cristybb503372010-05-27 20:51:26 +00001873MagickExport PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1874 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001875 ExceptionInfo *exception)
1876{
1877 CacheInfo
1878 *cache_info;
1879
1880 PixelPacket
1881 *pixels;
1882
1883 assert(image != (Image *) NULL);
1884 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001885 assert(image->cache != (Cache) NULL);
1886 cache_info=(CacheInfo *) image->cache;
1887 assert(cache_info->signature == MagickSignature);
1888 if (cache_info->methods.get_authentic_pixels_handler ==
1889 (GetAuthenticPixelsHandler) NULL)
1890 return((PixelPacket *) NULL);
1891 pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1892 rows,exception);
1893 return(pixels);
1894}
1895
1896/*
1897%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1898% %
1899% %
1900% %
1901+ G e t A u t h e n t i c P i x e l s C a c h e %
1902% %
1903% %
1904% %
1905%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1906%
1907% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1908% as defined by the geometry parameters. A pointer to the pixels is returned
1909% if the pixels are transferred, otherwise a NULL is returned.
1910%
1911% The format of the GetAuthenticPixelsCache() method is:
1912%
cristybb503372010-05-27 20:51:26 +00001913% PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1914% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001915% ExceptionInfo *exception)
1916%
1917% A description of each parameter follows:
1918%
1919% o image: the image.
1920%
1921% o x,y,columns,rows: These values define the perimeter of a region of
1922% pixels.
1923%
1924% o exception: return any errors or warnings in this structure.
1925%
1926*/
cristybb503372010-05-27 20:51:26 +00001927static PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1928 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001929 ExceptionInfo *exception)
1930{
1931 CacheInfo
1932 *cache_info;
1933
cristy5c9e6f22010-09-17 17:31:01 +00001934 const int
1935 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001936
1937 PixelPacket
1938 *pixels;
1939
cristy77ff0282010-09-13 00:51:10 +00001940 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001941 if (cache_info == (Cache) NULL)
1942 return((PixelPacket *) NULL);
cristy6ebe97c2010-07-03 01:17:28 +00001943 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001944 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1945 cache_info->nexus_info[id],exception);
1946 return(pixels);
1947}
1948
1949/*
1950%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1951% %
1952% %
1953% %
1954+ G e t I m a g e E x t e n t %
1955% %
1956% %
1957% %
1958%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1959%
1960% GetImageExtent() returns the extent of the pixels associated with the
1961% last call to QueueAuthenticPixels() or GetAuthenticPixels().
1962%
1963% The format of the GetImageExtent() method is:
1964%
1965% MagickSizeType GetImageExtent(const Image *image)
1966%
1967% A description of each parameter follows:
1968%
1969% o image: the image.
1970%
1971*/
1972MagickExport MagickSizeType GetImageExtent(const Image *image)
1973{
1974 CacheInfo
1975 *cache_info;
1976
cristy5c9e6f22010-09-17 17:31:01 +00001977 const int
1978 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001979
1980 MagickSizeType
1981 extent;
1982
1983 assert(image != (Image *) NULL);
1984 assert(image->signature == MagickSignature);
1985 if (image->debug != MagickFalse)
1986 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1987 assert(image->cache != (Cache) NULL);
1988 cache_info=(CacheInfo *) image->cache;
1989 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001990 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001991 extent=GetPixelCacheNexusExtent(image->cache,cache_info->nexus_info[id]);
1992 return(extent);
1993}
1994
1995/*
1996%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1997% %
1998% %
1999% %
2000+ G e t I m a g e P i x e l C a c h e %
2001% %
2002% %
2003% %
2004%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2005%
2006% GetImagePixelCache() ensures that there is only a single reference to the
2007% pixel cache to be modified, updating the provided cache pointer to point to
2008% a clone of the original pixel cache if necessary.
2009%
2010% The format of the GetImagePixelCache method is:
2011%
2012% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2013% ExceptionInfo *exception)
2014%
2015% A description of each parameter follows:
2016%
2017% o image: the image.
2018%
2019% o clone: any value other than MagickFalse clones the cache pixels.
2020%
2021% o exception: return any errors or warnings in this structure.
2022%
2023*/
cristy3ed852e2009-09-05 21:47:34 +00002024static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
2025{
2026 CacheInfo
2027 *cache_info;
2028
2029 /*
2030 Does the image match the pixel cache morphology?
2031 */
2032 cache_info=(CacheInfo *) image->cache;
2033 if ((image->storage_class != cache_info->storage_class) ||
2034 (image->colorspace != cache_info->colorspace) ||
2035 (image->columns != cache_info->columns) ||
2036 (image->rows != cache_info->rows) ||
2037 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2038 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2039 return(MagickFalse);
2040 return(MagickTrue);
2041}
2042
cristy77ff0282010-09-13 00:51:10 +00002043static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2044 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002045{
2046 CacheInfo
2047 *cache_info;
2048
cristy3ed852e2009-09-05 21:47:34 +00002049 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00002050 destroy,
cristy3ed852e2009-09-05 21:47:34 +00002051 status;
2052
cristy50a10922010-02-15 18:35:25 +00002053 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00002054 cpu_throttle = 0,
2055 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00002056 time_limit = 0;
2057
cristy1ea34962010-07-01 19:49:21 +00002058 static time_t
cristya21afde2010-07-02 00:45:40 +00002059 cache_genesis = 0;
cristy1ea34962010-07-01 19:49:21 +00002060
cristyc4f9f132010-03-04 18:50:01 +00002061 status=MagickTrue;
2062 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00002063 if (cpu_throttle == 0)
2064 {
2065 char
2066 *limit;
2067
2068 /*
2069 Set CPU throttle in milleseconds.
2070 */
2071 cpu_throttle=MagickResourceInfinity;
2072 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2073 if (limit == (char *) NULL)
2074 limit=GetPolicyValue("throttle");
2075 if (limit != (char *) NULL)
2076 {
2077 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2078 limit=DestroyString(limit);
2079 }
2080 }
2081 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2082 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00002083 if (time_limit == 0)
2084 {
cristy6ebe97c2010-07-03 01:17:28 +00002085 /*
2086 Set the exire time in seconds.
2087 */
cristy1ea34962010-07-01 19:49:21 +00002088 time_limit=GetMagickResourceLimit(TimeResource);
cristya21afde2010-07-02 00:45:40 +00002089 cache_genesis=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00002090 }
2091 if ((time_limit != MagickResourceInfinity) &&
cristya21afde2010-07-02 00:45:40 +00002092 ((MagickSizeType) (time((time_t *) NULL)-cache_genesis) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00002093 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00002094 assert(image->cache != (Cache) NULL);
2095 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002096 destroy=MagickFalse;
cristy01b7eb02009-09-10 23:10:14 +00002097 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002098 {
cristyaaa0cb62010-02-15 17:47:27 +00002099 LockSemaphoreInfo(cache_info->semaphore);
2100 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002101 {
cristyaaa0cb62010-02-15 17:47:27 +00002102 Image
2103 clone_image;
2104
2105 CacheInfo
2106 *clone_info;
2107
2108 /*
2109 Clone pixel cache.
2110 */
2111 clone_image=(*image);
cristy93505cf2010-08-10 21:37:49 +00002112 clone_image.semaphore=AllocateSemaphoreInfo();
2113 clone_image.reference_count=1;
cristyaaa0cb62010-02-15 17:47:27 +00002114 clone_image.cache=ClonePixelCache(cache_info);
2115 clone_info=(CacheInfo *) clone_image.cache;
cristyabd6e372010-09-15 19:11:26 +00002116 status=OpenPixelCache(&clone_image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00002117 if (status != MagickFalse)
2118 {
cristyabd6e372010-09-15 19:11:26 +00002119 if (clone != MagickFalse)
2120 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00002121 if (status != MagickFalse)
2122 {
cristyabd6e372010-09-15 19:11:26 +00002123 destroy=MagickTrue;
2124 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00002125 }
2126 }
cristy93505cf2010-08-10 21:37:49 +00002127 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002128 }
cristyaaa0cb62010-02-15 17:47:27 +00002129 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002130 }
cristy4320e0e2009-09-10 15:00:08 +00002131 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002132 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002133 if (status != MagickFalse)
2134 {
2135 /*
2136 Ensure the image matches the pixel cache morphology.
2137 */
2138 image->taint=MagickTrue;
2139 image->type=UndefinedType;
cristydd438462010-05-06 13:44:04 +00002140 if (image->colorspace == GRAYColorspace)
2141 image->colorspace=RGBColorspace;
cristy3ed852e2009-09-05 21:47:34 +00002142 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2143 status=OpenPixelCache(image,IOMode,exception);
2144 }
cristyf84a1932010-01-03 18:00:18 +00002145 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002146 if (status == MagickFalse)
2147 return((Cache) NULL);
2148 return(image->cache);
2149}
2150
2151/*
2152%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2153% %
2154% %
2155% %
2156% G e t O n e A u t h e n t i c P i x e l %
2157% %
2158% %
2159% %
2160%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2161%
2162% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2163% location. The image background color is returned if an error occurs.
2164%
2165% The format of the GetOneAuthenticPixel() method is:
2166%
cristybb503372010-05-27 20:51:26 +00002167% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2168% const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002169%
2170% A description of each parameter follows:
2171%
2172% o image: the image.
2173%
2174% o x,y: These values define the location of the pixel to return.
2175%
2176% o pixel: return a pixel at the specified (x,y) location.
2177%
2178% o exception: return any errors or warnings in this structure.
2179%
2180*/
cristyacbbb7c2010-06-30 18:56:48 +00002181MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2182 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002183{
2184 CacheInfo
2185 *cache_info;
2186
2187 GetOneAuthenticPixelFromHandler
2188 get_one_authentic_pixel_from_handler;
2189
2190 MagickBooleanType
2191 status;
2192
2193 assert(image != (Image *) NULL);
2194 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002195 assert(image->cache != (Cache) NULL);
2196 cache_info=(CacheInfo *) image->cache;
2197 assert(cache_info->signature == MagickSignature);
2198 *pixel=image->background_color;
2199 get_one_authentic_pixel_from_handler=
2200 cache_info->methods.get_one_authentic_pixel_from_handler;
2201 if (get_one_authentic_pixel_from_handler ==
2202 (GetOneAuthenticPixelFromHandler) NULL)
2203 return(MagickFalse);
2204 status=cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2205 pixel,exception);
2206 return(status);
2207}
2208
2209/*
2210%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2211% %
2212% %
2213% %
2214+ 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 %
2215% %
2216% %
2217% %
2218%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2219%
2220% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2221% location. The image background color is returned if an error occurs.
2222%
2223% The format of the GetOneAuthenticPixelFromCache() method is:
2224%
2225% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy5f959472010-05-27 22:19:46 +00002226% const ssize_t x,const ssize_t y,PixelPacket *pixel,
2227% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002228%
2229% A description of each parameter follows:
2230%
2231% o image: the image.
2232%
2233% o x,y: These values define the location of the pixel to return.
2234%
2235% o pixel: return a pixel at the specified (x,y) location.
2236%
2237% o exception: return any errors or warnings in this structure.
2238%
2239*/
2240static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristybb503372010-05-27 20:51:26 +00002241 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002242{
2243 PixelPacket
2244 *pixels;
2245
cristy3ed852e2009-09-05 21:47:34 +00002246 *pixel=image->background_color;
2247 pixels=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2248 if (pixels == (PixelPacket *) NULL)
2249 return(MagickFalse);
2250 *pixel=(*pixels);
2251 return(MagickTrue);
2252}
2253
2254/*
2255%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2256% %
2257% %
2258% %
2259% G e t O n e V i r t u a l M a g i c k P i x e l %
2260% %
2261% %
2262% %
2263%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2264%
2265% GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2266% location. The image background color is returned if an error occurs. If
2267% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2268%
2269% The format of the GetOneVirtualMagickPixel() method is:
2270%
2271% MagickBooleanType GetOneVirtualMagickPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002272% const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
cristy3ed852e2009-09-05 21:47:34 +00002273% ExceptionInfo exception)
2274%
2275% A description of each parameter follows:
2276%
2277% o image: the image.
2278%
2279% o x,y: these values define the location of the pixel to return.
2280%
2281% o pixel: return a pixel at the specified (x,y) location.
2282%
2283% o exception: return any errors or warnings in this structure.
2284%
2285*/
2286MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
cristyacbbb7c2010-06-30 18:56:48 +00002287 const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
2288 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002289{
2290 CacheInfo
2291 *cache_info;
2292
2293 register const IndexPacket
2294 *indexes;
2295
2296 register const PixelPacket
2297 *p;
2298
2299 assert(image != (const Image *) NULL);
2300 assert(image->signature == MagickSignature);
2301 assert(image->cache != (Cache) NULL);
2302 cache_info=(CacheInfo *) image->cache;
2303 assert(cache_info->signature == MagickSignature);
2304 GetMagickPixelPacket(image,pixel);
2305 p=GetVirtualPixelCache(image,GetPixelCacheVirtualMethod(image),x,y,1,1,
2306 exception);
2307 if (p == (const PixelPacket *) NULL)
2308 return(MagickFalse);
2309 indexes=GetVirtualIndexQueue(image);
2310 SetMagickPixelPacket(image,p,indexes,pixel);
2311 return(MagickTrue);
2312}
2313
2314/*
2315%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2316% %
2317% %
2318% %
2319% G e t O n e V i r t u a l M e t h o d P i x e l %
2320% %
2321% %
2322% %
2323%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2324%
2325% GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2326% location as defined by specified pixel method. The image background color
2327% is returned if an error occurs. If you plan to modify the pixel, use
2328% GetOneAuthenticPixel() instead.
2329%
2330% The format of the GetOneVirtualMethodPixel() method is:
2331%
2332% MagickBooleanType GetOneVirtualMethodPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002333% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2334% const ssize_t y,Pixelpacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002335%
2336% A description of each parameter follows:
2337%
2338% o image: the image.
2339%
2340% o virtual_pixel_method: the virtual pixel method.
2341%
2342% o x,y: These values define the location of the pixel to return.
2343%
2344% o pixel: return a pixel at the specified (x,y) location.
2345%
2346% o exception: return any errors or warnings in this structure.
2347%
2348*/
2349MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002350 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002351 PixelPacket *pixel,ExceptionInfo *exception)
2352{
2353 GetOneVirtualPixelFromHandler
2354 get_one_virtual_pixel_from_handler;
2355
2356 CacheInfo
2357 *cache_info;
2358
2359 MagickBooleanType
2360 status;
2361
2362 assert(image != (const Image *) NULL);
2363 assert(image->signature == MagickSignature);
2364 assert(image->cache != (Cache) NULL);
2365 cache_info=(CacheInfo *) image->cache;
2366 assert(cache_info->signature == MagickSignature);
2367 *pixel=image->background_color;
2368 get_one_virtual_pixel_from_handler=
2369 cache_info->methods.get_one_virtual_pixel_from_handler;
2370 if (get_one_virtual_pixel_from_handler ==
2371 (GetOneVirtualPixelFromHandler) NULL)
2372 return(MagickFalse);
2373 status=get_one_virtual_pixel_from_handler(image,virtual_pixel_method,x,y,
2374 pixel,exception);
2375 return(status);
2376}
2377
2378/*
2379%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2380% %
2381% %
2382% %
2383% G e t O n e V i r t u a l P i x e l %
2384% %
2385% %
2386% %
2387%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2388%
2389% GetOneVirtualPixel() returns a single virtual pixel at the specified
2390% (x,y) location. The image background color is returned if an error occurs.
2391% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2392%
2393% The format of the GetOneVirtualPixel() method is:
2394%
cristybb503372010-05-27 20:51:26 +00002395% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2396% const ssize_t y,PixelPacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002397%
2398% A description of each parameter follows:
2399%
2400% o image: the image.
2401%
2402% o x,y: These values define the location of the pixel to return.
2403%
2404% o pixel: return a pixel at the specified (x,y) location.
2405%
2406% o exception: return any errors or warnings in this structure.
2407%
2408*/
2409MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002410 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002411{
2412 GetOneVirtualPixelFromHandler
2413 get_one_virtual_pixel_from_handler;
2414
2415 CacheInfo
2416 *cache_info;
2417
2418 MagickBooleanType
2419 status;
2420
2421 assert(image != (const Image *) NULL);
2422 assert(image->signature == MagickSignature);
2423 assert(image->cache != (Cache) NULL);
2424 cache_info=(CacheInfo *) image->cache;
2425 assert(cache_info->signature == MagickSignature);
2426 *pixel=image->background_color;
2427 get_one_virtual_pixel_from_handler=
2428 cache_info->methods.get_one_virtual_pixel_from_handler;
2429 if (get_one_virtual_pixel_from_handler ==
2430 (GetOneVirtualPixelFromHandler) NULL)
2431 return(MagickFalse);
2432 status=get_one_virtual_pixel_from_handler(image,GetPixelCacheVirtualMethod(
2433 image),x,y,pixel,exception);
2434 return(status);
2435}
2436
2437/*
2438%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2439% %
2440% %
2441% %
2442+ 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 %
2443% %
2444% %
2445% %
2446%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2447%
2448% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2449% specified (x,y) location. The image background color is returned if an
2450% error occurs.
2451%
2452% The format of the GetOneVirtualPixelFromCache() method is:
2453%
2454% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristybb503372010-05-27 20:51:26 +00002455% const VirtualPixelPacket method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002456% PixelPacket *pixel,ExceptionInfo *exception)
2457%
2458% A description of each parameter follows:
2459%
2460% o image: the image.
2461%
2462% o virtual_pixel_method: the virtual pixel method.
2463%
2464% o x,y: These values define the location of the pixel to return.
2465%
2466% o pixel: return a pixel at the specified (x,y) location.
2467%
2468% o exception: return any errors or warnings in this structure.
2469%
2470*/
2471static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002472 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002473 PixelPacket *pixel,ExceptionInfo *exception)
2474{
2475 const PixelPacket
2476 *pixels;
2477
2478 *pixel=image->background_color;
2479 pixels=GetVirtualPixelCache(image,virtual_pixel_method,x,y,1UL,1UL,exception);
2480 if (pixels == (const PixelPacket *) NULL)
2481 return(MagickFalse);
2482 *pixel=(*pixels);
2483 return(MagickTrue);
2484}
2485
2486/*
2487%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2488% %
2489% %
2490% %
2491+ G e t P i x e l C a c h e C o l o r s p a c e %
2492% %
2493% %
2494% %
2495%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2496%
2497% GetPixelCacheColorspace() returns the class type of the pixel cache.
2498%
2499% The format of the GetPixelCacheColorspace() method is:
2500%
2501% Colorspace GetPixelCacheColorspace(Cache cache)
2502%
2503% A description of each parameter follows:
2504%
2505% o cache: the pixel cache.
2506%
2507*/
2508MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
2509{
2510 CacheInfo
2511 *cache_info;
2512
2513 assert(cache != (Cache) NULL);
2514 cache_info=(CacheInfo *) cache;
2515 assert(cache_info->signature == MagickSignature);
2516 if (cache_info->debug != MagickFalse)
2517 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2518 cache_info->filename);
2519 return(cache_info->colorspace);
2520}
2521
2522/*
2523%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2524% %
2525% %
2526% %
2527+ G e t P i x e l C a c h e M e t h o d s %
2528% %
2529% %
2530% %
2531%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2532%
2533% GetPixelCacheMethods() initializes the CacheMethods structure.
2534%
2535% The format of the GetPixelCacheMethods() method is:
2536%
2537% void GetPixelCacheMethods(CacheMethods *cache_methods)
2538%
2539% A description of each parameter follows:
2540%
2541% o cache_methods: Specifies a pointer to a CacheMethods structure.
2542%
2543*/
2544MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
2545{
2546 assert(cache_methods != (CacheMethods *) NULL);
2547 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2548 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2549 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2550 cache_methods->get_virtual_indexes_from_handler=GetVirtualIndexesFromCache;
2551 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2552 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2553 cache_methods->get_authentic_indexes_from_handler=
2554 GetAuthenticIndexesFromCache;
2555 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2556 cache_methods->get_one_authentic_pixel_from_handler=
2557 GetOneAuthenticPixelFromCache;
2558 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2559 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2560 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2561}
2562
2563/*
2564%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2565% %
2566% %
2567% %
2568+ G e t P i x e l C a c h e N e x u s E x t e n t %
2569% %
2570% %
2571% %
2572%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2573%
2574% GetPixelCacheNexusExtent() returns the extent of the pixels associated with
2575% the last call to SetPixelCacheNexusPixels() or GetPixelCacheNexusPixels().
2576%
2577% The format of the GetPixelCacheNexusExtent() method is:
2578%
2579% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2580% NexusInfo *nexus_info)
2581%
2582% A description of each parameter follows:
2583%
2584% o nexus_info: the nexus info.
2585%
2586*/
2587MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2588 NexusInfo *nexus_info)
2589{
2590 CacheInfo
2591 *cache_info;
2592
2593 MagickSizeType
2594 extent;
2595
2596 if (cache == (Cache) NULL)
2597 return(0);
2598 cache_info=(CacheInfo *) cache;
2599 assert(cache_info->signature == MagickSignature);
2600 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2601 if (extent == 0)
2602 return((MagickSizeType) cache_info->columns*cache_info->rows);
2603 return(extent);
2604}
2605
2606/*
2607%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2608% %
2609% %
2610% %
2611+ 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 %
2612% %
2613% %
2614% %
2615%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2616%
2617% GetPixelCacheNexusIndexes() returns the indexes associated with the
2618% specified cache nexus.
2619%
2620% The format of the GetPixelCacheNexusIndexes() method is:
2621%
2622% IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2623% NexusInfo *nexus_info)
2624%
2625% A description of each parameter follows:
2626%
2627% o cache: the pixel cache.
2628%
2629% o nexus_info: the cache nexus to return the colormap indexes.
2630%
2631*/
2632MagickExport IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2633 NexusInfo *nexus_info)
2634{
2635 CacheInfo
2636 *cache_info;
2637
2638 if (cache == (Cache) NULL)
2639 return((IndexPacket *) NULL);
2640 cache_info=(CacheInfo *) cache;
2641 assert(cache_info->signature == MagickSignature);
2642 if (cache_info->storage_class == UndefinedClass)
2643 return((IndexPacket *) NULL);
2644 return(nexus_info->indexes);
2645}
2646
2647/*
2648%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2649% %
2650% %
2651% %
2652+ G e t P i x e l C a c h e N e x u s P i x e l s %
2653% %
2654% %
2655% %
2656%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2657%
2658% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2659% cache nexus.
2660%
2661% The format of the GetPixelCacheNexusPixels() method is:
2662%
2663% PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2664% NexusInfo *nexus_info)
2665%
2666% A description of each parameter follows:
2667%
2668% o cache: the pixel cache.
2669%
2670% o nexus_info: the cache nexus to return the pixels.
2671%
2672*/
2673MagickExport PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2674 NexusInfo *nexus_info)
2675{
2676 CacheInfo
2677 *cache_info;
2678
2679 if (cache == (Cache) NULL)
2680 return((PixelPacket *) NULL);
2681 cache_info=(CacheInfo *) cache;
2682 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002683 if (cache_info->storage_class == UndefinedClass)
2684 return((PixelPacket *) NULL);
2685 return(nexus_info->pixels);
2686}
2687
2688/*
2689%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2690% %
2691% %
2692% %
cristy056ba772010-01-02 23:33:54 +00002693+ G e t P i x e l C a c h e P i x e l s %
2694% %
2695% %
2696% %
2697%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2698%
2699% GetPixelCachePixels() returns the pixels associated with the specified image.
2700%
2701% The format of the GetPixelCachePixels() method is:
2702%
cristyf84a1932010-01-03 18:00:18 +00002703% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2704% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002705%
2706% A description of each parameter follows:
2707%
2708% o image: the image.
2709%
2710% o length: the pixel cache length.
2711%
cristyf84a1932010-01-03 18:00:18 +00002712% o exception: return any errors or warnings in this structure.
2713%
cristy056ba772010-01-02 23:33:54 +00002714*/
cristyf84a1932010-01-03 18:00:18 +00002715MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2716 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002717{
2718 CacheInfo
2719 *cache_info;
2720
2721 assert(image != (const Image *) NULL);
2722 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002723 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00002724 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002725 assert(cache_info->signature == MagickSignature);
2726 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002727 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002728 return((void *) NULL);
2729 *length=cache_info->length;
2730 return((void *) cache_info->pixels);
2731}
2732
2733/*
2734%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2735% %
2736% %
2737% %
cristyb32b90a2009-09-07 21:45:48 +00002738+ 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 +00002739% %
2740% %
2741% %
2742%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2743%
2744% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2745%
2746% The format of the GetPixelCacheStorageClass() method is:
2747%
2748% ClassType GetPixelCacheStorageClass(Cache cache)
2749%
2750% A description of each parameter follows:
2751%
2752% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2753%
2754% o cache: the pixel cache.
2755%
2756*/
2757MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
2758{
2759 CacheInfo
2760 *cache_info;
2761
2762 assert(cache != (Cache) NULL);
2763 cache_info=(CacheInfo *) cache;
2764 assert(cache_info->signature == MagickSignature);
2765 if (cache_info->debug != MagickFalse)
2766 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2767 cache_info->filename);
2768 return(cache_info->storage_class);
2769}
2770
2771/*
2772%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2773% %
2774% %
2775% %
cristyb32b90a2009-09-07 21:45:48 +00002776+ G e t P i x e l C a c h e T i l e S i z e %
2777% %
2778% %
2779% %
2780%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2781%
2782% GetPixelCacheTileSize() returns the pixel cache tile size.
2783%
2784% The format of the GetPixelCacheTileSize() method is:
2785%
cristybb503372010-05-27 20:51:26 +00002786% void GetPixelCacheTileSize(const Image *image,size_t *width,
2787% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002788%
2789% A description of each parameter follows:
2790%
2791% o image: the image.
2792%
2793% o width: the optimize cache tile width in pixels.
2794%
2795% o height: the optimize cache tile height in pixels.
2796%
2797*/
cristybb503372010-05-27 20:51:26 +00002798MagickExport void GetPixelCacheTileSize(const Image *image,size_t *width,
2799 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002800{
2801 CacheInfo
2802 *cache_info;
2803
2804 assert(image != (Image *) NULL);
2805 assert(image->signature == MagickSignature);
2806 if (image->debug != MagickFalse)
2807 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2808 assert(image->cache != (Cache) NULL);
2809 cache_info=(CacheInfo *) image->cache;
2810 assert(cache_info->signature == MagickSignature);
2811 *width=2048UL/sizeof(PixelPacket);
2812 if (GetPixelCacheType(image) == DiskCache)
cristydaa97692009-09-13 02:10:35 +00002813 *width=8192UL/sizeof(PixelPacket);
cristyb32b90a2009-09-07 21:45:48 +00002814 *height=(*width);
2815}
2816
2817/*
2818%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2819% %
2820% %
2821% %
2822+ G e t P i x e l C a c h e T y p e %
2823% %
2824% %
2825% %
2826%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2827%
2828% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2829%
2830% The format of the GetPixelCacheType() method is:
2831%
2832% CacheType GetPixelCacheType(const Image *image)
2833%
2834% A description of each parameter follows:
2835%
2836% o image: the image.
2837%
2838*/
2839MagickExport CacheType GetPixelCacheType(const Image *image)
2840{
2841 CacheInfo
2842 *cache_info;
2843
2844 assert(image != (Image *) NULL);
2845 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002846 assert(image->cache != (Cache) NULL);
2847 cache_info=(CacheInfo *) image->cache;
2848 assert(cache_info->signature == MagickSignature);
2849 return(cache_info->type);
2850}
2851
2852/*
2853%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2854% %
2855% %
2856% %
cristy3ed852e2009-09-05 21:47:34 +00002857+ 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 %
2858% %
2859% %
2860% %
2861%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2862%
2863% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2864% pixel cache. A virtual pixel is any pixel access that is outside the
2865% boundaries of the image cache.
2866%
2867% The format of the GetPixelCacheVirtualMethod() method is:
2868%
2869% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2870%
2871% A description of each parameter follows:
2872%
2873% o image: the image.
2874%
2875*/
2876MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2877{
2878 CacheInfo
2879 *cache_info;
2880
2881 assert(image != (Image *) NULL);
2882 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002883 assert(image->cache != (Cache) NULL);
2884 cache_info=(CacheInfo *) image->cache;
2885 assert(cache_info->signature == MagickSignature);
2886 return(cache_info->virtual_pixel_method);
2887}
2888
2889/*
2890%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2891% %
2892% %
2893% %
2894+ 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 %
2895% %
2896% %
2897% %
2898%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2899%
2900% GetVirtualIndexesFromCache() returns the indexes associated with the last
2901% call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2902%
2903% The format of the GetVirtualIndexesFromCache() method is:
2904%
2905% IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2906%
2907% A description of each parameter follows:
2908%
2909% o image: the image.
2910%
2911*/
2912static const IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2913{
2914 CacheInfo
2915 *cache_info;
2916
2917 const IndexPacket
2918 *indexes;
2919
cristy5c9e6f22010-09-17 17:31:01 +00002920 const int
2921 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002922
cristy3ed852e2009-09-05 21:47:34 +00002923 cache_info=(CacheInfo *) image->cache;
cristy6ebe97c2010-07-03 01:17:28 +00002924 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00002925 indexes=GetVirtualIndexesFromNexus(image->cache,cache_info->nexus_info[id]);
2926 return(indexes);
2927}
2928
2929/*
2930%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2931% %
2932% %
2933% %
2934+ 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 %
2935% %
2936% %
2937% %
2938%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2939%
2940% GetVirtualIndexesFromNexus() returns the indexes associated with the
2941% specified cache nexus.
2942%
2943% The format of the GetVirtualIndexesFromNexus() method is:
2944%
2945% const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2946% NexusInfo *nexus_info)
2947%
2948% A description of each parameter follows:
2949%
2950% o cache: the pixel cache.
2951%
2952% o nexus_info: the cache nexus to return the colormap indexes.
2953%
2954*/
2955MagickExport const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2956 NexusInfo *nexus_info)
2957{
2958 CacheInfo
2959 *cache_info;
2960
2961 if (cache == (Cache) NULL)
2962 return((IndexPacket *) NULL);
2963 cache_info=(CacheInfo *) cache;
2964 assert(cache_info->signature == MagickSignature);
2965 if (cache_info->storage_class == UndefinedClass)
2966 return((IndexPacket *) NULL);
2967 return(nexus_info->indexes);
2968}
2969
2970/*
2971%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2972% %
2973% %
2974% %
2975% G e t V i r t u a l I n d e x Q u e u e %
2976% %
2977% %
2978% %
2979%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2980%
2981% GetVirtualIndexQueue() returns the virtual black channel or the
2982% colormap indexes associated with the last call to QueueAuthenticPixels() or
2983% GetVirtualPixels(). NULL is returned if the black channel or colormap
2984% indexes are not available.
2985%
2986% The format of the GetVirtualIndexQueue() method is:
2987%
2988% const IndexPacket *GetVirtualIndexQueue(const Image *image)
2989%
2990% A description of each parameter follows:
2991%
2992% o image: the image.
2993%
2994*/
2995MagickExport const IndexPacket *GetVirtualIndexQueue(const Image *image)
2996{
2997 CacheInfo
2998 *cache_info;
2999
3000 assert(image != (const Image *) NULL);
3001 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003002 assert(image->cache != (Cache) NULL);
3003 cache_info=(CacheInfo *) image->cache;
3004 assert(cache_info->signature == MagickSignature);
3005 if (cache_info->methods.get_virtual_indexes_from_handler ==
3006 (GetVirtualIndexesFromHandler) NULL)
3007 return((IndexPacket *) NULL);
3008 return(cache_info->methods.get_virtual_indexes_from_handler(image));
3009}
3010
3011/*
3012%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3013% %
3014% %
3015% %
3016+ 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 %
3017% %
3018% %
3019% %
3020%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3021%
3022% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3023% pixel cache as defined by the geometry parameters. A pointer to the pixels
3024% is returned if the pixels are transferred, otherwise a NULL is returned.
3025%
3026% The format of the GetVirtualPixelsFromNexus() method is:
3027%
3028% PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003029% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00003030% const size_t columns,const size_t rows,NexusInfo *nexus_info,
3031% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003032%
3033% A description of each parameter follows:
3034%
3035% o image: the image.
3036%
3037% o virtual_pixel_method: the virtual pixel method.
3038%
3039% o x,y,columns,rows: These values define the perimeter of a region of
3040% pixels.
3041%
3042% o nexus_info: the cache nexus to acquire.
3043%
3044% o exception: return any errors or warnings in this structure.
3045%
3046*/
3047
cristybb503372010-05-27 20:51:26 +00003048static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003049 DitherMatrix[64] =
3050 {
3051 0, 48, 12, 60, 3, 51, 15, 63,
3052 32, 16, 44, 28, 35, 19, 47, 31,
3053 8, 56, 4, 52, 11, 59, 7, 55,
3054 40, 24, 36, 20, 43, 27, 39, 23,
3055 2, 50, 14, 62, 1, 49, 13, 61,
3056 34, 18, 46, 30, 33, 17, 45, 29,
3057 10, 58, 6, 54, 9, 57, 5, 53,
3058 42, 26, 38, 22, 41, 25, 37, 21
3059 };
3060
cristybb503372010-05-27 20:51:26 +00003061static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003062{
cristybb503372010-05-27 20:51:26 +00003063 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003064 index;
3065
3066 index=x+DitherMatrix[x & 0x07]-32L;
3067 if (index < 0L)
3068 return(0L);
cristybb503372010-05-27 20:51:26 +00003069 if (index >= (ssize_t) columns)
3070 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00003071 return(index);
3072}
3073
cristybb503372010-05-27 20:51:26 +00003074static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003075{
cristybb503372010-05-27 20:51:26 +00003076 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003077 index;
3078
3079 index=y+DitherMatrix[y & 0x07]-32L;
3080 if (index < 0L)
3081 return(0L);
cristybb503372010-05-27 20:51:26 +00003082 if (index >= (ssize_t) rows)
3083 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00003084 return(index);
3085}
3086
cristybb503372010-05-27 20:51:26 +00003087static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003088{
3089 if (x < 0L)
3090 return(0L);
cristybb503372010-05-27 20:51:26 +00003091 if (x >= (ssize_t) columns)
3092 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003093 return(x);
3094}
3095
cristybb503372010-05-27 20:51:26 +00003096static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003097{
3098 if (y < 0L)
3099 return(0L);
cristybb503372010-05-27 20:51:26 +00003100 if (y >= (ssize_t) rows)
3101 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003102 return(y);
3103}
3104
cristybb503372010-05-27 20:51:26 +00003105static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003106{
cristybb503372010-05-27 20:51:26 +00003107 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003108}
3109
cristybb503372010-05-27 20:51:26 +00003110static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003111{
cristybb503372010-05-27 20:51:26 +00003112 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003113}
3114
3115/*
3116 VirtualPixelModulo() computes the remainder of dividing offset by extent. It
3117 returns not only the quotient (tile the offset falls in) but also the positive
3118 remainer within that tile such that 0 <= remainder < extent. This method is
3119 essentially a ldiv() using a floored modulo division rather than the normal
3120 default truncated modulo division.
3121*/
cristybb503372010-05-27 20:51:26 +00003122static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3123 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003124{
3125 MagickModulo
3126 modulo;
3127
cristybb503372010-05-27 20:51:26 +00003128 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003129 if (offset < 0L)
3130 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003131 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003132 return(modulo);
3133}
3134
3135MagickExport const PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003136 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3137 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003138 ExceptionInfo *exception)
3139{
3140 CacheInfo
3141 *cache_info;
3142
cristyc3ec0d42010-04-07 01:18:08 +00003143 IndexPacket
3144 virtual_index;
3145
cristy3ed852e2009-09-05 21:47:34 +00003146 MagickOffsetType
3147 offset;
3148
3149 MagickSizeType
3150 length,
3151 number_pixels;
3152
3153 NexusInfo
3154 **virtual_nexus;
3155
3156 PixelPacket
3157 *pixels,
3158 virtual_pixel;
3159
3160 RectangleInfo
3161 region;
3162
3163 register const IndexPacket
cristyc3ec0d42010-04-07 01:18:08 +00003164 *restrict virtual_indexes;
cristy3ed852e2009-09-05 21:47:34 +00003165
3166 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003167 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003168
3169 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003170 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003171
cristye076a6e2010-08-15 19:59:43 +00003172 register PixelPacket
3173 *restrict q;
3174
cristybb503372010-05-27 20:51:26 +00003175 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003176 u,
3177 v;
3178
cristy3ed852e2009-09-05 21:47:34 +00003179 /*
3180 Acquire pixels.
3181 */
cristy3ed852e2009-09-05 21:47:34 +00003182 cache_info=(CacheInfo *) image->cache;
cristy4cfbb3f2010-03-14 20:40:23 +00003183 if (cache_info->type == UndefinedCache)
cristy3ed852e2009-09-05 21:47:34 +00003184 return((const PixelPacket *) NULL);
3185 region.x=x;
3186 region.y=y;
3187 region.width=columns;
3188 region.height=rows;
3189 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
3190 if (pixels == (PixelPacket *) NULL)
3191 return((const PixelPacket *) NULL);
cristydf415c82010-03-11 16:47:50 +00003192 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3193 nexus_info->region.x;
3194 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3195 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003196 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3197 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003198 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3199 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003200 {
3201 MagickBooleanType
3202 status;
3203
3204 /*
3205 Pixel request is inside cache extents.
3206 */
3207 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
3208 return(pixels);
3209 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3210 if (status == MagickFalse)
3211 return((const PixelPacket *) NULL);
3212 if ((cache_info->storage_class == PseudoClass) ||
3213 (cache_info->colorspace == CMYKColorspace))
3214 {
3215 status=ReadPixelCacheIndexes(cache_info,nexus_info,exception);
3216 if (status == MagickFalse)
3217 return((const PixelPacket *) NULL);
3218 }
3219 return(pixels);
3220 }
3221 /*
3222 Pixel request is outside cache extents.
3223 */
3224 q=pixels;
3225 indexes=GetPixelCacheNexusIndexes(cache_info,nexus_info);
3226 virtual_nexus=AcquirePixelCacheNexus(1);
3227 if (virtual_nexus == (NexusInfo **) NULL)
3228 {
3229 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3230 "UnableToGetCacheNexus","`%s'",image->filename);
3231 return((const PixelPacket *) NULL);
3232 }
3233 switch (virtual_pixel_method)
3234 {
3235 case BlackVirtualPixelMethod:
3236 {
cristy4789f0d2010-01-10 00:01:06 +00003237 SetRedPixelComponent(&virtual_pixel,0);
3238 SetGreenPixelComponent(&virtual_pixel,0);
3239 SetBluePixelComponent(&virtual_pixel,0);
3240 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003241 break;
3242 }
3243 case GrayVirtualPixelMethod:
3244 {
cristy4789f0d2010-01-10 00:01:06 +00003245 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3246 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3247 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3248 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003249 break;
3250 }
3251 case TransparentVirtualPixelMethod:
3252 {
cristy4789f0d2010-01-10 00:01:06 +00003253 SetRedPixelComponent(&virtual_pixel,0);
3254 SetGreenPixelComponent(&virtual_pixel,0);
3255 SetBluePixelComponent(&virtual_pixel,0);
3256 SetOpacityPixelComponent(&virtual_pixel,TransparentOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003257 break;
3258 }
3259 case MaskVirtualPixelMethod:
3260 case WhiteVirtualPixelMethod:
3261 {
cristy4789f0d2010-01-10 00:01:06 +00003262 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3263 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3264 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3265 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003266 break;
3267 }
3268 default:
3269 {
3270 virtual_pixel=image->background_color;
3271 break;
3272 }
3273 }
cristyc3ec0d42010-04-07 01:18:08 +00003274 virtual_index=0;
cristybb503372010-05-27 20:51:26 +00003275 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003276 {
cristybb503372010-05-27 20:51:26 +00003277 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003278 {
3279 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003280 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003281 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3282 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003283 {
3284 MagickModulo
3285 x_modulo,
3286 y_modulo;
3287
3288 /*
3289 Transfer a single pixel.
3290 */
3291 length=(MagickSizeType) 1;
3292 switch (virtual_pixel_method)
3293 {
3294 case BackgroundVirtualPixelMethod:
3295 case ConstantVirtualPixelMethod:
3296 case BlackVirtualPixelMethod:
3297 case GrayVirtualPixelMethod:
3298 case TransparentVirtualPixelMethod:
3299 case MaskVirtualPixelMethod:
3300 case WhiteVirtualPixelMethod:
3301 {
3302 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003303 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003304 break;
3305 }
3306 case EdgeVirtualPixelMethod:
3307 default:
3308 {
3309 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003310 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003311 1UL,1UL,virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003312 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3313 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003314 break;
3315 }
3316 case RandomVirtualPixelMethod:
3317 {
3318 if (cache_info->random_info == (RandomInfo *) NULL)
3319 cache_info->random_info=AcquireRandomInfo();
3320 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003321 RandomX(cache_info->random_info,cache_info->columns),
3322 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003323 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003324 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3325 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003326 break;
3327 }
3328 case DitherVirtualPixelMethod:
3329 {
3330 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003331 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003332 1UL,1UL,virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003333 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3334 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003335 break;
3336 }
3337 case TileVirtualPixelMethod:
3338 {
3339 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3340 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3341 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3342 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3343 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003344 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3345 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003346 break;
3347 }
3348 case MirrorVirtualPixelMethod:
3349 {
3350 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3351 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003352 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003353 x_modulo.remainder-1L;
3354 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3355 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003356 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003357 y_modulo.remainder-1L;
3358 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3359 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3360 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003361 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3362 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003363 break;
3364 }
3365 case CheckerTileVirtualPixelMethod:
3366 {
3367 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3368 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3369 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3370 {
3371 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003372 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003373 break;
3374 }
3375 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3376 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3377 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003378 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3379 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003380 break;
3381 }
3382 case HorizontalTileVirtualPixelMethod:
3383 {
cristybb503372010-05-27 20:51:26 +00003384 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003385 {
3386 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003387 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003388 break;
3389 }
3390 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3391 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3392 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3393 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3394 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003395 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3396 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003397 break;
3398 }
3399 case VerticalTileVirtualPixelMethod:
3400 {
cristybb503372010-05-27 20:51:26 +00003401 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
cristy3ed852e2009-09-05 21:47:34 +00003402 {
3403 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003404 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003405 break;
3406 }
3407 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3408 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3409 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3410 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3411 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003412 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3413 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003414 break;
3415 }
3416 case HorizontalTileEdgeVirtualPixelMethod:
3417 {
3418 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3419 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003420 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003421 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003422 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3423 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003424 break;
3425 }
3426 case VerticalTileEdgeVirtualPixelMethod:
3427 {
3428 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3429 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003430 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003431 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003432 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3433 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003434 break;
3435 }
3436 }
3437 if (p == (const PixelPacket *) NULL)
3438 break;
3439 *q++=(*p);
cristyc3ec0d42010-04-07 01:18:08 +00003440 if ((indexes != (IndexPacket *) NULL) &&
3441 (virtual_indexes != (const IndexPacket *) NULL))
3442 *indexes++=(*virtual_indexes);
cristy3ed852e2009-09-05 21:47:34 +00003443 continue;
3444 }
3445 /*
3446 Transfer a run of pixels.
3447 */
3448 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,
cristybb503372010-05-27 20:51:26 +00003449 (size_t) length,1UL,virtual_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003450 if (p == (const PixelPacket *) NULL)
3451 break;
cristyc3ec0d42010-04-07 01:18:08 +00003452 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003453 (void) CopyMagickMemory(q,p,(size_t) length*sizeof(*p));
3454 q+=length;
cristyc3ec0d42010-04-07 01:18:08 +00003455 if ((indexes != (IndexPacket *) NULL) &&
3456 (virtual_indexes != (const IndexPacket *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003457 {
cristyc3ec0d42010-04-07 01:18:08 +00003458 (void) CopyMagickMemory(indexes,virtual_indexes,(size_t) length*
3459 sizeof(*virtual_indexes));
3460 indexes+=length;
cristy3ed852e2009-09-05 21:47:34 +00003461 }
3462 }
3463 }
3464 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3465 return(pixels);
3466}
3467
3468/*
3469%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3470% %
3471% %
3472% %
3473+ G e t V i r t u a l P i x e l C a c h e %
3474% %
3475% %
3476% %
3477%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3478%
3479% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3480% cache as defined by the geometry parameters. A pointer to the pixels
3481% is returned if the pixels are transferred, otherwise a NULL is returned.
3482%
3483% The format of the GetVirtualPixelCache() method is:
3484%
3485% const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003486% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3487% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003488% ExceptionInfo *exception)
3489%
3490% A description of each parameter follows:
3491%
3492% o image: the image.
3493%
3494% o virtual_pixel_method: the virtual pixel method.
3495%
3496% o x,y,columns,rows: These values define the perimeter of a region of
3497% pixels.
3498%
3499% o exception: return any errors or warnings in this structure.
3500%
3501*/
3502static const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003503 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3504 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003505{
3506 CacheInfo
3507 *cache_info;
3508
cristy5c9e6f22010-09-17 17:31:01 +00003509 const int
3510 id = GetOpenMPThreadId();
3511
cristy3ed852e2009-09-05 21:47:34 +00003512 const PixelPacket
3513 *pixels;
3514
cristy3ed852e2009-09-05 21:47:34 +00003515 cache_info=(CacheInfo *) image->cache;
cristy6ebe97c2010-07-03 01:17:28 +00003516 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00003517 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3518 cache_info->nexus_info[id],exception);
3519 return(pixels);
3520}
3521
3522/*
3523%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3524% %
3525% %
3526% %
3527% G e t V i r t u a l P i x e l Q u e u e %
3528% %
3529% %
3530% %
3531%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3532%
3533% GetVirtualPixelQueue() returns the virtual pixels associated with the
3534% last call to QueueAuthenticPixels() or GetVirtualPixels().
3535%
3536% The format of the GetVirtualPixelQueue() method is:
3537%
3538% const PixelPacket *GetVirtualPixelQueue(const Image image)
3539%
3540% A description of each parameter follows:
3541%
3542% o image: the image.
3543%
3544*/
3545MagickExport const PixelPacket *GetVirtualPixelQueue(const Image *image)
3546{
3547 CacheInfo
3548 *cache_info;
3549
3550 assert(image != (const Image *) NULL);
3551 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003552 assert(image->cache != (Cache) NULL);
3553 cache_info=(CacheInfo *) image->cache;
3554 assert(cache_info->signature == MagickSignature);
3555 if (cache_info->methods.get_virtual_pixels_handler ==
3556 (GetVirtualPixelsHandler) NULL)
3557 return((PixelPacket *) NULL);
3558 return(cache_info->methods.get_virtual_pixels_handler(image));
3559}
3560
3561/*
3562%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3563% %
3564% %
3565% %
3566% G e t V i r t u a l P i x e l s %
3567% %
3568% %
3569% %
3570%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3571%
3572% GetVirtualPixels() returns an immutable pixel region. If the
3573% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003574% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003575% copy of the pixels or it may point to the original pixels in memory.
3576% Performance is maximized if the selected region is part of one row, or one
3577% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003578% (without a copy) if the image is in memory, or in a memory-mapped file. The
3579% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003580%
3581% Pixels accessed via the returned pointer represent a simple array of type
3582% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
3583% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to access
3584% the black color component or to obtain the colormap indexes (of type
3585% IndexPacket) corresponding to the region.
3586%
3587% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3588%
3589% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3590% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3591% GetCacheViewAuthenticPixels() instead.
3592%
3593% The format of the GetVirtualPixels() method is:
3594%
cristybb503372010-05-27 20:51:26 +00003595% const PixelPacket *GetVirtualPixels(const Image *image,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 x,y,columns,rows: These values define the perimeter of a region of
3604% pixels.
3605%
3606% o exception: return any errors or warnings in this structure.
3607%
3608*/
3609MagickExport const PixelPacket *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003610 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3611 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003612{
3613 CacheInfo
3614 *cache_info;
3615
3616 const PixelPacket
3617 *pixels;
3618
3619 assert(image != (const Image *) NULL);
3620 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003621 assert(image->cache != (Cache) NULL);
3622 cache_info=(CacheInfo *) image->cache;
3623 assert(cache_info->signature == MagickSignature);
3624 if (cache_info->methods.get_virtual_pixel_handler ==
3625 (GetVirtualPixelHandler) NULL)
3626 return((const PixelPacket *) NULL);
3627 pixels=cache_info->methods.get_virtual_pixel_handler(image,
3628 GetPixelCacheVirtualMethod(image),x,y,columns,rows,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 s F r o m C a c h e %
3638% %
3639% %
3640% %
3641%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3642%
3643% GetVirtualPixelsCache() returns the pixels associated with the last call
3644% to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3645%
3646% The format of the GetVirtualPixelsCache() method is:
3647%
3648% PixelPacket *GetVirtualPixelsCache(const Image *image)
3649%
3650% A description of each parameter follows:
3651%
3652% o image: the image.
3653%
3654*/
3655static const PixelPacket *GetVirtualPixelsCache(const Image *image)
3656{
3657 CacheInfo
3658 *cache_info;
3659
cristy5c9e6f22010-09-17 17:31:01 +00003660 const int
3661 id = GetOpenMPThreadId();
3662
cristy3ed852e2009-09-05 21:47:34 +00003663 const PixelPacket
3664 *pixels;
3665
cristy3ed852e2009-09-05 21:47:34 +00003666 cache_info=(CacheInfo *) image->cache;
cristy6ebe97c2010-07-03 01:17:28 +00003667 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00003668 pixels=GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]);
3669 return(pixels);
3670}
3671
3672/*
3673%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3674% %
3675% %
3676% %
3677+ G e t V i r t u a l P i x e l s N e x u s %
3678% %
3679% %
3680% %
3681%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3682%
3683% GetVirtualPixelsNexus() returns the pixels associated with the specified
3684% cache nexus.
3685%
3686% The format of the GetVirtualPixelsNexus() method is:
3687%
3688% const IndexPacket *GetVirtualPixelsNexus(const Cache cache,
3689% NexusInfo *nexus_info)
3690%
3691% A description of each parameter follows:
3692%
3693% o cache: the pixel cache.
3694%
3695% o nexus_info: the cache nexus to return the colormap pixels.
3696%
3697*/
3698MagickExport const PixelPacket *GetVirtualPixelsNexus(const Cache cache,
3699 NexusInfo *nexus_info)
3700{
3701 CacheInfo
3702 *cache_info;
3703
3704 if (cache == (Cache) NULL)
3705 return((PixelPacket *) NULL);
3706 cache_info=(CacheInfo *) cache;
3707 assert(cache_info->signature == MagickSignature);
3708 if (cache_info->storage_class == UndefinedClass)
3709 return((PixelPacket *) NULL);
3710 return((const PixelPacket *) nexus_info->pixels);
3711}
3712
3713/*
3714%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3715% %
3716% %
3717% %
3718+ M a s k P i x e l C a c h e N e x u s %
3719% %
3720% %
3721% %
3722%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3723%
3724% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3725% The method returns MagickTrue if the pixel region is masked, otherwise
3726% MagickFalse.
3727%
3728% The format of the MaskPixelCacheNexus() method is:
3729%
3730% MagickBooleanType MaskPixelCacheNexus(Image *image,
3731% NexusInfo *nexus_info,ExceptionInfo *exception)
3732%
3733% A description of each parameter follows:
3734%
3735% o image: the image.
3736%
3737% o nexus_info: the cache nexus to clip.
3738%
3739% o exception: return any errors or warnings in this structure.
3740%
3741*/
3742
3743static inline void MagickPixelCompositeMask(const MagickPixelPacket *p,
3744 const MagickRealType alpha,const MagickPixelPacket *q,
3745 const MagickRealType beta,MagickPixelPacket *composite)
3746{
3747 MagickRealType
3748 gamma;
3749
3750 if (alpha == TransparentOpacity)
3751 {
3752 *composite=(*q);
3753 return;
3754 }
3755 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3756 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3757 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3758 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3759 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3760 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3761 composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
3762}
3763
3764static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3765 ExceptionInfo *exception)
3766{
3767 CacheInfo
3768 *cache_info;
3769
3770 MagickPixelPacket
3771 alpha,
3772 beta;
3773
3774 MagickSizeType
3775 number_pixels;
3776
3777 NexusInfo
3778 **clip_nexus,
3779 **image_nexus;
3780
3781 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003782 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003783
3784 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003785 *restrict nexus_indexes,
3786 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003787
cristy3ed852e2009-09-05 21:47:34 +00003788 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003789 *restrict p,
3790 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003791
cristye076a6e2010-08-15 19:59:43 +00003792 register ssize_t
3793 i;
3794
cristy3ed852e2009-09-05 21:47:34 +00003795 /*
3796 Apply clip mask.
3797 */
3798 if (image->debug != MagickFalse)
3799 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3800 if (image->mask == (Image *) NULL)
3801 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +00003802 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00003803 if (cache_info == (Cache) NULL)
3804 return(MagickFalse);
3805 image_nexus=AcquirePixelCacheNexus(1);
3806 clip_nexus=AcquirePixelCacheNexus(1);
3807 if ((image_nexus == (NexusInfo **) NULL) ||
3808 (clip_nexus == (NexusInfo **) NULL))
3809 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy09449f72010-01-23 03:08:36 +00003810 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,
3811 nexus_info->region.y,nexus_info->region.width,nexus_info->region.height,
3812 image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003813 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
3814 q=nexus_info->pixels;
3815 nexus_indexes=nexus_info->indexes;
3816 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3817 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3818 nexus_info->region.height,clip_nexus[0],&image->exception);
3819 GetMagickPixelPacket(image,&alpha);
3820 GetMagickPixelPacket(image,&beta);
3821 number_pixels=(MagickSizeType) nexus_info->region.width*
3822 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +00003823 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +00003824 {
3825 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
3826 break;
3827 SetMagickPixelPacket(image,p,indexes+i,&alpha);
3828 SetMagickPixelPacket(image,q,nexus_indexes+i,&beta);
3829 MagickPixelCompositeMask(&beta,(MagickRealType) PixelIntensityToQuantum(r),
3830 &alpha,alpha.opacity,&beta);
cristyce70c172010-01-07 17:15:30 +00003831 q->red=ClampToQuantum(beta.red);
3832 q->green=ClampToQuantum(beta.green);
3833 q->blue=ClampToQuantum(beta.blue);
3834 q->opacity=ClampToQuantum(beta.opacity);
cristy3ed852e2009-09-05 21:47:34 +00003835 if (cache_info->active_index_channel != MagickFalse)
3836 nexus_indexes[i]=indexes[i];
3837 p++;
3838 q++;
3839 r++;
3840 }
3841 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3842 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +00003843 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003844 return(MagickFalse);
3845 return(MagickTrue);
3846}
3847
3848/*
3849%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3850% %
3851% %
3852% %
3853+ O p e n P i x e l C a c h e %
3854% %
3855% %
3856% %
3857%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3858%
3859% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3860% dimensions, allocating space for the image pixels and optionally the
3861% colormap indexes, and memory mapping the cache if it is disk based. The
3862% cache nexus array is initialized as well.
3863%
3864% The format of the OpenPixelCache() method is:
3865%
3866% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3867% ExceptionInfo *exception)
3868%
3869% A description of each parameter follows:
3870%
3871% o image: the image.
3872%
3873% o mode: ReadMode, WriteMode, or IOMode.
3874%
3875% o exception: return any errors or warnings in this structure.
3876%
3877*/
3878
cristyd43a46b2010-01-21 02:13:41 +00003879static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003880{
3881 cache_info->mapped=MagickFalse;
3882 cache_info->pixels=(PixelPacket *) AcquireMagickMemory((size_t)
3883 cache_info->length);
3884 if (cache_info->pixels == (PixelPacket *) NULL)
3885 {
3886 cache_info->mapped=MagickTrue;
3887 cache_info->pixels=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
3888 cache_info->length);
3889 }
3890}
3891
3892static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3893{
3894 CacheInfo
3895 *cache_info;
3896
3897 MagickOffsetType
3898 count,
3899 extent,
3900 offset;
3901
3902 cache_info=(CacheInfo *) image->cache;
3903 if (image->debug != MagickFalse)
3904 {
3905 char
3906 format[MaxTextExtent],
3907 message[MaxTextExtent];
3908
cristyb9080c92009-12-01 20:13:26 +00003909 (void) FormatMagickSize(length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00003910 (void) FormatMagickString(message,MaxTextExtent,
cristy2ce15c92010-03-12 14:03:41 +00003911 "extend %s (%s[%d], disk, %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003912 cache_info->cache_filename,cache_info->file,format);
3913 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3914 }
3915 if (length != (MagickSizeType) ((MagickOffsetType) length))
3916 return(MagickFalse);
3917 extent=(MagickOffsetType) MagickSeek(cache_info->file,0,SEEK_END);
3918 if (extent < 0)
3919 return(MagickFalse);
3920 if ((MagickSizeType) extent >= length)
3921 return(MagickTrue);
3922 offset=(MagickOffsetType) length-1;
3923 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3924 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3925}
3926
3927static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3928 ExceptionInfo *exception)
3929{
3930 char
3931 format[MaxTextExtent],
3932 message[MaxTextExtent];
3933
3934 CacheInfo
3935 *cache_info,
3936 source_info;
3937
3938 MagickSizeType
3939 length,
3940 number_pixels;
3941
3942 MagickStatusType
3943 status;
3944
3945 size_t
cristye076a6e2010-08-15 19:59:43 +00003946 columns,
cristy3ed852e2009-09-05 21:47:34 +00003947 packet_size;
3948
cristy3ed852e2009-09-05 21:47:34 +00003949 if (image->debug != MagickFalse)
3950 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3951 if ((image->columns == 0) || (image->rows == 0))
3952 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3953 cache_info=(CacheInfo *) image->cache;
3954 source_info=(*cache_info);
3955 source_info.file=(-1);
cristye8c25f92010-06-03 00:53:06 +00003956 (void) FormatMagickString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3957 image->filename,(double) GetImageIndexInList(image));
cristy87528ea2009-09-10 14:53:56 +00003958 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +00003959 cache_info->rows=image->rows;
3960 cache_info->columns=image->columns;
3961 cache_info->active_index_channel=((image->storage_class == PseudoClass) ||
3962 (image->colorspace == CMYKColorspace)) ? MagickTrue : MagickFalse;
cristy73724512010-04-12 14:43:14 +00003963 if (image->ping != MagickFalse)
3964 {
3965 cache_info->storage_class=image->storage_class;
3966 cache_info->colorspace=image->colorspace;
3967 cache_info->type=PingCache;
3968 cache_info->pixels=(PixelPacket *) NULL;
3969 cache_info->indexes=(IndexPacket *) NULL;
3970 cache_info->length=0;
3971 return(MagickTrue);
3972 }
cristy3ed852e2009-09-05 21:47:34 +00003973 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3974 packet_size=sizeof(PixelPacket);
3975 if (cache_info->active_index_channel != MagickFalse)
3976 packet_size+=sizeof(IndexPacket);
3977 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00003978 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00003979 if (cache_info->columns != columns)
3980 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3981 image->filename);
3982 cache_info->length=length;
3983 status=AcquireMagickResource(AreaResource,cache_info->length);
3984 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
3985 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3986 {
3987 status=AcquireMagickResource(MemoryResource,cache_info->length);
3988 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3989 (cache_info->type == MemoryCache))
3990 {
cristyd43a46b2010-01-21 02:13:41 +00003991 AllocatePixelCachePixels(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00003992 if (cache_info->pixels == (PixelPacket *) NULL)
3993 cache_info->pixels=source_info.pixels;
3994 else
3995 {
3996 /*
3997 Create memory pixel cache.
3998 */
3999 if (image->debug != MagickFalse)
4000 {
cristy97e7a572009-12-05 15:07:53 +00004001 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004002 format);
cristy3ed852e2009-09-05 21:47:34 +00004003 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004004 "open %s (%s memory, %.20gx%.20g %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00004005 cache_info->mapped != MagickFalse ? "anonymous" : "heap",
cristye8c25f92010-06-03 00:53:06 +00004006 (double) cache_info->columns,(double) cache_info->rows,
4007 format);
cristy3ed852e2009-09-05 21:47:34 +00004008 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4009 message);
4010 }
4011 cache_info->storage_class=image->storage_class;
4012 cache_info->colorspace=image->colorspace;
4013 cache_info->type=MemoryCache;
4014 cache_info->indexes=(IndexPacket *) NULL;
4015 if (cache_info->active_index_channel != MagickFalse)
4016 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4017 number_pixels);
4018 if (source_info.storage_class != UndefinedClass)
4019 {
4020 status|=ClonePixelCachePixels(cache_info,&source_info,
4021 exception);
4022 RelinquishPixelCachePixels(&source_info);
4023 }
4024 return(MagickTrue);
4025 }
4026 }
4027 RelinquishMagickResource(MemoryResource,cache_info->length);
4028 }
4029 /*
4030 Create pixel cache on disk.
4031 */
4032 status=AcquireMagickResource(DiskResource,cache_info->length);
4033 if (status == MagickFalse)
4034 {
4035 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4036 "CacheResourcesExhausted","`%s'",image->filename);
4037 return(MagickFalse);
4038 }
4039 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4040 {
4041 RelinquishMagickResource(DiskResource,cache_info->length);
4042 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4043 image->filename);
4044 return(MagickFalse);
4045 }
4046 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4047 cache_info->length);
4048 if (status == MagickFalse)
4049 {
4050 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4051 image->filename);
4052 return(MagickFalse);
4053 }
4054 cache_info->storage_class=image->storage_class;
4055 cache_info->colorspace=image->colorspace;
4056 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4057 status=AcquireMagickResource(AreaResource,cache_info->length);
4058 if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4059 cache_info->type=DiskCache;
4060 else
4061 {
4062 status=AcquireMagickResource(MapResource,cache_info->length);
4063 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4064 (cache_info->type != MemoryCache))
4065 cache_info->type=DiskCache;
4066 else
4067 {
4068 cache_info->pixels=(PixelPacket *) MapBlob(cache_info->file,mode,
4069 cache_info->offset,(size_t) cache_info->length);
4070 if (cache_info->pixels == (PixelPacket *) NULL)
4071 {
4072 cache_info->pixels=source_info.pixels;
4073 cache_info->type=DiskCache;
4074 }
4075 else
4076 {
4077 /*
4078 Create file-backed memory-mapped pixel cache.
4079 */
4080 (void) ClosePixelCacheOnDisk(cache_info);
4081 cache_info->type=MapCache;
4082 cache_info->mapped=MagickTrue;
4083 cache_info->indexes=(IndexPacket *) NULL;
4084 if (cache_info->active_index_channel != MagickFalse)
4085 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4086 number_pixels);
4087 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4088 {
4089 status=ClonePixelCachePixels(cache_info,&source_info,
4090 exception);
4091 RelinquishPixelCachePixels(&source_info);
4092 }
4093 if (image->debug != MagickFalse)
4094 {
cristy97e7a572009-12-05 15:07:53 +00004095 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004096 format);
cristy3ed852e2009-09-05 21:47:34 +00004097 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004098 "open %s (%s[%d], memory-mapped, %.20gx%.20g %sB)",
cristy3ed852e2009-09-05 21:47:34 +00004099 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004100 cache_info->file,(double) cache_info->columns,(double)
4101 cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004102 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4103 message);
4104 }
4105 return(MagickTrue);
4106 }
4107 }
4108 RelinquishMagickResource(MapResource,cache_info->length);
4109 }
4110 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4111 {
4112 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4113 RelinquishPixelCachePixels(&source_info);
4114 }
4115 if (image->debug != MagickFalse)
4116 {
cristyb9080c92009-12-01 20:13:26 +00004117 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00004118 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004119 "open %s (%s[%d], disk, %.20gx%.20g %sB)",cache_info->filename,
4120 cache_info->cache_filename,cache_info->file,(double)
4121 cache_info->columns,(double) cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004122 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4123 }
4124 return(MagickTrue);
4125}
4126
4127/*
4128%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4129% %
4130% %
4131% %
4132+ P e r s i s t P i x e l C a c h e %
4133% %
4134% %
4135% %
4136%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4137%
4138% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4139% persistent pixel cache is one that resides on disk and is not destroyed
4140% when the program exits.
4141%
4142% The format of the PersistPixelCache() method is:
4143%
4144% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4145% const MagickBooleanType attach,MagickOffsetType *offset,
4146% ExceptionInfo *exception)
4147%
4148% A description of each parameter follows:
4149%
4150% o image: the image.
4151%
4152% o filename: the persistent pixel cache filename.
4153%
cristy01b7eb02009-09-10 23:10:14 +00004154% o attach: A value other than zero initializes the persistent pixel
4155% cache.
4156%
cristy3ed852e2009-09-05 21:47:34 +00004157% o initialize: A value other than zero initializes the persistent pixel
4158% cache.
4159%
4160% o offset: the offset in the persistent cache to store pixels.
4161%
4162% o exception: return any errors or warnings in this structure.
4163%
4164*/
4165MagickExport MagickBooleanType PersistPixelCache(Image *image,
4166 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4167 ExceptionInfo *exception)
4168{
4169 CacheInfo
4170 *cache_info,
4171 *clone_info;
4172
4173 Image
4174 clone_image;
4175
cristy3ed852e2009-09-05 21:47:34 +00004176 MagickBooleanType
4177 status;
4178
cristye076a6e2010-08-15 19:59:43 +00004179 ssize_t
4180 page_size;
4181
cristy3ed852e2009-09-05 21:47:34 +00004182 assert(image != (Image *) NULL);
4183 assert(image->signature == MagickSignature);
4184 if (image->debug != MagickFalse)
4185 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4186 assert(image->cache != (void *) NULL);
4187 assert(filename != (const char *) NULL);
4188 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004189 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004190 cache_info=(CacheInfo *) image->cache;
4191 assert(cache_info->signature == MagickSignature);
4192 if (attach != MagickFalse)
4193 {
4194 /*
cristy01b7eb02009-09-10 23:10:14 +00004195 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004196 */
4197 if (image->debug != MagickFalse)
4198 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4199 "attach persistent cache");
4200 (void) CopyMagickString(cache_info->cache_filename,filename,
4201 MaxTextExtent);
4202 cache_info->type=DiskCache;
4203 cache_info->offset=(*offset);
4204 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4205 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004206 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004207 return(MagickTrue);
4208 }
cristy01b7eb02009-09-10 23:10:14 +00004209 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4210 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004211 {
cristyf84a1932010-01-03 18:00:18 +00004212 LockSemaphoreInfo(cache_info->semaphore);
cristy09449f72010-01-23 03:08:36 +00004213 if ((cache_info->mode != ReadMode) &&
4214 (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004215 (cache_info->reference_count == 1))
4216 {
4217 int
4218 status;
4219
4220 /*
cristy01b7eb02009-09-10 23:10:14 +00004221 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004222 */
4223 status=rename(cache_info->cache_filename,filename);
4224 if (status == 0)
4225 {
4226 (void) CopyMagickString(cache_info->cache_filename,filename,
4227 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004228 *offset+=cache_info->length+page_size-(cache_info->length %
4229 page_size);
cristyf84a1932010-01-03 18:00:18 +00004230 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004231 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004232 if (image->debug != MagickFalse)
4233 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4234 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004235 return(MagickTrue);
4236 }
4237 }
cristyf84a1932010-01-03 18:00:18 +00004238 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004239 }
4240 /*
cristy01b7eb02009-09-10 23:10:14 +00004241 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004242 */
4243 clone_image=(*image);
4244 clone_info=(CacheInfo *) clone_image.cache;
4245 image->cache=ClonePixelCache(cache_info);
4246 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4247 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4248 cache_info->type=DiskCache;
4249 cache_info->offset=(*offset);
4250 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004251 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004252 if (status != MagickFalse)
cristyabd6e372010-09-15 19:11:26 +00004253 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
cristy688f07b2009-09-27 15:19:13 +00004254 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004255 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4256 return(status);
4257}
4258
4259/*
4260%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4261% %
4262% %
4263% %
4264+ Q u e u e A u t h e n t i c N e x u s %
4265% %
4266% %
4267% %
4268%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4269%
4270% QueueAuthenticNexus() allocates an region to store image pixels as defined
4271% by the region rectangle and returns a pointer to the region. This region is
4272% subsequently transferred from the pixel cache with
4273% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4274% pixels are transferred, otherwise a NULL is returned.
4275%
4276% The format of the QueueAuthenticNexus() method is:
4277%
cristy5f959472010-05-27 22:19:46 +00004278% PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
4279% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004280% NexusInfo *nexus_info,ExceptionInfo *exception)
4281%
4282% A description of each parameter follows:
4283%
4284% o image: the image.
4285%
4286% o x,y,columns,rows: These values define the perimeter of a region of
4287% pixels.
4288%
4289% o nexus_info: the cache nexus to set.
4290%
4291% o exception: return any errors or warnings in this structure.
4292%
4293*/
cristybb503372010-05-27 20:51:26 +00004294MagickExport PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy30097232010-07-01 02:16:30 +00004295 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
4296 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004297{
4298 CacheInfo
4299 *cache_info;
4300
4301 MagickOffsetType
4302 offset;
4303
4304 MagickSizeType
4305 number_pixels;
4306
4307 RectangleInfo
4308 region;
4309
4310 /*
4311 Validate pixel cache geometry.
4312 */
cristy77ff0282010-09-13 00:51:10 +00004313 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
4314 if (cache_info == (Cache) NULL)
4315 return((PixelPacket *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004316 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4317 {
4318 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4319 "NoPixelsDefinedInCache","`%s'",image->filename);
4320 return((PixelPacket *) NULL);
4321 }
cristybb503372010-05-27 20:51:26 +00004322 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4323 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004324 {
4325 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4326 "PixelsAreNotAuthentic","`%s'",image->filename);
4327 return((PixelPacket *) NULL);
4328 }
4329 offset=(MagickOffsetType) y*cache_info->columns+x;
4330 if (offset < 0)
4331 return((PixelPacket *) NULL);
4332 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4333 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4334 if ((MagickSizeType) offset >= number_pixels)
4335 return((PixelPacket *) NULL);
4336 /*
4337 Return pixel cache.
4338 */
4339 region.x=x;
4340 region.y=y;
4341 region.width=columns;
4342 region.height=rows;
4343 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4344}
4345
4346/*
4347%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4348% %
4349% %
4350% %
4351+ 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 %
4352% %
4353% %
4354% %
4355%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4356%
4357% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4358% defined by the region rectangle and returns a pointer to the region. This
4359% region is subsequently transferred from the pixel cache with
4360% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4361% pixels are transferred, otherwise a NULL is returned.
4362%
4363% The format of the QueueAuthenticPixelsCache() method is:
4364%
cristybb503372010-05-27 20:51:26 +00004365% PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4366% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004367% ExceptionInfo *exception)
4368%
4369% A description of each parameter follows:
4370%
4371% o image: the image.
4372%
4373% o x,y,columns,rows: These values define the perimeter of a region of
4374% pixels.
4375%
4376% o exception: return any errors or warnings in this structure.
4377%
4378*/
cristybb503372010-05-27 20:51:26 +00004379static PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4380 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004381 ExceptionInfo *exception)
4382{
4383 CacheInfo
4384 *cache_info;
4385
cristy5c9e6f22010-09-17 17:31:01 +00004386 const int
4387 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004388
4389 PixelPacket
4390 *pixels;
4391
cristy77ff0282010-09-13 00:51:10 +00004392 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00004393 if (cache_info == (Cache) NULL)
4394 return((PixelPacket *) NULL);
cristy6ebe97c2010-07-03 01:17:28 +00004395 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00004396 pixels=QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4397 exception);
4398 return(pixels);
4399}
4400
4401/*
4402%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4403% %
4404% %
4405% %
4406% Q u e u e A u t h e n t i c P i x e l s %
4407% %
4408% %
4409% %
4410%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4411%
4412% QueueAuthenticPixels() queues a mutable pixel region. If the region is
4413% successfully intialized a pointer to a PixelPacket array representing the
4414% region is returned, otherwise NULL is returned. The returned pointer may
4415% point to a temporary working buffer for the pixels or it may point to the
4416% final location of the pixels in memory.
4417%
4418% Write-only access means that any existing pixel values corresponding to
4419% the region are ignored. This is useful if the initial image is being
4420% created from scratch, or if the existing pixel values are to be
4421% completely replaced without need to refer to their pre-existing values.
4422% The application is free to read and write the pixel buffer returned by
4423% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4424% initialize the pixel array values. Initializing pixel array values is the
4425% application's responsibility.
4426%
4427% Performance is maximized if the selected region is part of one row, or
4428% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004429% pixels in-place (without a copy) if the image is in memory, or in a
4430% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004431% by the user.
4432%
4433% Pixels accessed via the returned pointer represent a simple array of type
4434% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
4435% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
4436% the black color component or the colormap indexes (of type IndexPacket)
4437% corresponding to the region. Once the PixelPacket (and/or IndexPacket)
4438% array has been updated, the changes must be saved back to the underlying
4439% image using SyncAuthenticPixels() or they may be lost.
4440%
4441% The format of the QueueAuthenticPixels() method is:
4442%
cristy5f959472010-05-27 22:19:46 +00004443% PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4444% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004445% ExceptionInfo *exception)
4446%
4447% A description of each parameter follows:
4448%
4449% o image: the image.
4450%
4451% o x,y,columns,rows: These values define the perimeter of a region of
4452% pixels.
4453%
4454% o exception: return any errors or warnings in this structure.
4455%
4456*/
cristybb503372010-05-27 20:51:26 +00004457MagickExport PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4458 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004459 ExceptionInfo *exception)
4460{
4461 CacheInfo
4462 *cache_info;
4463
4464 PixelPacket
4465 *pixels;
4466
4467 assert(image != (Image *) NULL);
4468 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004469 assert(image->cache != (Cache) NULL);
4470 cache_info=(CacheInfo *) image->cache;
4471 assert(cache_info->signature == MagickSignature);
4472 if (cache_info->methods.queue_authentic_pixels_handler ==
4473 (QueueAuthenticPixelsHandler) NULL)
4474 return((PixelPacket *) NULL);
4475 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4476 rows,exception);
4477 return(pixels);
4478}
4479
4480/*
4481%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4482% %
4483% %
4484% %
4485+ R e a d P i x e l C a c h e I n d e x e s %
4486% %
4487% %
4488% %
4489%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4490%
4491% ReadPixelCacheIndexes() reads colormap indexes from the specified region of
4492% the pixel cache.
4493%
4494% The format of the ReadPixelCacheIndexes() method is:
4495%
4496% MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4497% NexusInfo *nexus_info,ExceptionInfo *exception)
4498%
4499% A description of each parameter follows:
4500%
4501% o cache_info: the pixel cache.
4502%
4503% o nexus_info: the cache nexus to read the colormap indexes.
4504%
4505% o exception: return any errors or warnings in this structure.
4506%
4507*/
4508static MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4509 NexusInfo *nexus_info,ExceptionInfo *exception)
4510{
4511 MagickOffsetType
4512 count,
4513 offset;
4514
4515 MagickSizeType
4516 length,
4517 number_pixels;
4518
4519 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004520 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004521
cristybb503372010-05-27 20:51:26 +00004522 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004523 y;
4524
cristybb503372010-05-27 20:51:26 +00004525 size_t
cristy3ed852e2009-09-05 21:47:34 +00004526 rows;
4527
cristy3ed852e2009-09-05 21:47:34 +00004528 if (cache_info->active_index_channel == MagickFalse)
4529 return(MagickFalse);
4530 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4531 return(MagickTrue);
4532 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4533 nexus_info->region.x;
4534 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
4535 rows=nexus_info->region.height;
4536 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004537 q=nexus_info->indexes;
4538 switch (cache_info->type)
4539 {
4540 case MemoryCache:
4541 case MapCache:
4542 {
4543 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004544 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004545
4546 /*
4547 Read indexes from memory.
4548 */
cristydd341db2010-03-04 19:06:38 +00004549 if ((cache_info->columns == nexus_info->region.width) &&
4550 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4551 {
4552 length=number_pixels;
4553 rows=1UL;
4554 }
cristy3ed852e2009-09-05 21:47:34 +00004555 p=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00004556 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004557 {
4558 (void) CopyMagickMemory(q,p,(size_t) length);
4559 p+=cache_info->columns;
4560 q+=nexus_info->region.width;
4561 }
4562 break;
4563 }
4564 case DiskCache:
4565 {
4566 /*
4567 Read indexes from disk.
4568 */
4569 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4570 {
4571 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4572 cache_info->cache_filename);
4573 return(MagickFalse);
4574 }
cristydd341db2010-03-04 19:06:38 +00004575 if ((cache_info->columns == nexus_info->region.width) &&
4576 (number_pixels < MagickMaxBufferExtent))
4577 {
4578 length=number_pixels;
4579 rows=1UL;
4580 }
cristy3ed852e2009-09-05 21:47:34 +00004581 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004582 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004583 {
4584 count=ReadPixelCacheRegion(cache_info,cache_info->offset+number_pixels*
4585 sizeof(PixelPacket)+offset*sizeof(*q),length,(unsigned char *) q);
4586 if ((MagickSizeType) count < length)
4587 break;
4588 offset+=cache_info->columns;
4589 q+=nexus_info->region.width;
4590 }
cristybb503372010-05-27 20:51:26 +00004591 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004592 {
4593 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4594 cache_info->cache_filename);
4595 return(MagickFalse);
4596 }
4597 break;
4598 }
4599 default:
4600 break;
4601 }
4602 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004603 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004604 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004605 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004606 nexus_info->region.width,(double) nexus_info->region.height,(double)
4607 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004608 return(MagickTrue);
4609}
4610
4611/*
4612%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4613% %
4614% %
4615% %
4616+ R e a d P i x e l C a c h e P i x e l s %
4617% %
4618% %
4619% %
4620%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4621%
4622% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4623% cache.
4624%
4625% The format of the ReadPixelCachePixels() method is:
4626%
4627% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4628% NexusInfo *nexus_info,ExceptionInfo *exception)
4629%
4630% A description of each parameter follows:
4631%
4632% o cache_info: the pixel cache.
4633%
4634% o nexus_info: the cache nexus to read the pixels.
4635%
4636% o exception: return any errors or warnings in this structure.
4637%
4638*/
4639static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4640 NexusInfo *nexus_info,ExceptionInfo *exception)
4641{
4642 MagickOffsetType
4643 count,
4644 offset;
4645
4646 MagickSizeType
4647 length,
4648 number_pixels;
4649
cristy3ed852e2009-09-05 21:47:34 +00004650 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004651 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004652
cristye076a6e2010-08-15 19:59:43 +00004653 register ssize_t
4654 y;
4655
cristybb503372010-05-27 20:51:26 +00004656 size_t
cristy3ed852e2009-09-05 21:47:34 +00004657 rows;
4658
cristy3ed852e2009-09-05 21:47:34 +00004659 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4660 return(MagickTrue);
4661 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4662 nexus_info->region.x;
4663 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
4664 rows=nexus_info->region.height;
4665 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004666 q=nexus_info->pixels;
4667 switch (cache_info->type)
4668 {
4669 case MemoryCache:
4670 case MapCache:
4671 {
4672 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004673 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004674
4675 /*
4676 Read pixels from memory.
4677 */
cristydd341db2010-03-04 19:06:38 +00004678 if ((cache_info->columns == nexus_info->region.width) &&
4679 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4680 {
4681 length=number_pixels;
4682 rows=1UL;
4683 }
cristy3ed852e2009-09-05 21:47:34 +00004684 p=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00004685 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004686 {
4687 (void) CopyMagickMemory(q,p,(size_t) length);
4688 p+=cache_info->columns;
4689 q+=nexus_info->region.width;
4690 }
4691 break;
4692 }
4693 case DiskCache:
4694 {
4695 /*
4696 Read pixels from disk.
4697 */
4698 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4699 {
4700 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4701 cache_info->cache_filename);
4702 return(MagickFalse);
4703 }
cristydd341db2010-03-04 19:06:38 +00004704 if ((cache_info->columns == nexus_info->region.width) &&
4705 (number_pixels < MagickMaxBufferExtent))
4706 {
4707 length=number_pixels;
4708 rows=1UL;
4709 }
cristybb503372010-05-27 20:51:26 +00004710 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004711 {
4712 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4713 sizeof(*q),length,(unsigned char *) q);
4714 if ((MagickSizeType) count < length)
4715 break;
4716 offset+=cache_info->columns;
4717 q+=nexus_info->region.width;
4718 }
cristybb503372010-05-27 20:51:26 +00004719 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004720 {
4721 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4722 cache_info->cache_filename);
4723 return(MagickFalse);
4724 }
4725 break;
4726 }
4727 default:
4728 break;
4729 }
4730 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004731 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004732 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004733 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004734 nexus_info->region.width,(double) nexus_info->region.height,(double)
4735 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004736 return(MagickTrue);
4737}
4738
4739/*
4740%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4741% %
4742% %
4743% %
4744+ R e f e r e n c e P i x e l C a c h e %
4745% %
4746% %
4747% %
4748%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4749%
4750% ReferencePixelCache() increments the reference count associated with the
4751% pixel cache returning a pointer to the cache.
4752%
4753% The format of the ReferencePixelCache method is:
4754%
4755% Cache ReferencePixelCache(Cache cache_info)
4756%
4757% A description of each parameter follows:
4758%
4759% o cache_info: the pixel cache.
4760%
4761*/
4762MagickExport Cache ReferencePixelCache(Cache cache)
4763{
4764 CacheInfo
4765 *cache_info;
4766
4767 assert(cache != (Cache *) NULL);
4768 cache_info=(CacheInfo *) cache;
4769 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004770 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004771 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004772 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004773 return(cache_info);
4774}
4775
4776/*
4777%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4778% %
4779% %
4780% %
4781+ S e t P i x e l C a c h e M e t h o d s %
4782% %
4783% %
4784% %
4785%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4786%
4787% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4788%
4789% The format of the SetPixelCacheMethods() method is:
4790%
4791% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4792%
4793% A description of each parameter follows:
4794%
4795% o cache: the pixel cache.
4796%
4797% o cache_methods: Specifies a pointer to a CacheMethods structure.
4798%
4799*/
4800MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4801{
4802 CacheInfo
4803 *cache_info;
4804
4805 GetOneAuthenticPixelFromHandler
4806 get_one_authentic_pixel_from_handler;
4807
4808 GetOneVirtualPixelFromHandler
4809 get_one_virtual_pixel_from_handler;
4810
4811 /*
4812 Set cache pixel methods.
4813 */
4814 assert(cache != (Cache) NULL);
4815 assert(cache_methods != (CacheMethods *) NULL);
4816 cache_info=(CacheInfo *) cache;
4817 assert(cache_info->signature == MagickSignature);
4818 if (cache_info->debug != MagickFalse)
4819 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4820 cache_info->filename);
4821 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4822 cache_info->methods.get_virtual_pixel_handler=
4823 cache_methods->get_virtual_pixel_handler;
4824 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4825 cache_info->methods.destroy_pixel_handler=
4826 cache_methods->destroy_pixel_handler;
4827 if (cache_methods->get_virtual_indexes_from_handler !=
4828 (GetVirtualIndexesFromHandler) NULL)
4829 cache_info->methods.get_virtual_indexes_from_handler=
4830 cache_methods->get_virtual_indexes_from_handler;
4831 if (cache_methods->get_authentic_pixels_handler !=
4832 (GetAuthenticPixelsHandler) NULL)
4833 cache_info->methods.get_authentic_pixels_handler=
4834 cache_methods->get_authentic_pixels_handler;
4835 if (cache_methods->queue_authentic_pixels_handler !=
4836 (QueueAuthenticPixelsHandler) NULL)
4837 cache_info->methods.queue_authentic_pixels_handler=
4838 cache_methods->queue_authentic_pixels_handler;
4839 if (cache_methods->sync_authentic_pixels_handler !=
4840 (SyncAuthenticPixelsHandler) NULL)
4841 cache_info->methods.sync_authentic_pixels_handler=
4842 cache_methods->sync_authentic_pixels_handler;
4843 if (cache_methods->get_authentic_pixels_from_handler !=
4844 (GetAuthenticPixelsFromHandler) NULL)
4845 cache_info->methods.get_authentic_pixels_from_handler=
4846 cache_methods->get_authentic_pixels_from_handler;
4847 if (cache_methods->get_authentic_indexes_from_handler !=
4848 (GetAuthenticIndexesFromHandler) NULL)
4849 cache_info->methods.get_authentic_indexes_from_handler=
4850 cache_methods->get_authentic_indexes_from_handler;
4851 get_one_virtual_pixel_from_handler=
4852 cache_info->methods.get_one_virtual_pixel_from_handler;
4853 if (get_one_virtual_pixel_from_handler !=
4854 (GetOneVirtualPixelFromHandler) NULL)
4855 cache_info->methods.get_one_virtual_pixel_from_handler=
4856 cache_methods->get_one_virtual_pixel_from_handler;
4857 get_one_authentic_pixel_from_handler=
4858 cache_methods->get_one_authentic_pixel_from_handler;
4859 if (get_one_authentic_pixel_from_handler !=
4860 (GetOneAuthenticPixelFromHandler) NULL)
4861 cache_info->methods.get_one_authentic_pixel_from_handler=
4862 cache_methods->get_one_authentic_pixel_from_handler;
4863}
4864
4865/*
4866%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4867% %
4868% %
4869% %
4870+ S e t P i x e l C a c h e N e x u s P i x e l s %
4871% %
4872% %
4873% %
4874%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4875%
4876% SetPixelCacheNexusPixels() defines the region of the cache for the
4877% specified cache nexus.
4878%
4879% The format of the SetPixelCacheNexusPixels() method is:
4880%
4881% PixelPacket SetPixelCacheNexusPixels(const Image *image,
4882% const RectangleInfo *region,NexusInfo *nexus_info,
4883% ExceptionInfo *exception)
4884%
4885% A description of each parameter follows:
4886%
4887% o image: the image.
4888%
4889% o region: A pointer to the RectangleInfo structure that defines the
4890% region of this particular cache nexus.
4891%
4892% o nexus_info: the cache nexus to set.
4893%
4894% o exception: return any errors or warnings in this structure.
4895%
4896*/
cristyabd6e372010-09-15 19:11:26 +00004897
4898static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4899 NexusInfo *nexus_info,ExceptionInfo *exception)
4900{
4901 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4902 return(MagickFalse);
4903 nexus_info->mapped=MagickFalse;
4904 nexus_info->cache=(PixelPacket *) AcquireMagickMemory((size_t)
4905 nexus_info->length);
4906 if (nexus_info->cache == (PixelPacket *) NULL)
4907 {
4908 nexus_info->mapped=MagickTrue;
4909 nexus_info->cache=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
4910 nexus_info->length);
4911 }
4912 if (nexus_info->cache == (PixelPacket *) NULL)
4913 {
4914 (void) ThrowMagickException(exception,GetMagickModule(),
4915 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4916 cache_info->filename);
4917 return(MagickFalse);
4918 }
4919 return(MagickTrue);
4920}
4921
cristy3ed852e2009-09-05 21:47:34 +00004922static PixelPacket *SetPixelCacheNexusPixels(const Image *image,
4923 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4924{
4925 CacheInfo
4926 *cache_info;
4927
4928 MagickBooleanType
4929 status;
4930
cristy3ed852e2009-09-05 21:47:34 +00004931 MagickSizeType
4932 length,
4933 number_pixels;
4934
cristy3ed852e2009-09-05 21:47:34 +00004935 cache_info=(CacheInfo *) image->cache;
4936 assert(cache_info->signature == MagickSignature);
4937 if (cache_info->type == UndefinedCache)
4938 return((PixelPacket *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00004939 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00004940 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
4941 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00004942 {
cristybb503372010-05-27 20:51:26 +00004943 ssize_t
cristybad067a2010-02-15 17:20:55 +00004944 x,
4945 y;
cristy3ed852e2009-09-05 21:47:34 +00004946
cristyeaedf062010-05-29 22:36:02 +00004947 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4948 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00004949 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4950 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00004951 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00004952 ((nexus_info->region.width == cache_info->columns) ||
4953 ((nexus_info->region.width % cache_info->columns) == 0)))))
4954 {
4955 MagickOffsetType
4956 offset;
4957
4958 /*
4959 Pixels are accessed directly from memory.
4960 */
4961 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4962 nexus_info->region.x;
4963 nexus_info->pixels=cache_info->pixels+offset;
4964 nexus_info->indexes=(IndexPacket *) NULL;
4965 if (cache_info->active_index_channel != MagickFalse)
4966 nexus_info->indexes=cache_info->indexes+offset;
4967 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00004968 }
4969 }
4970 /*
4971 Pixels are stored in a cache region until they are synced to the cache.
4972 */
4973 number_pixels=(MagickSizeType) nexus_info->region.width*
4974 nexus_info->region.height;
4975 length=number_pixels*sizeof(PixelPacket);
4976 if (cache_info->active_index_channel != MagickFalse)
4977 length+=number_pixels*sizeof(IndexPacket);
4978 if (nexus_info->cache == (PixelPacket *) NULL)
4979 {
4980 nexus_info->length=length;
4981 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4982 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004983 {
4984 nexus_info->length=0;
4985 return((PixelPacket *) NULL);
4986 }
cristy3ed852e2009-09-05 21:47:34 +00004987 }
4988 else
4989 if (nexus_info->length != length)
4990 {
4991 RelinquishCacheNexusPixels(nexus_info);
4992 nexus_info->length=length;
4993 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4994 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004995 {
4996 nexus_info->length=0;
4997 return((PixelPacket *) NULL);
4998 }
cristy3ed852e2009-09-05 21:47:34 +00004999 }
5000 nexus_info->pixels=nexus_info->cache;
5001 nexus_info->indexes=(IndexPacket *) NULL;
5002 if (cache_info->active_index_channel != MagickFalse)
5003 nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
5004 return(nexus_info->pixels);
5005}
5006
5007/*
5008%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5009% %
5010% %
5011% %
5012% 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 %
5013% %
5014% %
5015% %
5016%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5017%
5018% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5019% pixel cache and returns the previous setting. A virtual pixel is any pixel
5020% access that is outside the boundaries of the image cache.
5021%
5022% The format of the SetPixelCacheVirtualMethod() method is:
5023%
5024% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5025% const VirtualPixelMethod virtual_pixel_method)
5026%
5027% A description of each parameter follows:
5028%
5029% o image: the image.
5030%
5031% o virtual_pixel_method: choose the type of virtual pixel.
5032%
5033*/
5034MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5035 const VirtualPixelMethod virtual_pixel_method)
5036{
5037 CacheInfo
5038 *cache_info;
5039
5040 VirtualPixelMethod
5041 method;
5042
5043 assert(image != (Image *) NULL);
5044 assert(image->signature == MagickSignature);
5045 if (image->debug != MagickFalse)
5046 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5047 assert(image->cache != (Cache) NULL);
5048 cache_info=(CacheInfo *) image->cache;
5049 assert(cache_info->signature == MagickSignature);
5050 method=cache_info->virtual_pixel_method;
5051 cache_info->virtual_pixel_method=virtual_pixel_method;
5052 return(method);
5053}
5054
5055/*
5056%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5057% %
5058% %
5059% %
5060+ 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 %
5061% %
5062% %
5063% %
5064%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5065%
5066% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5067% in-memory or disk cache. The method returns MagickTrue if the pixel region
5068% is synced, otherwise MagickFalse.
5069%
5070% The format of the SyncAuthenticPixelCacheNexus() method is:
5071%
5072% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5073% NexusInfo *nexus_info,ExceptionInfo *exception)
5074%
5075% A description of each parameter follows:
5076%
5077% o image: the image.
5078%
5079% o nexus_info: the cache nexus to sync.
5080%
5081% o exception: return any errors or warnings in this structure.
5082%
5083*/
5084MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5085 NexusInfo *nexus_info,ExceptionInfo *exception)
5086{
5087 CacheInfo
5088 *cache_info;
5089
5090 MagickBooleanType
5091 status;
5092
5093 /*
5094 Transfer pixels to the cache.
5095 */
5096 assert(image != (Image *) NULL);
5097 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005098 if (image->cache == (Cache) NULL)
5099 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5100 cache_info=(CacheInfo *) image->cache;
5101 if (cache_info->type == UndefinedCache)
5102 return(MagickFalse);
5103 if ((image->clip_mask != (Image *) NULL) &&
5104 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5105 return(MagickFalse);
5106 if ((image->mask != (Image *) NULL) &&
5107 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5108 return(MagickFalse);
5109 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5110 return(MagickTrue);
5111 assert(cache_info->signature == MagickSignature);
5112 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5113 if ((cache_info->active_index_channel != MagickFalse) &&
5114 (WritePixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse))
5115 return(MagickFalse);
5116 return(status);
5117}
5118
5119/*
5120%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5121% %
5122% %
5123% %
5124+ S y n c A u t h e n t i c P i x e l C a c h e %
5125% %
5126% %
5127% %
5128%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5129%
5130% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5131% or disk cache. The method returns MagickTrue if the pixel region is synced,
5132% otherwise MagickFalse.
5133%
5134% The format of the SyncAuthenticPixelsCache() method is:
5135%
5136% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5137% ExceptionInfo *exception)
5138%
5139% A description of each parameter follows:
5140%
5141% o image: the image.
5142%
5143% o exception: return any errors or warnings in this structure.
5144%
5145*/
5146static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5147 ExceptionInfo *exception)
5148{
5149 CacheInfo
5150 *cache_info;
5151
cristy5c9e6f22010-09-17 17:31:01 +00005152 const int
5153 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005154
5155 MagickBooleanType
5156 status;
5157
5158 cache_info=(CacheInfo *) image->cache;
cristy6ebe97c2010-07-03 01:17:28 +00005159 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00005160 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5161 exception);
5162 return(status);
5163}
5164
5165/*
5166%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5167% %
5168% %
5169% %
5170% S y n c A u t h e n t i c P i x e l s %
5171% %
5172% %
5173% %
5174%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5175%
5176% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5177% The method returns MagickTrue if the pixel region is flushed, otherwise
5178% MagickFalse.
5179%
5180% The format of the SyncAuthenticPixels() method is:
5181%
5182% MagickBooleanType SyncAuthenticPixels(Image *image,
5183% ExceptionInfo *exception)
5184%
5185% A description of each parameter follows:
5186%
5187% o image: the image.
5188%
5189% o exception: return any errors or warnings in this structure.
5190%
5191*/
5192MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5193 ExceptionInfo *exception)
5194{
5195 CacheInfo
5196 *cache_info;
5197
5198 assert(image != (Image *) NULL);
5199 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005200 assert(image->cache != (Cache) NULL);
5201 cache_info=(CacheInfo *) image->cache;
5202 assert(cache_info->signature == MagickSignature);
5203 if (cache_info->methods.sync_authentic_pixels_handler ==
5204 (SyncAuthenticPixelsHandler) NULL)
5205 return(MagickFalse);
5206 return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
5207}
5208
5209/*
5210%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5211% %
5212% %
5213% %
5214+ W r i t e P i x e l C a c h e I n d e x e s %
5215% %
5216% %
5217% %
5218%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5219%
5220% WritePixelCacheIndexes() writes the colormap indexes to the specified
5221% region of the pixel cache.
5222%
5223% The format of the WritePixelCacheIndexes() method is:
5224%
5225% MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5226% NexusInfo *nexus_info,ExceptionInfo *exception)
5227%
5228% A description of each parameter follows:
5229%
5230% o cache_info: the pixel cache.
5231%
5232% o nexus_info: the cache nexus to write the colormap indexes.
5233%
5234% o exception: return any errors or warnings in this structure.
5235%
5236*/
5237static MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5238 NexusInfo *nexus_info,ExceptionInfo *exception)
5239{
5240 MagickOffsetType
5241 count,
5242 offset;
5243
5244 MagickSizeType
5245 length,
5246 number_pixels;
5247
5248 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005249 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005250
cristybb503372010-05-27 20:51:26 +00005251 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005252 y;
5253
cristybb503372010-05-27 20:51:26 +00005254 size_t
cristy3ed852e2009-09-05 21:47:34 +00005255 rows;
5256
cristy3ed852e2009-09-05 21:47:34 +00005257 if (cache_info->active_index_channel == MagickFalse)
5258 return(MagickFalse);
5259 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5260 return(MagickTrue);
5261 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5262 nexus_info->region.x;
5263 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
5264 rows=nexus_info->region.height;
5265 number_pixels=(MagickSizeType) length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005266 p=nexus_info->indexes;
5267 switch (cache_info->type)
5268 {
5269 case MemoryCache:
5270 case MapCache:
5271 {
5272 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005273 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005274
5275 /*
5276 Write indexes to memory.
5277 */
cristydd341db2010-03-04 19:06:38 +00005278 if ((cache_info->columns == nexus_info->region.width) &&
5279 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5280 {
5281 length=number_pixels;
5282 rows=1UL;
5283 }
cristy3ed852e2009-09-05 21:47:34 +00005284 q=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00005285 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005286 {
5287 (void) CopyMagickMemory(q,p,(size_t) length);
5288 p+=nexus_info->region.width;
5289 q+=cache_info->columns;
5290 }
5291 break;
5292 }
5293 case DiskCache:
5294 {
5295 /*
5296 Write indexes to disk.
5297 */
5298 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5299 {
5300 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5301 cache_info->cache_filename);
5302 return(MagickFalse);
5303 }
cristydd341db2010-03-04 19:06:38 +00005304 if ((cache_info->columns == nexus_info->region.width) &&
5305 (number_pixels < MagickMaxBufferExtent))
5306 {
5307 length=number_pixels;
5308 rows=1UL;
5309 }
cristy3ed852e2009-09-05 21:47:34 +00005310 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005311 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005312 {
5313 count=WritePixelCacheRegion(cache_info,cache_info->offset+number_pixels*
5314 sizeof(PixelPacket)+offset*sizeof(*p),length,
5315 (const unsigned char *) p);
5316 if ((MagickSizeType) count < length)
5317 break;
5318 p+=nexus_info->region.width;
5319 offset+=cache_info->columns;
5320 }
cristybb503372010-05-27 20:51:26 +00005321 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005322 {
5323 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5324 cache_info->cache_filename);
5325 return(MagickFalse);
5326 }
5327 break;
5328 }
5329 default:
5330 break;
5331 }
5332 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005333 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005334 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005335 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005336 nexus_info->region.width,(double) nexus_info->region.height,(double)
5337 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005338 return(MagickTrue);
5339}
5340
5341/*
5342%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5343% %
5344% %
5345% %
5346+ W r i t e C a c h e P i x e l s %
5347% %
5348% %
5349% %
5350%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5351%
5352% WritePixelCachePixels() writes image pixels to the specified region of the
5353% pixel cache.
5354%
5355% The format of the WritePixelCachePixels() method is:
5356%
5357% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5358% NexusInfo *nexus_info,ExceptionInfo *exception)
5359%
5360% A description of each parameter follows:
5361%
5362% o cache_info: the pixel cache.
5363%
5364% o nexus_info: the cache nexus to write the pixels.
5365%
5366% o exception: return any errors or warnings in this structure.
5367%
5368*/
5369static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5370 NexusInfo *nexus_info,ExceptionInfo *exception)
5371{
5372 MagickOffsetType
5373 count,
5374 offset;
5375
5376 MagickSizeType
5377 length,
5378 number_pixels;
5379
cristy3ed852e2009-09-05 21:47:34 +00005380 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005381 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005382
cristybb503372010-05-27 20:51:26 +00005383 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005384 y;
5385
cristybb503372010-05-27 20:51:26 +00005386 size_t
cristy3ed852e2009-09-05 21:47:34 +00005387 rows;
5388
cristy3ed852e2009-09-05 21:47:34 +00005389 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5390 return(MagickTrue);
5391 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5392 nexus_info->region.x;
5393 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
5394 rows=nexus_info->region.height;
5395 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005396 p=nexus_info->pixels;
5397 switch (cache_info->type)
5398 {
5399 case MemoryCache:
5400 case MapCache:
5401 {
5402 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005403 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005404
5405 /*
5406 Write pixels to memory.
5407 */
cristydd341db2010-03-04 19:06:38 +00005408 if ((cache_info->columns == nexus_info->region.width) &&
5409 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5410 {
5411 length=number_pixels;
5412 rows=1UL;
5413 }
cristy3ed852e2009-09-05 21:47:34 +00005414 q=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00005415 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005416 {
5417 (void) CopyMagickMemory(q,p,(size_t) length);
5418 p+=nexus_info->region.width;
5419 q+=cache_info->columns;
5420 }
5421 break;
5422 }
5423 case DiskCache:
5424 {
5425 /*
5426 Write pixels to disk.
5427 */
5428 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5429 {
5430 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5431 cache_info->cache_filename);
5432 return(MagickFalse);
5433 }
cristydd341db2010-03-04 19:06:38 +00005434 if ((cache_info->columns == nexus_info->region.width) &&
5435 (number_pixels < MagickMaxBufferExtent))
5436 {
5437 length=number_pixels;
5438 rows=1UL;
5439 }
cristybb503372010-05-27 20:51:26 +00005440 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005441 {
5442 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5443 sizeof(*p),length,(const unsigned char *) p);
5444 if ((MagickSizeType) count < length)
5445 break;
5446 p+=nexus_info->region.width;
5447 offset+=cache_info->columns;
5448 }
cristybb503372010-05-27 20:51:26 +00005449 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005450 {
5451 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5452 cache_info->cache_filename);
5453 return(MagickFalse);
5454 }
5455 break;
5456 }
5457 default:
5458 break;
5459 }
5460 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005461 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005462 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005463 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005464 nexus_info->region.width,(double) nexus_info->region.height,(double)
5465 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005466 return(MagickTrue);
5467}