blob: bf0cea89ef56a0cd5f2dfa86372f93ebabd87269 [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 cache_info=(CacheInfo *) image->cache;
cristy6ebe97c2010-07-03 01:17:28 +00001619 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001620 return(GetPixelCacheNexusIndexes(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001621}
1622
1623/*
1624%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1625% %
1626% %
1627% %
1628% G e t A u t h e n t i c I n d e x Q u e u e %
1629% %
1630% %
1631% %
1632%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1633%
1634% GetAuthenticIndexQueue() returns the authentic black channel or the colormap
1635% indexes associated with the last call to QueueAuthenticPixels() or
1636% GetVirtualPixels(). NULL is returned if the black channel or colormap
1637% indexes are not available.
1638%
1639% The format of the GetAuthenticIndexQueue() method is:
1640%
1641% IndexPacket *GetAuthenticIndexQueue(const Image *image)
1642%
1643% A description of each parameter follows:
1644%
1645% o image: the image.
1646%
1647*/
1648MagickExport IndexPacket *GetAuthenticIndexQueue(const Image *image)
1649{
1650 CacheInfo
1651 *cache_info;
1652
1653 assert(image != (const Image *) NULL);
1654 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001655 assert(image->cache != (Cache) NULL);
1656 cache_info=(CacheInfo *) image->cache;
1657 assert(cache_info->signature == MagickSignature);
1658 if (cache_info->methods.get_authentic_indexes_from_handler ==
1659 (GetAuthenticIndexesFromHandler) NULL)
1660 return((IndexPacket *) NULL);
1661 return(cache_info->methods.get_authentic_indexes_from_handler(image));
1662}
1663
1664/*
1665%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1666% %
1667% %
1668% %
1669+ 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 %
1670% %
1671% %
1672% %
1673%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1674%
1675% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1676% disk pixel cache as defined by the geometry parameters. A pointer to the
1677% pixels is returned if the pixels are transferred, otherwise a NULL is
1678% returned.
1679%
1680% The format of the GetAuthenticPixelCacheNexus() method is:
1681%
cristybb503372010-05-27 20:51:26 +00001682% PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1683% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001684% NexusInfo *nexus_info,ExceptionInfo *exception)
1685%
1686% A description of each parameter follows:
1687%
1688% o image: the image.
1689%
1690% o x,y,columns,rows: These values define the perimeter of a region of
1691% pixels.
1692%
1693% o nexus_info: the cache nexus to return.
1694%
1695% o exception: return any errors or warnings in this structure.
1696%
1697*/
1698
1699static inline MagickBooleanType IsNexusInCore(const CacheInfo *cache_info,
1700 NexusInfo *nexus_info)
1701{
1702 MagickOffsetType
1703 offset;
1704
cristy73724512010-04-12 14:43:14 +00001705 if (cache_info->type == PingCache)
1706 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001707 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1708 nexus_info->region.x;
1709 if (nexus_info->pixels != (cache_info->pixels+offset))
1710 return(MagickFalse);
1711 return(MagickTrue);
1712}
1713
cristye076a6e2010-08-15 19:59:43 +00001714MagickExport PixelPacket *GetAuthenticPixelCacheNexus(Image *image,
1715 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001716 NexusInfo *nexus_info,ExceptionInfo *exception)
1717{
1718 CacheInfo
1719 *cache_info;
1720
1721 PixelPacket
1722 *pixels;
1723
1724 /*
1725 Transfer pixels from the cache.
1726 */
1727 assert(image != (Image *) NULL);
1728 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001729 pixels=QueueAuthenticNexus(image,x,y,columns,rows,nexus_info,exception);
1730 if (pixels == (PixelPacket *) NULL)
1731 return((PixelPacket *) NULL);
1732 cache_info=(CacheInfo *) image->cache;
1733 assert(cache_info->signature == MagickSignature);
1734 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
1735 return(pixels);
1736 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1737 return((PixelPacket *) NULL);
1738 if (cache_info->active_index_channel != MagickFalse)
1739 if (ReadPixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse)
1740 return((PixelPacket *) NULL);
1741 return(pixels);
1742}
1743
1744/*
1745%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1746% %
1747% %
1748% %
1749+ 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 %
1750% %
1751% %
1752% %
1753%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1754%
1755% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1756% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1757%
1758% The format of the GetAuthenticPixelsFromCache() method is:
1759%
1760% PixelPacket *GetAuthenticPixelsFromCache(const Image image)
1761%
1762% A description of each parameter follows:
1763%
1764% o image: the image.
1765%
1766*/
1767static PixelPacket *GetAuthenticPixelsFromCache(const Image *image)
1768{
1769 CacheInfo
1770 *cache_info;
1771
cristy5c9e6f22010-09-17 17:31:01 +00001772 const int
1773 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001774
cristy3ed852e2009-09-05 21:47:34 +00001775 cache_info=(CacheInfo *) image->cache;
cristy6ebe97c2010-07-03 01:17:28 +00001776 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001777 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001778}
1779
1780/*
1781%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1782% %
1783% %
1784% %
1785% G e t A u t h e n t i c P i x e l Q u e u e %
1786% %
1787% %
1788% %
1789%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1790%
1791% GetAuthenticPixelQueue() returns the authentic pixels associated with the
1792% last call to QueueAuthenticPixels() or GetAuthenticPixels().
1793%
1794% The format of the GetAuthenticPixelQueue() method is:
1795%
1796% PixelPacket *GetAuthenticPixelQueue(const Image image)
1797%
1798% A description of each parameter follows:
1799%
1800% o image: the image.
1801%
1802*/
1803MagickExport PixelPacket *GetAuthenticPixelQueue(const Image *image)
1804{
1805 CacheInfo
1806 *cache_info;
1807
1808 assert(image != (const Image *) NULL);
1809 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001810 assert(image->cache != (Cache) NULL);
1811 cache_info=(CacheInfo *) image->cache;
1812 assert(cache_info->signature == MagickSignature);
1813 if (cache_info->methods.get_authentic_pixels_from_handler ==
1814 (GetAuthenticPixelsFromHandler) NULL)
1815 return((PixelPacket *) NULL);
1816 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1817}
1818
1819/*
1820%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1821% %
1822% %
1823% %
1824% G e t A u t h e n t i c P i x e l s %
1825% %
1826% %
1827% %
1828%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1829%
1830% GetAuthenticPixels() obtains a pixel region for read/write access. If the
1831% region is successfully accessed, a pointer to a PixelPacket array
1832% representing the region is returned, otherwise NULL is returned.
1833%
1834% The returned pointer may point to a temporary working copy of the pixels
1835% or it may point to the original pixels in memory. Performance is maximized
1836% if the selected region is part of one row, or one or more full rows, since
1837% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001838% if the image is in memory, or in a memory-mapped file. The returned pointer
1839% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001840%
1841% Pixels accessed via the returned pointer represent a simple array of type
1842% PixelPacket. If the image type is CMYK or if the storage class is
1843% PseduoClass, call GetAuthenticIndexQueue() after invoking
1844% GetAuthenticPixels() to obtain the black color component or colormap indexes
1845% (of type IndexPacket) corresponding to the region. Once the PixelPacket
1846% (and/or IndexPacket) array has been updated, the changes must be saved back
1847% to the underlying image using SyncAuthenticPixels() or they may be lost.
1848%
1849% The format of the GetAuthenticPixels() method is:
1850%
cristy5f959472010-05-27 22:19:46 +00001851% PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1852% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001853% ExceptionInfo *exception)
1854%
1855% A description of each parameter follows:
1856%
1857% o image: the image.
1858%
1859% o x,y,columns,rows: These values define the perimeter of a region of
1860% pixels.
1861%
1862% o exception: return any errors or warnings in this structure.
1863%
1864*/
cristybb503372010-05-27 20:51:26 +00001865MagickExport PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1866 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001867 ExceptionInfo *exception)
1868{
1869 CacheInfo
1870 *cache_info;
1871
1872 PixelPacket
1873 *pixels;
1874
1875 assert(image != (Image *) NULL);
1876 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001877 assert(image->cache != (Cache) NULL);
1878 cache_info=(CacheInfo *) image->cache;
1879 assert(cache_info->signature == MagickSignature);
1880 if (cache_info->methods.get_authentic_pixels_handler ==
1881 (GetAuthenticPixelsHandler) NULL)
1882 return((PixelPacket *) NULL);
1883 pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1884 rows,exception);
1885 return(pixels);
1886}
1887
1888/*
1889%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1890% %
1891% %
1892% %
1893+ G e t A u t h e n t i c P i x e l s C a c h e %
1894% %
1895% %
1896% %
1897%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1898%
1899% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1900% as defined by the geometry parameters. A pointer to the pixels is returned
1901% if the pixels are transferred, otherwise a NULL is returned.
1902%
1903% The format of the GetAuthenticPixelsCache() method is:
1904%
cristybb503372010-05-27 20:51:26 +00001905% PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1906% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001907% ExceptionInfo *exception)
1908%
1909% A description of each parameter follows:
1910%
1911% o image: the image.
1912%
1913% o x,y,columns,rows: These values define the perimeter of a region of
1914% pixels.
1915%
1916% o exception: return any errors or warnings in this structure.
1917%
1918*/
cristybb503372010-05-27 20:51:26 +00001919static PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1920 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001921 ExceptionInfo *exception)
1922{
1923 CacheInfo
1924 *cache_info;
1925
cristy5c9e6f22010-09-17 17:31:01 +00001926 const int
1927 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001928
cristy77ff0282010-09-13 00:51:10 +00001929 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001930 if (cache_info == (Cache) NULL)
1931 return((PixelPacket *) NULL);
cristy6ebe97c2010-07-03 01:17:28 +00001932 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001933 return(GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1934 cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00001935}
1936
1937/*
1938%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1939% %
1940% %
1941% %
1942+ G e t I m a g e E x t e n t %
1943% %
1944% %
1945% %
1946%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1947%
1948% GetImageExtent() returns the extent of the pixels associated with the
1949% last call to QueueAuthenticPixels() or GetAuthenticPixels().
1950%
1951% The format of the GetImageExtent() method is:
1952%
1953% MagickSizeType GetImageExtent(const Image *image)
1954%
1955% A description of each parameter follows:
1956%
1957% o image: the image.
1958%
1959*/
1960MagickExport MagickSizeType GetImageExtent(const Image *image)
1961{
1962 CacheInfo
1963 *cache_info;
1964
cristy5c9e6f22010-09-17 17:31:01 +00001965 const int
1966 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001967
cristy3ed852e2009-09-05 21:47:34 +00001968 assert(image != (Image *) NULL);
1969 assert(image->signature == MagickSignature);
1970 if (image->debug != MagickFalse)
1971 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1972 assert(image->cache != (Cache) NULL);
1973 cache_info=(CacheInfo *) image->cache;
1974 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001975 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001976 return(GetPixelCacheNexusExtent(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001977}
1978
1979/*
1980%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1981% %
1982% %
1983% %
1984+ G e t I m a g e P i x e l C a c h e %
1985% %
1986% %
1987% %
1988%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1989%
1990% GetImagePixelCache() ensures that there is only a single reference to the
1991% pixel cache to be modified, updating the provided cache pointer to point to
1992% a clone of the original pixel cache if necessary.
1993%
1994% The format of the GetImagePixelCache method is:
1995%
1996% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1997% ExceptionInfo *exception)
1998%
1999% A description of each parameter follows:
2000%
2001% o image: the image.
2002%
2003% o clone: any value other than MagickFalse clones the cache pixels.
2004%
2005% o exception: return any errors or warnings in this structure.
2006%
2007*/
cristy3ed852e2009-09-05 21:47:34 +00002008static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
2009{
2010 CacheInfo
2011 *cache_info;
2012
2013 /*
2014 Does the image match the pixel cache morphology?
2015 */
2016 cache_info=(CacheInfo *) image->cache;
2017 if ((image->storage_class != cache_info->storage_class) ||
2018 (image->colorspace != cache_info->colorspace) ||
2019 (image->columns != cache_info->columns) ||
2020 (image->rows != cache_info->rows) ||
2021 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2022 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2023 return(MagickFalse);
2024 return(MagickTrue);
2025}
2026
cristy77ff0282010-09-13 00:51:10 +00002027static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2028 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002029{
2030 CacheInfo
2031 *cache_info;
2032
cristy3ed852e2009-09-05 21:47:34 +00002033 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00002034 destroy,
cristy3ed852e2009-09-05 21:47:34 +00002035 status;
2036
cristy50a10922010-02-15 18:35:25 +00002037 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00002038 cpu_throttle = 0,
2039 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00002040 time_limit = 0;
2041
cristy1ea34962010-07-01 19:49:21 +00002042 static time_t
cristya21afde2010-07-02 00:45:40 +00002043 cache_genesis = 0;
cristy1ea34962010-07-01 19:49:21 +00002044
cristyc4f9f132010-03-04 18:50:01 +00002045 status=MagickTrue;
2046 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00002047 if (cpu_throttle == 0)
2048 {
2049 char
2050 *limit;
2051
2052 /*
2053 Set CPU throttle in milleseconds.
2054 */
2055 cpu_throttle=MagickResourceInfinity;
2056 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2057 if (limit == (char *) NULL)
2058 limit=GetPolicyValue("throttle");
2059 if (limit != (char *) NULL)
2060 {
2061 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2062 limit=DestroyString(limit);
2063 }
2064 }
2065 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2066 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00002067 if (time_limit == 0)
2068 {
cristy6ebe97c2010-07-03 01:17:28 +00002069 /*
2070 Set the exire time in seconds.
2071 */
cristy1ea34962010-07-01 19:49:21 +00002072 time_limit=GetMagickResourceLimit(TimeResource);
cristya21afde2010-07-02 00:45:40 +00002073 cache_genesis=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00002074 }
2075 if ((time_limit != MagickResourceInfinity) &&
cristya21afde2010-07-02 00:45:40 +00002076 ((MagickSizeType) (time((time_t *) NULL)-cache_genesis) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00002077 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00002078 assert(image->cache != (Cache) NULL);
2079 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002080 destroy=MagickFalse;
cristy01b7eb02009-09-10 23:10:14 +00002081 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002082 {
cristyaaa0cb62010-02-15 17:47:27 +00002083 LockSemaphoreInfo(cache_info->semaphore);
2084 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002085 {
cristyaaa0cb62010-02-15 17:47:27 +00002086 Image
2087 clone_image;
2088
2089 CacheInfo
2090 *clone_info;
2091
2092 /*
2093 Clone pixel cache.
2094 */
2095 clone_image=(*image);
cristy93505cf2010-08-10 21:37:49 +00002096 clone_image.semaphore=AllocateSemaphoreInfo();
2097 clone_image.reference_count=1;
cristyaaa0cb62010-02-15 17:47:27 +00002098 clone_image.cache=ClonePixelCache(cache_info);
2099 clone_info=(CacheInfo *) clone_image.cache;
cristyabd6e372010-09-15 19:11:26 +00002100 status=OpenPixelCache(&clone_image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00002101 if (status != MagickFalse)
2102 {
cristyabd6e372010-09-15 19:11:26 +00002103 if (clone != MagickFalse)
2104 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00002105 if (status != MagickFalse)
2106 {
cristyabd6e372010-09-15 19:11:26 +00002107 destroy=MagickTrue;
2108 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00002109 }
2110 }
cristy93505cf2010-08-10 21:37:49 +00002111 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002112 }
cristyaaa0cb62010-02-15 17:47:27 +00002113 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002114 }
cristy4320e0e2009-09-10 15:00:08 +00002115 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002116 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002117 if (status != MagickFalse)
2118 {
2119 /*
2120 Ensure the image matches the pixel cache morphology.
2121 */
2122 image->taint=MagickTrue;
2123 image->type=UndefinedType;
cristydd438462010-05-06 13:44:04 +00002124 if (image->colorspace == GRAYColorspace)
2125 image->colorspace=RGBColorspace;
cristy3ed852e2009-09-05 21:47:34 +00002126 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2127 status=OpenPixelCache(image,IOMode,exception);
2128 }
cristyf84a1932010-01-03 18:00:18 +00002129 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002130 if (status == MagickFalse)
2131 return((Cache) NULL);
2132 return(image->cache);
2133}
2134
2135/*
2136%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2137% %
2138% %
2139% %
2140% G e t O n e A u t h e n t i c P i x e l %
2141% %
2142% %
2143% %
2144%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2145%
2146% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2147% location. The image background color is returned if an error occurs.
2148%
2149% The format of the GetOneAuthenticPixel() method is:
2150%
cristybb503372010-05-27 20:51:26 +00002151% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2152% const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002153%
2154% A description of each parameter follows:
2155%
2156% o image: the image.
2157%
2158% o x,y: These values define the location of the pixel to return.
2159%
2160% o pixel: return a pixel at the specified (x,y) location.
2161%
2162% o exception: return any errors or warnings in this structure.
2163%
2164*/
cristyacbbb7c2010-06-30 18:56:48 +00002165MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2166 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002167{
2168 CacheInfo
2169 *cache_info;
2170
2171 GetOneAuthenticPixelFromHandler
2172 get_one_authentic_pixel_from_handler;
2173
2174 MagickBooleanType
2175 status;
2176
2177 assert(image != (Image *) NULL);
2178 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002179 assert(image->cache != (Cache) NULL);
2180 cache_info=(CacheInfo *) image->cache;
2181 assert(cache_info->signature == MagickSignature);
2182 *pixel=image->background_color;
2183 get_one_authentic_pixel_from_handler=
2184 cache_info->methods.get_one_authentic_pixel_from_handler;
2185 if (get_one_authentic_pixel_from_handler ==
2186 (GetOneAuthenticPixelFromHandler) NULL)
2187 return(MagickFalse);
2188 status=cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2189 pixel,exception);
2190 return(status);
2191}
2192
2193/*
2194%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2195% %
2196% %
2197% %
2198+ 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 %
2199% %
2200% %
2201% %
2202%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2203%
2204% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2205% location. The image background color is returned if an error occurs.
2206%
2207% The format of the GetOneAuthenticPixelFromCache() method is:
2208%
2209% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy5f959472010-05-27 22:19:46 +00002210% const ssize_t x,const ssize_t y,PixelPacket *pixel,
2211% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002212%
2213% A description of each parameter follows:
2214%
2215% o image: the image.
2216%
2217% o x,y: These values define the location of the pixel to return.
2218%
2219% o pixel: return a pixel at the specified (x,y) location.
2220%
2221% o exception: return any errors or warnings in this structure.
2222%
2223*/
2224static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristybb503372010-05-27 20:51:26 +00002225 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002226{
2227 PixelPacket
2228 *pixels;
2229
cristy3ed852e2009-09-05 21:47:34 +00002230 *pixel=image->background_color;
2231 pixels=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2232 if (pixels == (PixelPacket *) NULL)
2233 return(MagickFalse);
2234 *pixel=(*pixels);
2235 return(MagickTrue);
2236}
2237
2238/*
2239%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2240% %
2241% %
2242% %
2243% G e t O n e V i r t u a l M a g i c k P i x e l %
2244% %
2245% %
2246% %
2247%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2248%
2249% GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2250% location. The image background color is returned if an error occurs. If
2251% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2252%
2253% The format of the GetOneVirtualMagickPixel() method is:
2254%
2255% MagickBooleanType GetOneVirtualMagickPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002256% const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
cristy3ed852e2009-09-05 21:47:34 +00002257% ExceptionInfo exception)
2258%
2259% A description of each parameter follows:
2260%
2261% o image: the image.
2262%
2263% o x,y: these values define the location of the pixel to return.
2264%
2265% o pixel: return a pixel at the specified (x,y) location.
2266%
2267% o exception: return any errors or warnings in this structure.
2268%
2269*/
2270MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
cristyacbbb7c2010-06-30 18:56:48 +00002271 const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
2272 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002273{
2274 CacheInfo
2275 *cache_info;
2276
2277 register const IndexPacket
2278 *indexes;
2279
2280 register const PixelPacket
2281 *p;
2282
2283 assert(image != (const Image *) NULL);
2284 assert(image->signature == MagickSignature);
2285 assert(image->cache != (Cache) NULL);
2286 cache_info=(CacheInfo *) image->cache;
2287 assert(cache_info->signature == MagickSignature);
2288 GetMagickPixelPacket(image,pixel);
2289 p=GetVirtualPixelCache(image,GetPixelCacheVirtualMethod(image),x,y,1,1,
2290 exception);
2291 if (p == (const PixelPacket *) NULL)
2292 return(MagickFalse);
2293 indexes=GetVirtualIndexQueue(image);
2294 SetMagickPixelPacket(image,p,indexes,pixel);
2295 return(MagickTrue);
2296}
2297
2298/*
2299%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2300% %
2301% %
2302% %
2303% G e t O n e V i r t u a l M e t h o d P i x e l %
2304% %
2305% %
2306% %
2307%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2308%
2309% GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2310% location as defined by specified pixel method. The image background color
2311% is returned if an error occurs. If you plan to modify the pixel, use
2312% GetOneAuthenticPixel() instead.
2313%
2314% The format of the GetOneVirtualMethodPixel() method is:
2315%
2316% MagickBooleanType GetOneVirtualMethodPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002317% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2318% const ssize_t y,Pixelpacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002319%
2320% A description of each parameter follows:
2321%
2322% o image: the image.
2323%
2324% o virtual_pixel_method: the virtual pixel method.
2325%
2326% o x,y: These values define the location of the pixel to return.
2327%
2328% o pixel: return a pixel at the specified (x,y) location.
2329%
2330% o exception: return any errors or warnings in this structure.
2331%
2332*/
2333MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002334 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002335 PixelPacket *pixel,ExceptionInfo *exception)
2336{
2337 GetOneVirtualPixelFromHandler
2338 get_one_virtual_pixel_from_handler;
2339
2340 CacheInfo
2341 *cache_info;
2342
2343 MagickBooleanType
2344 status;
2345
2346 assert(image != (const Image *) NULL);
2347 assert(image->signature == MagickSignature);
2348 assert(image->cache != (Cache) NULL);
2349 cache_info=(CacheInfo *) image->cache;
2350 assert(cache_info->signature == MagickSignature);
2351 *pixel=image->background_color;
2352 get_one_virtual_pixel_from_handler=
2353 cache_info->methods.get_one_virtual_pixel_from_handler;
2354 if (get_one_virtual_pixel_from_handler ==
2355 (GetOneVirtualPixelFromHandler) NULL)
2356 return(MagickFalse);
2357 status=get_one_virtual_pixel_from_handler(image,virtual_pixel_method,x,y,
2358 pixel,exception);
2359 return(status);
2360}
2361
2362/*
2363%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2364% %
2365% %
2366% %
2367% G e t O n e V i r t u a l P i x e l %
2368% %
2369% %
2370% %
2371%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2372%
2373% GetOneVirtualPixel() returns a single virtual pixel at the specified
2374% (x,y) location. The image background color is returned if an error occurs.
2375% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2376%
2377% The format of the GetOneVirtualPixel() method is:
2378%
cristybb503372010-05-27 20:51:26 +00002379% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2380% const ssize_t y,PixelPacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002381%
2382% A description of each parameter follows:
2383%
2384% o image: the image.
2385%
2386% o x,y: These values define the location of the pixel to return.
2387%
2388% o pixel: return a pixel at the specified (x,y) location.
2389%
2390% o exception: return any errors or warnings in this structure.
2391%
2392*/
2393MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002394 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002395{
2396 GetOneVirtualPixelFromHandler
2397 get_one_virtual_pixel_from_handler;
2398
2399 CacheInfo
2400 *cache_info;
2401
2402 MagickBooleanType
2403 status;
2404
2405 assert(image != (const Image *) NULL);
2406 assert(image->signature == MagickSignature);
2407 assert(image->cache != (Cache) NULL);
2408 cache_info=(CacheInfo *) image->cache;
2409 assert(cache_info->signature == MagickSignature);
2410 *pixel=image->background_color;
2411 get_one_virtual_pixel_from_handler=
2412 cache_info->methods.get_one_virtual_pixel_from_handler;
2413 if (get_one_virtual_pixel_from_handler ==
2414 (GetOneVirtualPixelFromHandler) NULL)
2415 return(MagickFalse);
2416 status=get_one_virtual_pixel_from_handler(image,GetPixelCacheVirtualMethod(
2417 image),x,y,pixel,exception);
2418 return(status);
2419}
2420
2421/*
2422%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2423% %
2424% %
2425% %
2426+ 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 %
2427% %
2428% %
2429% %
2430%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2431%
2432% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2433% specified (x,y) location. The image background color is returned if an
2434% error occurs.
2435%
2436% The format of the GetOneVirtualPixelFromCache() method is:
2437%
2438% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristybb503372010-05-27 20:51:26 +00002439% const VirtualPixelPacket method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002440% PixelPacket *pixel,ExceptionInfo *exception)
2441%
2442% A description of each parameter follows:
2443%
2444% o image: the image.
2445%
2446% o virtual_pixel_method: the virtual pixel method.
2447%
2448% o x,y: These values define the location of the pixel to return.
2449%
2450% o pixel: return a pixel at the specified (x,y) location.
2451%
2452% o exception: return any errors or warnings in this structure.
2453%
2454*/
2455static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002456 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002457 PixelPacket *pixel,ExceptionInfo *exception)
2458{
2459 const PixelPacket
2460 *pixels;
2461
2462 *pixel=image->background_color;
2463 pixels=GetVirtualPixelCache(image,virtual_pixel_method,x,y,1UL,1UL,exception);
2464 if (pixels == (const PixelPacket *) NULL)
2465 return(MagickFalse);
2466 *pixel=(*pixels);
2467 return(MagickTrue);
2468}
2469
2470/*
2471%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2472% %
2473% %
2474% %
2475+ G e t P i x e l C a c h e C o l o r s p a c e %
2476% %
2477% %
2478% %
2479%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2480%
2481% GetPixelCacheColorspace() returns the class type of the pixel cache.
2482%
2483% The format of the GetPixelCacheColorspace() method is:
2484%
2485% Colorspace GetPixelCacheColorspace(Cache cache)
2486%
2487% A description of each parameter follows:
2488%
2489% o cache: the pixel cache.
2490%
2491*/
2492MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
2493{
2494 CacheInfo
2495 *cache_info;
2496
2497 assert(cache != (Cache) NULL);
2498 cache_info=(CacheInfo *) cache;
2499 assert(cache_info->signature == MagickSignature);
2500 if (cache_info->debug != MagickFalse)
2501 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2502 cache_info->filename);
2503 return(cache_info->colorspace);
2504}
2505
2506/*
2507%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2508% %
2509% %
2510% %
2511+ G e t P i x e l C a c h e M e t h o d s %
2512% %
2513% %
2514% %
2515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2516%
2517% GetPixelCacheMethods() initializes the CacheMethods structure.
2518%
2519% The format of the GetPixelCacheMethods() method is:
2520%
2521% void GetPixelCacheMethods(CacheMethods *cache_methods)
2522%
2523% A description of each parameter follows:
2524%
2525% o cache_methods: Specifies a pointer to a CacheMethods structure.
2526%
2527*/
2528MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
2529{
2530 assert(cache_methods != (CacheMethods *) NULL);
2531 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2532 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2533 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2534 cache_methods->get_virtual_indexes_from_handler=GetVirtualIndexesFromCache;
2535 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2536 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2537 cache_methods->get_authentic_indexes_from_handler=
2538 GetAuthenticIndexesFromCache;
2539 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2540 cache_methods->get_one_authentic_pixel_from_handler=
2541 GetOneAuthenticPixelFromCache;
2542 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2543 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2544 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2545}
2546
2547/*
2548%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2549% %
2550% %
2551% %
2552+ G e t P i x e l C a c h e N e x u s E x t e n t %
2553% %
2554% %
2555% %
2556%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2557%
2558% GetPixelCacheNexusExtent() returns the extent of the pixels associated with
2559% the last call to SetPixelCacheNexusPixels() or GetPixelCacheNexusPixels().
2560%
2561% The format of the GetPixelCacheNexusExtent() method is:
2562%
2563% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2564% NexusInfo *nexus_info)
2565%
2566% A description of each parameter follows:
2567%
2568% o nexus_info: the nexus info.
2569%
2570*/
2571MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2572 NexusInfo *nexus_info)
2573{
2574 CacheInfo
2575 *cache_info;
2576
2577 MagickSizeType
2578 extent;
2579
2580 if (cache == (Cache) NULL)
2581 return(0);
2582 cache_info=(CacheInfo *) cache;
2583 assert(cache_info->signature == MagickSignature);
2584 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2585 if (extent == 0)
2586 return((MagickSizeType) cache_info->columns*cache_info->rows);
2587 return(extent);
2588}
2589
2590/*
2591%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2592% %
2593% %
2594% %
2595+ 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 %
2596% %
2597% %
2598% %
2599%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2600%
2601% GetPixelCacheNexusIndexes() returns the indexes associated with the
2602% specified cache nexus.
2603%
2604% The format of the GetPixelCacheNexusIndexes() method is:
2605%
2606% IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2607% NexusInfo *nexus_info)
2608%
2609% A description of each parameter follows:
2610%
2611% o cache: the pixel cache.
2612%
2613% o nexus_info: the cache nexus to return the colormap indexes.
2614%
2615*/
2616MagickExport IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2617 NexusInfo *nexus_info)
2618{
2619 CacheInfo
2620 *cache_info;
2621
2622 if (cache == (Cache) NULL)
2623 return((IndexPacket *) NULL);
2624 cache_info=(CacheInfo *) cache;
2625 assert(cache_info->signature == MagickSignature);
2626 if (cache_info->storage_class == UndefinedClass)
2627 return((IndexPacket *) NULL);
2628 return(nexus_info->indexes);
2629}
2630
2631/*
2632%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2633% %
2634% %
2635% %
2636+ G e t P i x e l C a c h e N e x u s P i x e l s %
2637% %
2638% %
2639% %
2640%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2641%
2642% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2643% cache nexus.
2644%
2645% The format of the GetPixelCacheNexusPixels() method is:
2646%
2647% PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2648% NexusInfo *nexus_info)
2649%
2650% A description of each parameter follows:
2651%
2652% o cache: the pixel cache.
2653%
2654% o nexus_info: the cache nexus to return the pixels.
2655%
2656*/
2657MagickExport PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2658 NexusInfo *nexus_info)
2659{
2660 CacheInfo
2661 *cache_info;
2662
2663 if (cache == (Cache) NULL)
2664 return((PixelPacket *) NULL);
2665 cache_info=(CacheInfo *) cache;
2666 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002667 if (cache_info->storage_class == UndefinedClass)
2668 return((PixelPacket *) NULL);
2669 return(nexus_info->pixels);
2670}
2671
2672/*
2673%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2674% %
2675% %
2676% %
cristy056ba772010-01-02 23:33:54 +00002677+ G e t P i x e l C a c h e P i x e l s %
2678% %
2679% %
2680% %
2681%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2682%
2683% GetPixelCachePixels() returns the pixels associated with the specified image.
2684%
2685% The format of the GetPixelCachePixels() method is:
2686%
cristyf84a1932010-01-03 18:00:18 +00002687% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2688% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002689%
2690% A description of each parameter follows:
2691%
2692% o image: the image.
2693%
2694% o length: the pixel cache length.
2695%
cristyf84a1932010-01-03 18:00:18 +00002696% o exception: return any errors or warnings in this structure.
2697%
cristy056ba772010-01-02 23:33:54 +00002698*/
cristyf84a1932010-01-03 18:00:18 +00002699MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2700 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002701{
2702 CacheInfo
2703 *cache_info;
2704
2705 assert(image != (const Image *) NULL);
2706 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002707 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00002708 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002709 assert(cache_info->signature == MagickSignature);
2710 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002711 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002712 return((void *) NULL);
2713 *length=cache_info->length;
2714 return((void *) cache_info->pixels);
2715}
2716
2717/*
2718%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2719% %
2720% %
2721% %
cristyb32b90a2009-09-07 21:45:48 +00002722+ 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 +00002723% %
2724% %
2725% %
2726%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2727%
2728% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2729%
2730% The format of the GetPixelCacheStorageClass() method is:
2731%
2732% ClassType GetPixelCacheStorageClass(Cache cache)
2733%
2734% A description of each parameter follows:
2735%
2736% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2737%
2738% o cache: the pixel cache.
2739%
2740*/
2741MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
2742{
2743 CacheInfo
2744 *cache_info;
2745
2746 assert(cache != (Cache) NULL);
2747 cache_info=(CacheInfo *) cache;
2748 assert(cache_info->signature == MagickSignature);
2749 if (cache_info->debug != MagickFalse)
2750 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2751 cache_info->filename);
2752 return(cache_info->storage_class);
2753}
2754
2755/*
2756%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2757% %
2758% %
2759% %
cristyb32b90a2009-09-07 21:45:48 +00002760+ G e t P i x e l C a c h e T i l e S i z e %
2761% %
2762% %
2763% %
2764%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2765%
2766% GetPixelCacheTileSize() returns the pixel cache tile size.
2767%
2768% The format of the GetPixelCacheTileSize() method is:
2769%
cristybb503372010-05-27 20:51:26 +00002770% void GetPixelCacheTileSize(const Image *image,size_t *width,
2771% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002772%
2773% A description of each parameter follows:
2774%
2775% o image: the image.
2776%
2777% o width: the optimize cache tile width in pixels.
2778%
2779% o height: the optimize cache tile height in pixels.
2780%
2781*/
cristybb503372010-05-27 20:51:26 +00002782MagickExport void GetPixelCacheTileSize(const Image *image,size_t *width,
2783 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002784{
2785 CacheInfo
2786 *cache_info;
2787
2788 assert(image != (Image *) NULL);
2789 assert(image->signature == MagickSignature);
2790 if (image->debug != MagickFalse)
2791 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2792 assert(image->cache != (Cache) NULL);
2793 cache_info=(CacheInfo *) image->cache;
2794 assert(cache_info->signature == MagickSignature);
2795 *width=2048UL/sizeof(PixelPacket);
2796 if (GetPixelCacheType(image) == DiskCache)
cristydaa97692009-09-13 02:10:35 +00002797 *width=8192UL/sizeof(PixelPacket);
cristyb32b90a2009-09-07 21:45:48 +00002798 *height=(*width);
2799}
2800
2801/*
2802%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2803% %
2804% %
2805% %
2806+ G e t P i x e l C a c h e T y p e %
2807% %
2808% %
2809% %
2810%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2811%
2812% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2813%
2814% The format of the GetPixelCacheType() method is:
2815%
2816% CacheType GetPixelCacheType(const Image *image)
2817%
2818% A description of each parameter follows:
2819%
2820% o image: the image.
2821%
2822*/
2823MagickExport CacheType GetPixelCacheType(const Image *image)
2824{
2825 CacheInfo
2826 *cache_info;
2827
2828 assert(image != (Image *) NULL);
2829 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002830 assert(image->cache != (Cache) NULL);
2831 cache_info=(CacheInfo *) image->cache;
2832 assert(cache_info->signature == MagickSignature);
2833 return(cache_info->type);
2834}
2835
2836/*
2837%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2838% %
2839% %
2840% %
cristy3ed852e2009-09-05 21:47:34 +00002841+ 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 %
2842% %
2843% %
2844% %
2845%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2846%
2847% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2848% pixel cache. A virtual pixel is any pixel access that is outside the
2849% boundaries of the image cache.
2850%
2851% The format of the GetPixelCacheVirtualMethod() method is:
2852%
2853% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2854%
2855% A description of each parameter follows:
2856%
2857% o image: the image.
2858%
2859*/
2860MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2861{
2862 CacheInfo
2863 *cache_info;
2864
2865 assert(image != (Image *) NULL);
2866 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002867 assert(image->cache != (Cache) NULL);
2868 cache_info=(CacheInfo *) image->cache;
2869 assert(cache_info->signature == MagickSignature);
2870 return(cache_info->virtual_pixel_method);
2871}
2872
2873/*
2874%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2875% %
2876% %
2877% %
2878+ 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 %
2879% %
2880% %
2881% %
2882%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2883%
2884% GetVirtualIndexesFromCache() returns the indexes associated with the last
2885% call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2886%
2887% The format of the GetVirtualIndexesFromCache() method is:
2888%
2889% IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2890%
2891% A description of each parameter follows:
2892%
2893% o image: the image.
2894%
2895*/
2896static const IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2897{
2898 CacheInfo
2899 *cache_info;
2900
cristy5c9e6f22010-09-17 17:31:01 +00002901 const int
2902 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002903
cristy3ed852e2009-09-05 21:47:34 +00002904 cache_info=(CacheInfo *) image->cache;
cristy6ebe97c2010-07-03 01:17:28 +00002905 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00002906 return(GetVirtualIndexesFromNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00002907}
2908
2909/*
2910%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2911% %
2912% %
2913% %
2914+ 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 %
2915% %
2916% %
2917% %
2918%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2919%
2920% GetVirtualIndexesFromNexus() returns the indexes associated with the
2921% specified cache nexus.
2922%
2923% The format of the GetVirtualIndexesFromNexus() method is:
2924%
2925% const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2926% NexusInfo *nexus_info)
2927%
2928% A description of each parameter follows:
2929%
2930% o cache: the pixel cache.
2931%
2932% o nexus_info: the cache nexus to return the colormap indexes.
2933%
2934*/
2935MagickExport const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2936 NexusInfo *nexus_info)
2937{
2938 CacheInfo
2939 *cache_info;
2940
2941 if (cache == (Cache) NULL)
2942 return((IndexPacket *) NULL);
2943 cache_info=(CacheInfo *) cache;
2944 assert(cache_info->signature == MagickSignature);
2945 if (cache_info->storage_class == UndefinedClass)
2946 return((IndexPacket *) NULL);
2947 return(nexus_info->indexes);
2948}
2949
2950/*
2951%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2952% %
2953% %
2954% %
2955% G e t V i r t u a l I n d e x Q u e u e %
2956% %
2957% %
2958% %
2959%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2960%
2961% GetVirtualIndexQueue() returns the virtual black channel or the
2962% colormap indexes associated with the last call to QueueAuthenticPixels() or
2963% GetVirtualPixels(). NULL is returned if the black channel or colormap
2964% indexes are not available.
2965%
2966% The format of the GetVirtualIndexQueue() method is:
2967%
2968% const IndexPacket *GetVirtualIndexQueue(const Image *image)
2969%
2970% A description of each parameter follows:
2971%
2972% o image: the image.
2973%
2974*/
2975MagickExport const IndexPacket *GetVirtualIndexQueue(const Image *image)
2976{
2977 CacheInfo
2978 *cache_info;
2979
2980 assert(image != (const Image *) NULL);
2981 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002982 assert(image->cache != (Cache) NULL);
2983 cache_info=(CacheInfo *) image->cache;
2984 assert(cache_info->signature == MagickSignature);
2985 if (cache_info->methods.get_virtual_indexes_from_handler ==
2986 (GetVirtualIndexesFromHandler) NULL)
2987 return((IndexPacket *) NULL);
2988 return(cache_info->methods.get_virtual_indexes_from_handler(image));
2989}
2990
2991/*
2992%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2993% %
2994% %
2995% %
2996+ 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 %
2997% %
2998% %
2999% %
3000%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3001%
3002% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3003% pixel cache as defined by the geometry parameters. A pointer to the pixels
3004% is returned if the pixels are transferred, otherwise a NULL is returned.
3005%
3006% The format of the GetVirtualPixelsFromNexus() method is:
3007%
3008% PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003009% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00003010% const size_t columns,const size_t rows,NexusInfo *nexus_info,
3011% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003012%
3013% A description of each parameter follows:
3014%
3015% o image: the image.
3016%
3017% o virtual_pixel_method: the virtual pixel method.
3018%
3019% o x,y,columns,rows: These values define the perimeter of a region of
3020% pixels.
3021%
3022% o nexus_info: the cache nexus to acquire.
3023%
3024% o exception: return any errors or warnings in this structure.
3025%
3026*/
3027
cristybb503372010-05-27 20:51:26 +00003028static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003029 DitherMatrix[64] =
3030 {
3031 0, 48, 12, 60, 3, 51, 15, 63,
3032 32, 16, 44, 28, 35, 19, 47, 31,
3033 8, 56, 4, 52, 11, 59, 7, 55,
3034 40, 24, 36, 20, 43, 27, 39, 23,
3035 2, 50, 14, 62, 1, 49, 13, 61,
3036 34, 18, 46, 30, 33, 17, 45, 29,
3037 10, 58, 6, 54, 9, 57, 5, 53,
3038 42, 26, 38, 22, 41, 25, 37, 21
3039 };
3040
cristybb503372010-05-27 20:51:26 +00003041static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003042{
cristybb503372010-05-27 20:51:26 +00003043 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003044 index;
3045
3046 index=x+DitherMatrix[x & 0x07]-32L;
3047 if (index < 0L)
3048 return(0L);
cristybb503372010-05-27 20:51:26 +00003049 if (index >= (ssize_t) columns)
3050 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00003051 return(index);
3052}
3053
cristybb503372010-05-27 20:51:26 +00003054static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003055{
cristybb503372010-05-27 20:51:26 +00003056 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003057 index;
3058
3059 index=y+DitherMatrix[y & 0x07]-32L;
3060 if (index < 0L)
3061 return(0L);
cristybb503372010-05-27 20:51:26 +00003062 if (index >= (ssize_t) rows)
3063 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00003064 return(index);
3065}
3066
cristybb503372010-05-27 20:51:26 +00003067static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003068{
3069 if (x < 0L)
3070 return(0L);
cristybb503372010-05-27 20:51:26 +00003071 if (x >= (ssize_t) columns)
3072 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003073 return(x);
3074}
3075
cristybb503372010-05-27 20:51:26 +00003076static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003077{
3078 if (y < 0L)
3079 return(0L);
cristybb503372010-05-27 20:51:26 +00003080 if (y >= (ssize_t) rows)
3081 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003082 return(y);
3083}
3084
cristybb503372010-05-27 20:51:26 +00003085static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003086{
cristybb503372010-05-27 20:51:26 +00003087 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003088}
3089
cristybb503372010-05-27 20:51:26 +00003090static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003091{
cristybb503372010-05-27 20:51:26 +00003092 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003093}
3094
3095/*
3096 VirtualPixelModulo() computes the remainder of dividing offset by extent. It
3097 returns not only the quotient (tile the offset falls in) but also the positive
3098 remainer within that tile such that 0 <= remainder < extent. This method is
3099 essentially a ldiv() using a floored modulo division rather than the normal
3100 default truncated modulo division.
3101*/
cristybb503372010-05-27 20:51:26 +00003102static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3103 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003104{
3105 MagickModulo
3106 modulo;
3107
cristybb503372010-05-27 20:51:26 +00003108 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003109 if (offset < 0L)
3110 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003111 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003112 return(modulo);
3113}
3114
3115MagickExport const PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003116 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3117 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003118 ExceptionInfo *exception)
3119{
3120 CacheInfo
3121 *cache_info;
3122
cristyc3ec0d42010-04-07 01:18:08 +00003123 IndexPacket
3124 virtual_index;
3125
cristy3ed852e2009-09-05 21:47:34 +00003126 MagickOffsetType
3127 offset;
3128
3129 MagickSizeType
3130 length,
3131 number_pixels;
3132
3133 NexusInfo
3134 **virtual_nexus;
3135
3136 PixelPacket
3137 *pixels,
3138 virtual_pixel;
3139
3140 RectangleInfo
3141 region;
3142
3143 register const IndexPacket
cristyc3ec0d42010-04-07 01:18:08 +00003144 *restrict virtual_indexes;
cristy3ed852e2009-09-05 21:47:34 +00003145
3146 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003147 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003148
3149 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003150 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003151
cristye076a6e2010-08-15 19:59:43 +00003152 register PixelPacket
3153 *restrict q;
3154
cristybb503372010-05-27 20:51:26 +00003155 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003156 u,
3157 v;
3158
cristy3ed852e2009-09-05 21:47:34 +00003159 /*
3160 Acquire pixels.
3161 */
cristy3ed852e2009-09-05 21:47:34 +00003162 cache_info=(CacheInfo *) image->cache;
cristy4cfbb3f2010-03-14 20:40:23 +00003163 if (cache_info->type == UndefinedCache)
cristy3ed852e2009-09-05 21:47:34 +00003164 return((const PixelPacket *) NULL);
3165 region.x=x;
3166 region.y=y;
3167 region.width=columns;
3168 region.height=rows;
3169 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
3170 if (pixels == (PixelPacket *) NULL)
3171 return((const PixelPacket *) NULL);
cristydf415c82010-03-11 16:47:50 +00003172 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3173 nexus_info->region.x;
3174 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3175 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003176 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3177 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003178 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3179 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003180 {
3181 MagickBooleanType
3182 status;
3183
3184 /*
3185 Pixel request is inside cache extents.
3186 */
3187 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
3188 return(pixels);
3189 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3190 if (status == MagickFalse)
3191 return((const PixelPacket *) NULL);
3192 if ((cache_info->storage_class == PseudoClass) ||
3193 (cache_info->colorspace == CMYKColorspace))
3194 {
3195 status=ReadPixelCacheIndexes(cache_info,nexus_info,exception);
3196 if (status == MagickFalse)
3197 return((const PixelPacket *) NULL);
3198 }
3199 return(pixels);
3200 }
3201 /*
3202 Pixel request is outside cache extents.
3203 */
3204 q=pixels;
3205 indexes=GetPixelCacheNexusIndexes(cache_info,nexus_info);
3206 virtual_nexus=AcquirePixelCacheNexus(1);
3207 if (virtual_nexus == (NexusInfo **) NULL)
3208 {
3209 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3210 "UnableToGetCacheNexus","`%s'",image->filename);
3211 return((const PixelPacket *) NULL);
3212 }
3213 switch (virtual_pixel_method)
3214 {
3215 case BlackVirtualPixelMethod:
3216 {
cristy4789f0d2010-01-10 00:01:06 +00003217 SetRedPixelComponent(&virtual_pixel,0);
3218 SetGreenPixelComponent(&virtual_pixel,0);
3219 SetBluePixelComponent(&virtual_pixel,0);
3220 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003221 break;
3222 }
3223 case GrayVirtualPixelMethod:
3224 {
cristy4789f0d2010-01-10 00:01:06 +00003225 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3226 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3227 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3228 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003229 break;
3230 }
3231 case TransparentVirtualPixelMethod:
3232 {
cristy4789f0d2010-01-10 00:01:06 +00003233 SetRedPixelComponent(&virtual_pixel,0);
3234 SetGreenPixelComponent(&virtual_pixel,0);
3235 SetBluePixelComponent(&virtual_pixel,0);
3236 SetOpacityPixelComponent(&virtual_pixel,TransparentOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003237 break;
3238 }
3239 case MaskVirtualPixelMethod:
3240 case WhiteVirtualPixelMethod:
3241 {
cristy4789f0d2010-01-10 00:01:06 +00003242 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3243 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3244 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3245 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003246 break;
3247 }
3248 default:
3249 {
3250 virtual_pixel=image->background_color;
3251 break;
3252 }
3253 }
cristyc3ec0d42010-04-07 01:18:08 +00003254 virtual_index=0;
cristybb503372010-05-27 20:51:26 +00003255 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003256 {
cristybb503372010-05-27 20:51:26 +00003257 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003258 {
3259 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003260 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003261 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3262 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003263 {
3264 MagickModulo
3265 x_modulo,
3266 y_modulo;
3267
3268 /*
3269 Transfer a single pixel.
3270 */
3271 length=(MagickSizeType) 1;
3272 switch (virtual_pixel_method)
3273 {
3274 case BackgroundVirtualPixelMethod:
3275 case ConstantVirtualPixelMethod:
3276 case BlackVirtualPixelMethod:
3277 case GrayVirtualPixelMethod:
3278 case TransparentVirtualPixelMethod:
3279 case MaskVirtualPixelMethod:
3280 case WhiteVirtualPixelMethod:
3281 {
3282 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003283 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003284 break;
3285 }
3286 case EdgeVirtualPixelMethod:
3287 default:
3288 {
3289 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003290 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003291 1UL,1UL,virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003292 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3293 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003294 break;
3295 }
3296 case RandomVirtualPixelMethod:
3297 {
3298 if (cache_info->random_info == (RandomInfo *) NULL)
3299 cache_info->random_info=AcquireRandomInfo();
3300 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003301 RandomX(cache_info->random_info,cache_info->columns),
3302 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003303 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003304 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3305 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003306 break;
3307 }
3308 case DitherVirtualPixelMethod:
3309 {
3310 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003311 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003312 1UL,1UL,virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003313 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3314 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003315 break;
3316 }
3317 case TileVirtualPixelMethod:
3318 {
3319 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3320 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3321 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3322 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3323 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 MirrorVirtualPixelMethod:
3329 {
3330 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3331 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003332 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003333 x_modulo.remainder-1L;
3334 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3335 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003336 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003337 y_modulo.remainder-1L;
3338 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3339 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3340 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003341 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3342 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003343 break;
3344 }
3345 case CheckerTileVirtualPixelMethod:
3346 {
3347 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3348 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3349 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3350 {
3351 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003352 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003353 break;
3354 }
3355 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3356 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3357 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003358 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3359 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003360 break;
3361 }
3362 case HorizontalTileVirtualPixelMethod:
3363 {
cristybb503372010-05-27 20:51:26 +00003364 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003365 {
3366 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003367 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003368 break;
3369 }
3370 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3371 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3372 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3373 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3374 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003375 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3376 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003377 break;
3378 }
3379 case VerticalTileVirtualPixelMethod:
3380 {
cristybb503372010-05-27 20:51:26 +00003381 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
cristy3ed852e2009-09-05 21:47:34 +00003382 {
3383 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003384 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003385 break;
3386 }
3387 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3388 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3389 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3390 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3391 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003392 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3393 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003394 break;
3395 }
3396 case HorizontalTileEdgeVirtualPixelMethod:
3397 {
3398 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3399 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003400 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003401 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003402 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3403 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003404 break;
3405 }
3406 case VerticalTileEdgeVirtualPixelMethod:
3407 {
3408 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3409 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003410 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003411 virtual_nexus[0],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 }
3417 if (p == (const PixelPacket *) NULL)
3418 break;
3419 *q++=(*p);
cristyc3ec0d42010-04-07 01:18:08 +00003420 if ((indexes != (IndexPacket *) NULL) &&
3421 (virtual_indexes != (const IndexPacket *) NULL))
3422 *indexes++=(*virtual_indexes);
cristy3ed852e2009-09-05 21:47:34 +00003423 continue;
3424 }
3425 /*
3426 Transfer a run of pixels.
3427 */
3428 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,
cristybb503372010-05-27 20:51:26 +00003429 (size_t) length,1UL,virtual_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003430 if (p == (const PixelPacket *) NULL)
3431 break;
cristyc3ec0d42010-04-07 01:18:08 +00003432 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003433 (void) CopyMagickMemory(q,p,(size_t) length*sizeof(*p));
3434 q+=length;
cristyc3ec0d42010-04-07 01:18:08 +00003435 if ((indexes != (IndexPacket *) NULL) &&
3436 (virtual_indexes != (const IndexPacket *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003437 {
cristyc3ec0d42010-04-07 01:18:08 +00003438 (void) CopyMagickMemory(indexes,virtual_indexes,(size_t) length*
3439 sizeof(*virtual_indexes));
3440 indexes+=length;
cristy3ed852e2009-09-05 21:47:34 +00003441 }
3442 }
3443 }
3444 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3445 return(pixels);
3446}
3447
3448/*
3449%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3450% %
3451% %
3452% %
3453+ G e t V i r t u a l P i x e l C a c h e %
3454% %
3455% %
3456% %
3457%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3458%
3459% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3460% cache as defined by the geometry parameters. A pointer to the pixels
3461% is returned if the pixels are transferred, otherwise a NULL is returned.
3462%
3463% The format of the GetVirtualPixelCache() method is:
3464%
3465% const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003466% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3467% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003468% ExceptionInfo *exception)
3469%
3470% A description of each parameter follows:
3471%
3472% o image: the image.
3473%
3474% o virtual_pixel_method: the virtual pixel method.
3475%
3476% o x,y,columns,rows: These values define the perimeter of a region of
3477% pixels.
3478%
3479% o exception: return any errors or warnings in this structure.
3480%
3481*/
3482static const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003483 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3484 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003485{
3486 CacheInfo
3487 *cache_info;
3488
cristy5c9e6f22010-09-17 17:31:01 +00003489 const int
3490 id = GetOpenMPThreadId();
3491
cristy3ed852e2009-09-05 21:47:34 +00003492 cache_info=(CacheInfo *) image->cache;
cristy6ebe97c2010-07-03 01:17:28 +00003493 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003494 return(GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3495 cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00003496}
3497
3498/*
3499%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3500% %
3501% %
3502% %
3503% G e t V i r t u a l P i x e l Q u e u e %
3504% %
3505% %
3506% %
3507%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3508%
3509% GetVirtualPixelQueue() returns the virtual pixels associated with the
3510% last call to QueueAuthenticPixels() or GetVirtualPixels().
3511%
3512% The format of the GetVirtualPixelQueue() method is:
3513%
3514% const PixelPacket *GetVirtualPixelQueue(const Image image)
3515%
3516% A description of each parameter follows:
3517%
3518% o image: the image.
3519%
3520*/
3521MagickExport const PixelPacket *GetVirtualPixelQueue(const Image *image)
3522{
3523 CacheInfo
3524 *cache_info;
3525
3526 assert(image != (const Image *) NULL);
3527 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003528 assert(image->cache != (Cache) NULL);
3529 cache_info=(CacheInfo *) image->cache;
3530 assert(cache_info->signature == MagickSignature);
3531 if (cache_info->methods.get_virtual_pixels_handler ==
3532 (GetVirtualPixelsHandler) NULL)
3533 return((PixelPacket *) NULL);
3534 return(cache_info->methods.get_virtual_pixels_handler(image));
3535}
3536
3537/*
3538%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3539% %
3540% %
3541% %
3542% G e t V i r t u a l P i x e l s %
3543% %
3544% %
3545% %
3546%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3547%
3548% GetVirtualPixels() returns an immutable pixel region. If the
3549% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003550% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003551% copy of the pixels or it may point to the original pixels in memory.
3552% Performance is maximized if the selected region is part of one row, or one
3553% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003554% (without a copy) if the image is in memory, or in a memory-mapped file. The
3555% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003556%
3557% Pixels accessed via the returned pointer represent a simple array of type
3558% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
3559% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to access
3560% the black color component or to obtain the colormap indexes (of type
3561% IndexPacket) corresponding to the region.
3562%
3563% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3564%
3565% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3566% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3567% GetCacheViewAuthenticPixels() instead.
3568%
3569% The format of the GetVirtualPixels() method is:
3570%
cristybb503372010-05-27 20:51:26 +00003571% const PixelPacket *GetVirtualPixels(const Image *image,const ssize_t x,
3572% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003573% ExceptionInfo *exception)
3574%
3575% A description of each parameter follows:
3576%
3577% o image: the image.
3578%
3579% o x,y,columns,rows: These values define the perimeter of a region of
3580% pixels.
3581%
3582% o exception: return any errors or warnings in this structure.
3583%
3584*/
3585MagickExport const PixelPacket *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003586 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3587 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003588{
3589 CacheInfo
3590 *cache_info;
3591
3592 const PixelPacket
3593 *pixels;
3594
3595 assert(image != (const Image *) NULL);
3596 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003597 assert(image->cache != (Cache) NULL);
3598 cache_info=(CacheInfo *) image->cache;
3599 assert(cache_info->signature == MagickSignature);
3600 if (cache_info->methods.get_virtual_pixel_handler ==
3601 (GetVirtualPixelHandler) NULL)
3602 return((const PixelPacket *) NULL);
3603 pixels=cache_info->methods.get_virtual_pixel_handler(image,
3604 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception);
3605 return(pixels);
3606}
3607
3608/*
3609%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3610% %
3611% %
3612% %
3613+ 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 %
3614% %
3615% %
3616% %
3617%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3618%
3619% GetVirtualPixelsCache() returns the pixels associated with the last call
3620% to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3621%
3622% The format of the GetVirtualPixelsCache() method is:
3623%
3624% PixelPacket *GetVirtualPixelsCache(const Image *image)
3625%
3626% A description of each parameter follows:
3627%
3628% o image: the image.
3629%
3630*/
3631static const PixelPacket *GetVirtualPixelsCache(const Image *image)
3632{
3633 CacheInfo
3634 *cache_info;
3635
cristy5c9e6f22010-09-17 17:31:01 +00003636 const int
3637 id = GetOpenMPThreadId();
3638
cristy3ed852e2009-09-05 21:47:34 +00003639 cache_info=(CacheInfo *) image->cache;
cristy6ebe97c2010-07-03 01:17:28 +00003640 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003641 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003642}
3643
3644/*
3645%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3646% %
3647% %
3648% %
3649+ G e t V i r t u a l P i x e l s N e x u s %
3650% %
3651% %
3652% %
3653%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3654%
3655% GetVirtualPixelsNexus() returns the pixels associated with the specified
3656% cache nexus.
3657%
3658% The format of the GetVirtualPixelsNexus() method is:
3659%
3660% const IndexPacket *GetVirtualPixelsNexus(const Cache cache,
3661% NexusInfo *nexus_info)
3662%
3663% A description of each parameter follows:
3664%
3665% o cache: the pixel cache.
3666%
3667% o nexus_info: the cache nexus to return the colormap pixels.
3668%
3669*/
3670MagickExport const PixelPacket *GetVirtualPixelsNexus(const Cache cache,
3671 NexusInfo *nexus_info)
3672{
3673 CacheInfo
3674 *cache_info;
3675
3676 if (cache == (Cache) NULL)
3677 return((PixelPacket *) NULL);
3678 cache_info=(CacheInfo *) cache;
3679 assert(cache_info->signature == MagickSignature);
3680 if (cache_info->storage_class == UndefinedClass)
3681 return((PixelPacket *) NULL);
3682 return((const PixelPacket *) nexus_info->pixels);
3683}
3684
3685/*
3686%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3687% %
3688% %
3689% %
3690+ M a s k P i x e l C a c h e N e x u s %
3691% %
3692% %
3693% %
3694%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3695%
3696% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3697% The method returns MagickTrue if the pixel region is masked, otherwise
3698% MagickFalse.
3699%
3700% The format of the MaskPixelCacheNexus() method is:
3701%
3702% MagickBooleanType MaskPixelCacheNexus(Image *image,
3703% NexusInfo *nexus_info,ExceptionInfo *exception)
3704%
3705% A description of each parameter follows:
3706%
3707% o image: the image.
3708%
3709% o nexus_info: the cache nexus to clip.
3710%
3711% o exception: return any errors or warnings in this structure.
3712%
3713*/
3714
3715static inline void MagickPixelCompositeMask(const MagickPixelPacket *p,
3716 const MagickRealType alpha,const MagickPixelPacket *q,
3717 const MagickRealType beta,MagickPixelPacket *composite)
3718{
3719 MagickRealType
3720 gamma;
3721
3722 if (alpha == TransparentOpacity)
3723 {
3724 *composite=(*q);
3725 return;
3726 }
3727 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3728 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3729 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3730 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3731 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3732 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3733 composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
3734}
3735
3736static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3737 ExceptionInfo *exception)
3738{
3739 CacheInfo
3740 *cache_info;
3741
3742 MagickPixelPacket
3743 alpha,
3744 beta;
3745
3746 MagickSizeType
3747 number_pixels;
3748
3749 NexusInfo
3750 **clip_nexus,
3751 **image_nexus;
3752
3753 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003754 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003755
3756 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003757 *restrict nexus_indexes,
3758 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003759
cristy3ed852e2009-09-05 21:47:34 +00003760 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003761 *restrict p,
3762 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003763
cristye076a6e2010-08-15 19:59:43 +00003764 register ssize_t
3765 i;
3766
cristy3ed852e2009-09-05 21:47:34 +00003767 /*
3768 Apply clip mask.
3769 */
3770 if (image->debug != MagickFalse)
3771 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3772 if (image->mask == (Image *) NULL)
3773 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +00003774 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00003775 if (cache_info == (Cache) NULL)
3776 return(MagickFalse);
3777 image_nexus=AcquirePixelCacheNexus(1);
3778 clip_nexus=AcquirePixelCacheNexus(1);
3779 if ((image_nexus == (NexusInfo **) NULL) ||
3780 (clip_nexus == (NexusInfo **) NULL))
3781 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy09449f72010-01-23 03:08:36 +00003782 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,
3783 nexus_info->region.y,nexus_info->region.width,nexus_info->region.height,
3784 image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003785 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
3786 q=nexus_info->pixels;
3787 nexus_indexes=nexus_info->indexes;
3788 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3789 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3790 nexus_info->region.height,clip_nexus[0],&image->exception);
3791 GetMagickPixelPacket(image,&alpha);
3792 GetMagickPixelPacket(image,&beta);
3793 number_pixels=(MagickSizeType) nexus_info->region.width*
3794 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +00003795 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +00003796 {
3797 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
3798 break;
3799 SetMagickPixelPacket(image,p,indexes+i,&alpha);
3800 SetMagickPixelPacket(image,q,nexus_indexes+i,&beta);
3801 MagickPixelCompositeMask(&beta,(MagickRealType) PixelIntensityToQuantum(r),
3802 &alpha,alpha.opacity,&beta);
cristyce70c172010-01-07 17:15:30 +00003803 q->red=ClampToQuantum(beta.red);
3804 q->green=ClampToQuantum(beta.green);
3805 q->blue=ClampToQuantum(beta.blue);
3806 q->opacity=ClampToQuantum(beta.opacity);
cristy3ed852e2009-09-05 21:47:34 +00003807 if (cache_info->active_index_channel != MagickFalse)
3808 nexus_indexes[i]=indexes[i];
3809 p++;
3810 q++;
3811 r++;
3812 }
3813 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3814 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +00003815 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003816 return(MagickFalse);
3817 return(MagickTrue);
3818}
3819
3820/*
3821%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3822% %
3823% %
3824% %
3825+ O p e n P i x e l C a c h e %
3826% %
3827% %
3828% %
3829%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3830%
3831% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3832% dimensions, allocating space for the image pixels and optionally the
3833% colormap indexes, and memory mapping the cache if it is disk based. The
3834% cache nexus array is initialized as well.
3835%
3836% The format of the OpenPixelCache() method is:
3837%
3838% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3839% ExceptionInfo *exception)
3840%
3841% A description of each parameter follows:
3842%
3843% o image: the image.
3844%
3845% o mode: ReadMode, WriteMode, or IOMode.
3846%
3847% o exception: return any errors or warnings in this structure.
3848%
3849*/
3850
cristyd43a46b2010-01-21 02:13:41 +00003851static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003852{
3853 cache_info->mapped=MagickFalse;
3854 cache_info->pixels=(PixelPacket *) AcquireMagickMemory((size_t)
3855 cache_info->length);
3856 if (cache_info->pixels == (PixelPacket *) NULL)
3857 {
3858 cache_info->mapped=MagickTrue;
3859 cache_info->pixels=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
3860 cache_info->length);
3861 }
3862}
3863
3864static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3865{
3866 CacheInfo
3867 *cache_info;
3868
3869 MagickOffsetType
3870 count,
3871 extent,
3872 offset;
3873
3874 cache_info=(CacheInfo *) image->cache;
3875 if (image->debug != MagickFalse)
3876 {
3877 char
3878 format[MaxTextExtent],
3879 message[MaxTextExtent];
3880
cristyb9080c92009-12-01 20:13:26 +00003881 (void) FormatMagickSize(length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00003882 (void) FormatMagickString(message,MaxTextExtent,
cristy2ce15c92010-03-12 14:03:41 +00003883 "extend %s (%s[%d], disk, %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003884 cache_info->cache_filename,cache_info->file,format);
3885 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3886 }
3887 if (length != (MagickSizeType) ((MagickOffsetType) length))
3888 return(MagickFalse);
3889 extent=(MagickOffsetType) MagickSeek(cache_info->file,0,SEEK_END);
3890 if (extent < 0)
3891 return(MagickFalse);
3892 if ((MagickSizeType) extent >= length)
3893 return(MagickTrue);
3894 offset=(MagickOffsetType) length-1;
3895 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3896 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3897}
3898
3899static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3900 ExceptionInfo *exception)
3901{
3902 char
3903 format[MaxTextExtent],
3904 message[MaxTextExtent];
3905
3906 CacheInfo
3907 *cache_info,
3908 source_info;
3909
3910 MagickSizeType
3911 length,
3912 number_pixels;
3913
3914 MagickStatusType
3915 status;
3916
3917 size_t
cristye076a6e2010-08-15 19:59:43 +00003918 columns,
cristy3ed852e2009-09-05 21:47:34 +00003919 packet_size;
3920
cristy3ed852e2009-09-05 21:47:34 +00003921 if (image->debug != MagickFalse)
3922 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3923 if ((image->columns == 0) || (image->rows == 0))
3924 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3925 cache_info=(CacheInfo *) image->cache;
3926 source_info=(*cache_info);
3927 source_info.file=(-1);
cristye8c25f92010-06-03 00:53:06 +00003928 (void) FormatMagickString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3929 image->filename,(double) GetImageIndexInList(image));
cristy87528ea2009-09-10 14:53:56 +00003930 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +00003931 cache_info->rows=image->rows;
3932 cache_info->columns=image->columns;
3933 cache_info->active_index_channel=((image->storage_class == PseudoClass) ||
3934 (image->colorspace == CMYKColorspace)) ? MagickTrue : MagickFalse;
cristy73724512010-04-12 14:43:14 +00003935 if (image->ping != MagickFalse)
3936 {
3937 cache_info->storage_class=image->storage_class;
3938 cache_info->colorspace=image->colorspace;
3939 cache_info->type=PingCache;
3940 cache_info->pixels=(PixelPacket *) NULL;
3941 cache_info->indexes=(IndexPacket *) NULL;
3942 cache_info->length=0;
3943 return(MagickTrue);
3944 }
cristy3ed852e2009-09-05 21:47:34 +00003945 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3946 packet_size=sizeof(PixelPacket);
3947 if (cache_info->active_index_channel != MagickFalse)
3948 packet_size+=sizeof(IndexPacket);
3949 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00003950 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00003951 if (cache_info->columns != columns)
3952 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3953 image->filename);
3954 cache_info->length=length;
3955 status=AcquireMagickResource(AreaResource,cache_info->length);
3956 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
3957 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3958 {
3959 status=AcquireMagickResource(MemoryResource,cache_info->length);
3960 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3961 (cache_info->type == MemoryCache))
3962 {
cristyd43a46b2010-01-21 02:13:41 +00003963 AllocatePixelCachePixels(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00003964 if (cache_info->pixels == (PixelPacket *) NULL)
3965 cache_info->pixels=source_info.pixels;
3966 else
3967 {
3968 /*
3969 Create memory pixel cache.
3970 */
3971 if (image->debug != MagickFalse)
3972 {
cristy97e7a572009-12-05 15:07:53 +00003973 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00003974 format);
cristy3ed852e2009-09-05 21:47:34 +00003975 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00003976 "open %s (%s memory, %.20gx%.20g %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003977 cache_info->mapped != MagickFalse ? "anonymous" : "heap",
cristye8c25f92010-06-03 00:53:06 +00003978 (double) cache_info->columns,(double) cache_info->rows,
3979 format);
cristy3ed852e2009-09-05 21:47:34 +00003980 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3981 message);
3982 }
3983 cache_info->storage_class=image->storage_class;
3984 cache_info->colorspace=image->colorspace;
3985 cache_info->type=MemoryCache;
3986 cache_info->indexes=(IndexPacket *) NULL;
3987 if (cache_info->active_index_channel != MagickFalse)
3988 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
3989 number_pixels);
3990 if (source_info.storage_class != UndefinedClass)
3991 {
3992 status|=ClonePixelCachePixels(cache_info,&source_info,
3993 exception);
3994 RelinquishPixelCachePixels(&source_info);
3995 }
3996 return(MagickTrue);
3997 }
3998 }
3999 RelinquishMagickResource(MemoryResource,cache_info->length);
4000 }
4001 /*
4002 Create pixel cache on disk.
4003 */
4004 status=AcquireMagickResource(DiskResource,cache_info->length);
4005 if (status == MagickFalse)
4006 {
4007 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4008 "CacheResourcesExhausted","`%s'",image->filename);
4009 return(MagickFalse);
4010 }
4011 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4012 {
4013 RelinquishMagickResource(DiskResource,cache_info->length);
4014 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4015 image->filename);
4016 return(MagickFalse);
4017 }
4018 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4019 cache_info->length);
4020 if (status == MagickFalse)
4021 {
4022 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4023 image->filename);
4024 return(MagickFalse);
4025 }
4026 cache_info->storage_class=image->storage_class;
4027 cache_info->colorspace=image->colorspace;
4028 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4029 status=AcquireMagickResource(AreaResource,cache_info->length);
4030 if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4031 cache_info->type=DiskCache;
4032 else
4033 {
4034 status=AcquireMagickResource(MapResource,cache_info->length);
4035 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4036 (cache_info->type != MemoryCache))
4037 cache_info->type=DiskCache;
4038 else
4039 {
4040 cache_info->pixels=(PixelPacket *) MapBlob(cache_info->file,mode,
4041 cache_info->offset,(size_t) cache_info->length);
4042 if (cache_info->pixels == (PixelPacket *) NULL)
4043 {
4044 cache_info->pixels=source_info.pixels;
4045 cache_info->type=DiskCache;
4046 }
4047 else
4048 {
4049 /*
4050 Create file-backed memory-mapped pixel cache.
4051 */
4052 (void) ClosePixelCacheOnDisk(cache_info);
4053 cache_info->type=MapCache;
4054 cache_info->mapped=MagickTrue;
4055 cache_info->indexes=(IndexPacket *) NULL;
4056 if (cache_info->active_index_channel != MagickFalse)
4057 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4058 number_pixels);
4059 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4060 {
4061 status=ClonePixelCachePixels(cache_info,&source_info,
4062 exception);
4063 RelinquishPixelCachePixels(&source_info);
4064 }
4065 if (image->debug != MagickFalse)
4066 {
cristy97e7a572009-12-05 15:07:53 +00004067 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004068 format);
cristy3ed852e2009-09-05 21:47:34 +00004069 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004070 "open %s (%s[%d], memory-mapped, %.20gx%.20g %sB)",
cristy3ed852e2009-09-05 21:47:34 +00004071 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004072 cache_info->file,(double) cache_info->columns,(double)
4073 cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004074 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4075 message);
4076 }
4077 return(MagickTrue);
4078 }
4079 }
4080 RelinquishMagickResource(MapResource,cache_info->length);
4081 }
4082 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4083 {
4084 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4085 RelinquishPixelCachePixels(&source_info);
4086 }
4087 if (image->debug != MagickFalse)
4088 {
cristyb9080c92009-12-01 20:13:26 +00004089 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00004090 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004091 "open %s (%s[%d], disk, %.20gx%.20g %sB)",cache_info->filename,
4092 cache_info->cache_filename,cache_info->file,(double)
4093 cache_info->columns,(double) cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004094 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4095 }
4096 return(MagickTrue);
4097}
4098
4099/*
4100%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4101% %
4102% %
4103% %
4104+ P e r s i s t P i x e l C a c h e %
4105% %
4106% %
4107% %
4108%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4109%
4110% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4111% persistent pixel cache is one that resides on disk and is not destroyed
4112% when the program exits.
4113%
4114% The format of the PersistPixelCache() method is:
4115%
4116% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4117% const MagickBooleanType attach,MagickOffsetType *offset,
4118% ExceptionInfo *exception)
4119%
4120% A description of each parameter follows:
4121%
4122% o image: the image.
4123%
4124% o filename: the persistent pixel cache filename.
4125%
cristy01b7eb02009-09-10 23:10:14 +00004126% o attach: A value other than zero initializes the persistent pixel
4127% cache.
4128%
cristy3ed852e2009-09-05 21:47:34 +00004129% o initialize: A value other than zero initializes the persistent pixel
4130% cache.
4131%
4132% o offset: the offset in the persistent cache to store pixels.
4133%
4134% o exception: return any errors or warnings in this structure.
4135%
4136*/
4137MagickExport MagickBooleanType PersistPixelCache(Image *image,
4138 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4139 ExceptionInfo *exception)
4140{
4141 CacheInfo
4142 *cache_info,
4143 *clone_info;
4144
4145 Image
4146 clone_image;
4147
cristy3ed852e2009-09-05 21:47:34 +00004148 MagickBooleanType
4149 status;
4150
cristye076a6e2010-08-15 19:59:43 +00004151 ssize_t
4152 page_size;
4153
cristy3ed852e2009-09-05 21:47:34 +00004154 assert(image != (Image *) NULL);
4155 assert(image->signature == MagickSignature);
4156 if (image->debug != MagickFalse)
4157 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4158 assert(image->cache != (void *) NULL);
4159 assert(filename != (const char *) NULL);
4160 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004161 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004162 cache_info=(CacheInfo *) image->cache;
4163 assert(cache_info->signature == MagickSignature);
4164 if (attach != MagickFalse)
4165 {
4166 /*
cristy01b7eb02009-09-10 23:10:14 +00004167 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004168 */
4169 if (image->debug != MagickFalse)
4170 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4171 "attach persistent cache");
4172 (void) CopyMagickString(cache_info->cache_filename,filename,
4173 MaxTextExtent);
4174 cache_info->type=DiskCache;
4175 cache_info->offset=(*offset);
4176 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4177 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004178 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004179 return(MagickTrue);
4180 }
cristy01b7eb02009-09-10 23:10:14 +00004181 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4182 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004183 {
cristyf84a1932010-01-03 18:00:18 +00004184 LockSemaphoreInfo(cache_info->semaphore);
cristy09449f72010-01-23 03:08:36 +00004185 if ((cache_info->mode != ReadMode) &&
4186 (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004187 (cache_info->reference_count == 1))
4188 {
4189 int
4190 status;
4191
4192 /*
cristy01b7eb02009-09-10 23:10:14 +00004193 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004194 */
4195 status=rename(cache_info->cache_filename,filename);
4196 if (status == 0)
4197 {
4198 (void) CopyMagickString(cache_info->cache_filename,filename,
4199 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004200 *offset+=cache_info->length+page_size-(cache_info->length %
4201 page_size);
cristyf84a1932010-01-03 18:00:18 +00004202 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004203 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004204 if (image->debug != MagickFalse)
4205 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4206 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004207 return(MagickTrue);
4208 }
4209 }
cristyf84a1932010-01-03 18:00:18 +00004210 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004211 }
4212 /*
cristy01b7eb02009-09-10 23:10:14 +00004213 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004214 */
4215 clone_image=(*image);
4216 clone_info=(CacheInfo *) clone_image.cache;
4217 image->cache=ClonePixelCache(cache_info);
4218 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4219 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4220 cache_info->type=DiskCache;
4221 cache_info->offset=(*offset);
4222 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004223 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004224 if (status != MagickFalse)
cristyabd6e372010-09-15 19:11:26 +00004225 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
cristy688f07b2009-09-27 15:19:13 +00004226 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004227 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4228 return(status);
4229}
4230
4231/*
4232%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4233% %
4234% %
4235% %
4236+ Q u e u e A u t h e n t i c N e x u s %
4237% %
4238% %
4239% %
4240%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4241%
4242% QueueAuthenticNexus() allocates an region to store image pixels as defined
4243% by the region rectangle and returns a pointer to the region. This region is
4244% subsequently transferred from the pixel cache with
4245% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4246% pixels are transferred, otherwise a NULL is returned.
4247%
4248% The format of the QueueAuthenticNexus() method is:
4249%
cristy5f959472010-05-27 22:19:46 +00004250% PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
4251% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004252% NexusInfo *nexus_info,ExceptionInfo *exception)
4253%
4254% A description of each parameter follows:
4255%
4256% o image: the image.
4257%
4258% o x,y,columns,rows: These values define the perimeter of a region of
4259% pixels.
4260%
4261% o nexus_info: the cache nexus to set.
4262%
4263% o exception: return any errors or warnings in this structure.
4264%
4265*/
cristybb503372010-05-27 20:51:26 +00004266MagickExport PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy30097232010-07-01 02:16:30 +00004267 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
4268 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004269{
4270 CacheInfo
4271 *cache_info;
4272
4273 MagickOffsetType
4274 offset;
4275
4276 MagickSizeType
4277 number_pixels;
4278
4279 RectangleInfo
4280 region;
4281
4282 /*
4283 Validate pixel cache geometry.
4284 */
cristy77ff0282010-09-13 00:51:10 +00004285 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
4286 if (cache_info == (Cache) NULL)
4287 return((PixelPacket *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004288 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4289 {
4290 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4291 "NoPixelsDefinedInCache","`%s'",image->filename);
4292 return((PixelPacket *) NULL);
4293 }
cristybb503372010-05-27 20:51:26 +00004294 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4295 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004296 {
4297 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4298 "PixelsAreNotAuthentic","`%s'",image->filename);
4299 return((PixelPacket *) NULL);
4300 }
4301 offset=(MagickOffsetType) y*cache_info->columns+x;
4302 if (offset < 0)
4303 return((PixelPacket *) NULL);
4304 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4305 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4306 if ((MagickSizeType) offset >= number_pixels)
4307 return((PixelPacket *) NULL);
4308 /*
4309 Return pixel cache.
4310 */
4311 region.x=x;
4312 region.y=y;
4313 region.width=columns;
4314 region.height=rows;
4315 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4316}
4317
4318/*
4319%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4320% %
4321% %
4322% %
4323+ 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 %
4324% %
4325% %
4326% %
4327%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4328%
4329% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4330% defined by the region rectangle and returns a pointer to the region. This
4331% region is subsequently transferred from the pixel cache with
4332% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4333% pixels are transferred, otherwise a NULL is returned.
4334%
4335% The format of the QueueAuthenticPixelsCache() method is:
4336%
cristybb503372010-05-27 20:51:26 +00004337% PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4338% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004339% ExceptionInfo *exception)
4340%
4341% A description of each parameter follows:
4342%
4343% o image: the image.
4344%
4345% o x,y,columns,rows: These values define the perimeter of a region of
4346% pixels.
4347%
4348% o exception: return any errors or warnings in this structure.
4349%
4350*/
cristybb503372010-05-27 20:51:26 +00004351static PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4352 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004353 ExceptionInfo *exception)
4354{
4355 CacheInfo
4356 *cache_info;
4357
cristy5c9e6f22010-09-17 17:31:01 +00004358 const int
4359 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004360
cristy77ff0282010-09-13 00:51:10 +00004361 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00004362 if (cache_info == (Cache) NULL)
4363 return((PixelPacket *) NULL);
cristy6ebe97c2010-07-03 01:17:28 +00004364 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00004365 return(QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4366 exception));
cristy3ed852e2009-09-05 21:47:34 +00004367}
4368
4369/*
4370%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4371% %
4372% %
4373% %
4374% Q u e u e A u t h e n t i c P i x e l s %
4375% %
4376% %
4377% %
4378%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4379%
4380% QueueAuthenticPixels() queues a mutable pixel region. If the region is
4381% successfully intialized a pointer to a PixelPacket array representing the
4382% region is returned, otherwise NULL is returned. The returned pointer may
4383% point to a temporary working buffer for the pixels or it may point to the
4384% final location of the pixels in memory.
4385%
4386% Write-only access means that any existing pixel values corresponding to
4387% the region are ignored. This is useful if the initial image is being
4388% created from scratch, or if the existing pixel values are to be
4389% completely replaced without need to refer to their pre-existing values.
4390% The application is free to read and write the pixel buffer returned by
4391% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4392% initialize the pixel array values. Initializing pixel array values is the
4393% application's responsibility.
4394%
4395% Performance is maximized if the selected region is part of one row, or
4396% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004397% pixels in-place (without a copy) if the image is in memory, or in a
4398% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004399% by the user.
4400%
4401% Pixels accessed via the returned pointer represent a simple array of type
4402% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
4403% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
4404% the black color component or the colormap indexes (of type IndexPacket)
4405% corresponding to the region. Once the PixelPacket (and/or IndexPacket)
4406% array has been updated, the changes must be saved back to the underlying
4407% image using SyncAuthenticPixels() or they may be lost.
4408%
4409% The format of the QueueAuthenticPixels() method is:
4410%
cristy5f959472010-05-27 22:19:46 +00004411% PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4412% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004413% ExceptionInfo *exception)
4414%
4415% A description of each parameter follows:
4416%
4417% o image: the image.
4418%
4419% o x,y,columns,rows: These values define the perimeter of a region of
4420% pixels.
4421%
4422% o exception: return any errors or warnings in this structure.
4423%
4424*/
cristybb503372010-05-27 20:51:26 +00004425MagickExport PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4426 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004427 ExceptionInfo *exception)
4428{
4429 CacheInfo
4430 *cache_info;
4431
4432 PixelPacket
4433 *pixels;
4434
4435 assert(image != (Image *) NULL);
4436 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004437 assert(image->cache != (Cache) NULL);
4438 cache_info=(CacheInfo *) image->cache;
4439 assert(cache_info->signature == MagickSignature);
4440 if (cache_info->methods.queue_authentic_pixels_handler ==
4441 (QueueAuthenticPixelsHandler) NULL)
4442 return((PixelPacket *) NULL);
4443 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4444 rows,exception);
4445 return(pixels);
4446}
4447
4448/*
4449%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4450% %
4451% %
4452% %
4453+ R e a d P i x e l C a c h e I n d e x e s %
4454% %
4455% %
4456% %
4457%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4458%
4459% ReadPixelCacheIndexes() reads colormap indexes from the specified region of
4460% the pixel cache.
4461%
4462% The format of the ReadPixelCacheIndexes() method is:
4463%
4464% MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4465% NexusInfo *nexus_info,ExceptionInfo *exception)
4466%
4467% A description of each parameter follows:
4468%
4469% o cache_info: the pixel cache.
4470%
4471% o nexus_info: the cache nexus to read the colormap indexes.
4472%
4473% o exception: return any errors or warnings in this structure.
4474%
4475*/
4476static MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4477 NexusInfo *nexus_info,ExceptionInfo *exception)
4478{
4479 MagickOffsetType
4480 count,
4481 offset;
4482
4483 MagickSizeType
4484 length,
4485 number_pixels;
4486
4487 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004488 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004489
cristybb503372010-05-27 20:51:26 +00004490 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004491 y;
4492
cristybb503372010-05-27 20:51:26 +00004493 size_t
cristy3ed852e2009-09-05 21:47:34 +00004494 rows;
4495
cristy3ed852e2009-09-05 21:47:34 +00004496 if (cache_info->active_index_channel == MagickFalse)
4497 return(MagickFalse);
4498 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4499 return(MagickTrue);
4500 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4501 nexus_info->region.x;
4502 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
4503 rows=nexus_info->region.height;
4504 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004505 q=nexus_info->indexes;
4506 switch (cache_info->type)
4507 {
4508 case MemoryCache:
4509 case MapCache:
4510 {
4511 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004512 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004513
4514 /*
4515 Read indexes from memory.
4516 */
cristydd341db2010-03-04 19:06:38 +00004517 if ((cache_info->columns == nexus_info->region.width) &&
4518 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4519 {
4520 length=number_pixels;
4521 rows=1UL;
4522 }
cristy3ed852e2009-09-05 21:47:34 +00004523 p=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00004524 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004525 {
4526 (void) CopyMagickMemory(q,p,(size_t) length);
4527 p+=cache_info->columns;
4528 q+=nexus_info->region.width;
4529 }
4530 break;
4531 }
4532 case DiskCache:
4533 {
4534 /*
4535 Read indexes from disk.
4536 */
4537 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4538 {
4539 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4540 cache_info->cache_filename);
4541 return(MagickFalse);
4542 }
cristydd341db2010-03-04 19:06:38 +00004543 if ((cache_info->columns == nexus_info->region.width) &&
4544 (number_pixels < MagickMaxBufferExtent))
4545 {
4546 length=number_pixels;
4547 rows=1UL;
4548 }
cristy3ed852e2009-09-05 21:47:34 +00004549 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004550 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004551 {
4552 count=ReadPixelCacheRegion(cache_info,cache_info->offset+number_pixels*
4553 sizeof(PixelPacket)+offset*sizeof(*q),length,(unsigned char *) q);
4554 if ((MagickSizeType) count < length)
4555 break;
4556 offset+=cache_info->columns;
4557 q+=nexus_info->region.width;
4558 }
cristybb503372010-05-27 20:51:26 +00004559 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004560 {
4561 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4562 cache_info->cache_filename);
4563 return(MagickFalse);
4564 }
4565 break;
4566 }
4567 default:
4568 break;
4569 }
4570 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004571 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004572 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004573 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004574 nexus_info->region.width,(double) nexus_info->region.height,(double)
4575 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004576 return(MagickTrue);
4577}
4578
4579/*
4580%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4581% %
4582% %
4583% %
4584+ R e a d P i x e l C a c h e P i x e l s %
4585% %
4586% %
4587% %
4588%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4589%
4590% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4591% cache.
4592%
4593% The format of the ReadPixelCachePixels() method is:
4594%
4595% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4596% NexusInfo *nexus_info,ExceptionInfo *exception)
4597%
4598% A description of each parameter follows:
4599%
4600% o cache_info: the pixel cache.
4601%
4602% o nexus_info: the cache nexus to read the pixels.
4603%
4604% o exception: return any errors or warnings in this structure.
4605%
4606*/
4607static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4608 NexusInfo *nexus_info,ExceptionInfo *exception)
4609{
4610 MagickOffsetType
4611 count,
4612 offset;
4613
4614 MagickSizeType
4615 length,
4616 number_pixels;
4617
cristy3ed852e2009-09-05 21:47:34 +00004618 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004619 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004620
cristye076a6e2010-08-15 19:59:43 +00004621 register ssize_t
4622 y;
4623
cristybb503372010-05-27 20:51:26 +00004624 size_t
cristy3ed852e2009-09-05 21:47:34 +00004625 rows;
4626
cristy3ed852e2009-09-05 21:47:34 +00004627 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4628 return(MagickTrue);
4629 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4630 nexus_info->region.x;
4631 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
4632 rows=nexus_info->region.height;
4633 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004634 q=nexus_info->pixels;
4635 switch (cache_info->type)
4636 {
4637 case MemoryCache:
4638 case MapCache:
4639 {
4640 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004641 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004642
4643 /*
4644 Read pixels from memory.
4645 */
cristydd341db2010-03-04 19:06:38 +00004646 if ((cache_info->columns == nexus_info->region.width) &&
4647 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4648 {
4649 length=number_pixels;
4650 rows=1UL;
4651 }
cristy3ed852e2009-09-05 21:47:34 +00004652 p=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00004653 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004654 {
4655 (void) CopyMagickMemory(q,p,(size_t) length);
4656 p+=cache_info->columns;
4657 q+=nexus_info->region.width;
4658 }
4659 break;
4660 }
4661 case DiskCache:
4662 {
4663 /*
4664 Read pixels from disk.
4665 */
4666 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4667 {
4668 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4669 cache_info->cache_filename);
4670 return(MagickFalse);
4671 }
cristydd341db2010-03-04 19:06:38 +00004672 if ((cache_info->columns == nexus_info->region.width) &&
4673 (number_pixels < MagickMaxBufferExtent))
4674 {
4675 length=number_pixels;
4676 rows=1UL;
4677 }
cristybb503372010-05-27 20:51:26 +00004678 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004679 {
4680 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4681 sizeof(*q),length,(unsigned char *) q);
4682 if ((MagickSizeType) count < length)
4683 break;
4684 offset+=cache_info->columns;
4685 q+=nexus_info->region.width;
4686 }
cristybb503372010-05-27 20:51:26 +00004687 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004688 {
4689 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4690 cache_info->cache_filename);
4691 return(MagickFalse);
4692 }
4693 break;
4694 }
4695 default:
4696 break;
4697 }
4698 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004699 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004700 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004701 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004702 nexus_info->region.width,(double) nexus_info->region.height,(double)
4703 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004704 return(MagickTrue);
4705}
4706
4707/*
4708%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4709% %
4710% %
4711% %
4712+ R e f e r e n c e P i x e l C a c h e %
4713% %
4714% %
4715% %
4716%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4717%
4718% ReferencePixelCache() increments the reference count associated with the
4719% pixel cache returning a pointer to the cache.
4720%
4721% The format of the ReferencePixelCache method is:
4722%
4723% Cache ReferencePixelCache(Cache cache_info)
4724%
4725% A description of each parameter follows:
4726%
4727% o cache_info: the pixel cache.
4728%
4729*/
4730MagickExport Cache ReferencePixelCache(Cache cache)
4731{
4732 CacheInfo
4733 *cache_info;
4734
4735 assert(cache != (Cache *) NULL);
4736 cache_info=(CacheInfo *) cache;
4737 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004738 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004739 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004740 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004741 return(cache_info);
4742}
4743
4744/*
4745%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4746% %
4747% %
4748% %
4749+ S e t P i x e l C a c h e M e t h o d s %
4750% %
4751% %
4752% %
4753%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4754%
4755% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4756%
4757% The format of the SetPixelCacheMethods() method is:
4758%
4759% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4760%
4761% A description of each parameter follows:
4762%
4763% o cache: the pixel cache.
4764%
4765% o cache_methods: Specifies a pointer to a CacheMethods structure.
4766%
4767*/
4768MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4769{
4770 CacheInfo
4771 *cache_info;
4772
4773 GetOneAuthenticPixelFromHandler
4774 get_one_authentic_pixel_from_handler;
4775
4776 GetOneVirtualPixelFromHandler
4777 get_one_virtual_pixel_from_handler;
4778
4779 /*
4780 Set cache pixel methods.
4781 */
4782 assert(cache != (Cache) NULL);
4783 assert(cache_methods != (CacheMethods *) NULL);
4784 cache_info=(CacheInfo *) cache;
4785 assert(cache_info->signature == MagickSignature);
4786 if (cache_info->debug != MagickFalse)
4787 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4788 cache_info->filename);
4789 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4790 cache_info->methods.get_virtual_pixel_handler=
4791 cache_methods->get_virtual_pixel_handler;
4792 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4793 cache_info->methods.destroy_pixel_handler=
4794 cache_methods->destroy_pixel_handler;
4795 if (cache_methods->get_virtual_indexes_from_handler !=
4796 (GetVirtualIndexesFromHandler) NULL)
4797 cache_info->methods.get_virtual_indexes_from_handler=
4798 cache_methods->get_virtual_indexes_from_handler;
4799 if (cache_methods->get_authentic_pixels_handler !=
4800 (GetAuthenticPixelsHandler) NULL)
4801 cache_info->methods.get_authentic_pixels_handler=
4802 cache_methods->get_authentic_pixels_handler;
4803 if (cache_methods->queue_authentic_pixels_handler !=
4804 (QueueAuthenticPixelsHandler) NULL)
4805 cache_info->methods.queue_authentic_pixels_handler=
4806 cache_methods->queue_authentic_pixels_handler;
4807 if (cache_methods->sync_authentic_pixels_handler !=
4808 (SyncAuthenticPixelsHandler) NULL)
4809 cache_info->methods.sync_authentic_pixels_handler=
4810 cache_methods->sync_authentic_pixels_handler;
4811 if (cache_methods->get_authentic_pixels_from_handler !=
4812 (GetAuthenticPixelsFromHandler) NULL)
4813 cache_info->methods.get_authentic_pixels_from_handler=
4814 cache_methods->get_authentic_pixels_from_handler;
4815 if (cache_methods->get_authentic_indexes_from_handler !=
4816 (GetAuthenticIndexesFromHandler) NULL)
4817 cache_info->methods.get_authentic_indexes_from_handler=
4818 cache_methods->get_authentic_indexes_from_handler;
4819 get_one_virtual_pixel_from_handler=
4820 cache_info->methods.get_one_virtual_pixel_from_handler;
4821 if (get_one_virtual_pixel_from_handler !=
4822 (GetOneVirtualPixelFromHandler) NULL)
4823 cache_info->methods.get_one_virtual_pixel_from_handler=
4824 cache_methods->get_one_virtual_pixel_from_handler;
4825 get_one_authentic_pixel_from_handler=
4826 cache_methods->get_one_authentic_pixel_from_handler;
4827 if (get_one_authentic_pixel_from_handler !=
4828 (GetOneAuthenticPixelFromHandler) NULL)
4829 cache_info->methods.get_one_authentic_pixel_from_handler=
4830 cache_methods->get_one_authentic_pixel_from_handler;
4831}
4832
4833/*
4834%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4835% %
4836% %
4837% %
4838+ S e t P i x e l C a c h e N e x u s P i x e l s %
4839% %
4840% %
4841% %
4842%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4843%
4844% SetPixelCacheNexusPixels() defines the region of the cache for the
4845% specified cache nexus.
4846%
4847% The format of the SetPixelCacheNexusPixels() method is:
4848%
4849% PixelPacket SetPixelCacheNexusPixels(const Image *image,
4850% const RectangleInfo *region,NexusInfo *nexus_info,
4851% ExceptionInfo *exception)
4852%
4853% A description of each parameter follows:
4854%
4855% o image: the image.
4856%
4857% o region: A pointer to the RectangleInfo structure that defines the
4858% region of this particular cache nexus.
4859%
4860% o nexus_info: the cache nexus to set.
4861%
4862% o exception: return any errors or warnings in this structure.
4863%
4864*/
cristyabd6e372010-09-15 19:11:26 +00004865
4866static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4867 NexusInfo *nexus_info,ExceptionInfo *exception)
4868{
4869 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4870 return(MagickFalse);
4871 nexus_info->mapped=MagickFalse;
4872 nexus_info->cache=(PixelPacket *) AcquireMagickMemory((size_t)
4873 nexus_info->length);
4874 if (nexus_info->cache == (PixelPacket *) NULL)
4875 {
4876 nexus_info->mapped=MagickTrue;
4877 nexus_info->cache=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
4878 nexus_info->length);
4879 }
4880 if (nexus_info->cache == (PixelPacket *) NULL)
4881 {
4882 (void) ThrowMagickException(exception,GetMagickModule(),
4883 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4884 cache_info->filename);
4885 return(MagickFalse);
4886 }
4887 return(MagickTrue);
4888}
4889
cristy3ed852e2009-09-05 21:47:34 +00004890static PixelPacket *SetPixelCacheNexusPixels(const Image *image,
4891 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4892{
4893 CacheInfo
4894 *cache_info;
4895
4896 MagickBooleanType
4897 status;
4898
cristy3ed852e2009-09-05 21:47:34 +00004899 MagickSizeType
4900 length,
4901 number_pixels;
4902
cristy3ed852e2009-09-05 21:47:34 +00004903 cache_info=(CacheInfo *) image->cache;
4904 assert(cache_info->signature == MagickSignature);
4905 if (cache_info->type == UndefinedCache)
4906 return((PixelPacket *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00004907 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00004908 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
4909 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00004910 {
cristybb503372010-05-27 20:51:26 +00004911 ssize_t
cristybad067a2010-02-15 17:20:55 +00004912 x,
4913 y;
cristy3ed852e2009-09-05 21:47:34 +00004914
cristyeaedf062010-05-29 22:36:02 +00004915 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4916 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00004917 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4918 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00004919 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00004920 ((nexus_info->region.width == cache_info->columns) ||
4921 ((nexus_info->region.width % cache_info->columns) == 0)))))
4922 {
4923 MagickOffsetType
4924 offset;
4925
4926 /*
4927 Pixels are accessed directly from memory.
4928 */
4929 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4930 nexus_info->region.x;
4931 nexus_info->pixels=cache_info->pixels+offset;
4932 nexus_info->indexes=(IndexPacket *) NULL;
4933 if (cache_info->active_index_channel != MagickFalse)
4934 nexus_info->indexes=cache_info->indexes+offset;
4935 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00004936 }
4937 }
4938 /*
4939 Pixels are stored in a cache region until they are synced to the cache.
4940 */
4941 number_pixels=(MagickSizeType) nexus_info->region.width*
4942 nexus_info->region.height;
4943 length=number_pixels*sizeof(PixelPacket);
4944 if (cache_info->active_index_channel != MagickFalse)
4945 length+=number_pixels*sizeof(IndexPacket);
4946 if (nexus_info->cache == (PixelPacket *) NULL)
4947 {
4948 nexus_info->length=length;
4949 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4950 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004951 {
4952 nexus_info->length=0;
4953 return((PixelPacket *) NULL);
4954 }
cristy3ed852e2009-09-05 21:47:34 +00004955 }
4956 else
4957 if (nexus_info->length != length)
4958 {
4959 RelinquishCacheNexusPixels(nexus_info);
4960 nexus_info->length=length;
4961 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4962 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004963 {
4964 nexus_info->length=0;
4965 return((PixelPacket *) NULL);
4966 }
cristy3ed852e2009-09-05 21:47:34 +00004967 }
4968 nexus_info->pixels=nexus_info->cache;
4969 nexus_info->indexes=(IndexPacket *) NULL;
4970 if (cache_info->active_index_channel != MagickFalse)
4971 nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
4972 return(nexus_info->pixels);
4973}
4974
4975/*
4976%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4977% %
4978% %
4979% %
4980% 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 %
4981% %
4982% %
4983% %
4984%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4985%
4986% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4987% pixel cache and returns the previous setting. A virtual pixel is any pixel
4988% access that is outside the boundaries of the image cache.
4989%
4990% The format of the SetPixelCacheVirtualMethod() method is:
4991%
4992% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
4993% const VirtualPixelMethod virtual_pixel_method)
4994%
4995% A description of each parameter follows:
4996%
4997% o image: the image.
4998%
4999% o virtual_pixel_method: choose the type of virtual pixel.
5000%
5001*/
5002MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5003 const VirtualPixelMethod virtual_pixel_method)
5004{
5005 CacheInfo
5006 *cache_info;
5007
5008 VirtualPixelMethod
5009 method;
5010
5011 assert(image != (Image *) NULL);
5012 assert(image->signature == MagickSignature);
5013 if (image->debug != MagickFalse)
5014 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5015 assert(image->cache != (Cache) NULL);
5016 cache_info=(CacheInfo *) image->cache;
5017 assert(cache_info->signature == MagickSignature);
5018 method=cache_info->virtual_pixel_method;
5019 cache_info->virtual_pixel_method=virtual_pixel_method;
5020 return(method);
5021}
5022
5023/*
5024%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5025% %
5026% %
5027% %
5028+ 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 %
5029% %
5030% %
5031% %
5032%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5033%
5034% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5035% in-memory or disk cache. The method returns MagickTrue if the pixel region
5036% is synced, otherwise MagickFalse.
5037%
5038% The format of the SyncAuthenticPixelCacheNexus() method is:
5039%
5040% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5041% NexusInfo *nexus_info,ExceptionInfo *exception)
5042%
5043% A description of each parameter follows:
5044%
5045% o image: the image.
5046%
5047% o nexus_info: the cache nexus to sync.
5048%
5049% o exception: return any errors or warnings in this structure.
5050%
5051*/
5052MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5053 NexusInfo *nexus_info,ExceptionInfo *exception)
5054{
5055 CacheInfo
5056 *cache_info;
5057
5058 MagickBooleanType
5059 status;
5060
5061 /*
5062 Transfer pixels to the cache.
5063 */
5064 assert(image != (Image *) NULL);
5065 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005066 if (image->cache == (Cache) NULL)
5067 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5068 cache_info=(CacheInfo *) image->cache;
5069 if (cache_info->type == UndefinedCache)
5070 return(MagickFalse);
5071 if ((image->clip_mask != (Image *) NULL) &&
5072 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5073 return(MagickFalse);
5074 if ((image->mask != (Image *) NULL) &&
5075 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5076 return(MagickFalse);
5077 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5078 return(MagickTrue);
5079 assert(cache_info->signature == MagickSignature);
5080 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5081 if ((cache_info->active_index_channel != MagickFalse) &&
5082 (WritePixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse))
5083 return(MagickFalse);
5084 return(status);
5085}
5086
5087/*
5088%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5089% %
5090% %
5091% %
5092+ S y n c A u t h e n t i c P i x e l C a c h e %
5093% %
5094% %
5095% %
5096%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5097%
5098% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5099% or disk cache. The method returns MagickTrue if the pixel region is synced,
5100% otherwise MagickFalse.
5101%
5102% The format of the SyncAuthenticPixelsCache() method is:
5103%
5104% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5105% ExceptionInfo *exception)
5106%
5107% A description of each parameter follows:
5108%
5109% o image: the image.
5110%
5111% o exception: return any errors or warnings in this structure.
5112%
5113*/
5114static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5115 ExceptionInfo *exception)
5116{
5117 CacheInfo
5118 *cache_info;
5119
cristy5c9e6f22010-09-17 17:31:01 +00005120 const int
5121 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005122
cristy3ed852e2009-09-05 21:47:34 +00005123 cache_info=(CacheInfo *) image->cache;
cristy6ebe97c2010-07-03 01:17:28 +00005124 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00005125 return(SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5126 exception));
cristy3ed852e2009-09-05 21:47:34 +00005127}
5128
5129/*
5130%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5131% %
5132% %
5133% %
5134% S y n c A u t h e n t i c P i x e l s %
5135% %
5136% %
5137% %
5138%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5139%
5140% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5141% The method returns MagickTrue if the pixel region is flushed, otherwise
5142% MagickFalse.
5143%
5144% The format of the SyncAuthenticPixels() method is:
5145%
5146% MagickBooleanType SyncAuthenticPixels(Image *image,
5147% ExceptionInfo *exception)
5148%
5149% A description of each parameter follows:
5150%
5151% o image: the image.
5152%
5153% o exception: return any errors or warnings in this structure.
5154%
5155*/
5156MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5157 ExceptionInfo *exception)
5158{
5159 CacheInfo
5160 *cache_info;
5161
5162 assert(image != (Image *) NULL);
5163 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005164 assert(image->cache != (Cache) NULL);
5165 cache_info=(CacheInfo *) image->cache;
5166 assert(cache_info->signature == MagickSignature);
5167 if (cache_info->methods.sync_authentic_pixels_handler ==
5168 (SyncAuthenticPixelsHandler) NULL)
5169 return(MagickFalse);
5170 return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
5171}
5172
5173/*
5174%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5175% %
5176% %
5177% %
5178+ W r i t e P i x e l C a c h e I n d e x e s %
5179% %
5180% %
5181% %
5182%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5183%
5184% WritePixelCacheIndexes() writes the colormap indexes to the specified
5185% region of the pixel cache.
5186%
5187% The format of the WritePixelCacheIndexes() method is:
5188%
5189% MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5190% NexusInfo *nexus_info,ExceptionInfo *exception)
5191%
5192% A description of each parameter follows:
5193%
5194% o cache_info: the pixel cache.
5195%
5196% o nexus_info: the cache nexus to write the colormap indexes.
5197%
5198% o exception: return any errors or warnings in this structure.
5199%
5200*/
5201static MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5202 NexusInfo *nexus_info,ExceptionInfo *exception)
5203{
5204 MagickOffsetType
5205 count,
5206 offset;
5207
5208 MagickSizeType
5209 length,
5210 number_pixels;
5211
5212 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005213 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005214
cristybb503372010-05-27 20:51:26 +00005215 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005216 y;
5217
cristybb503372010-05-27 20:51:26 +00005218 size_t
cristy3ed852e2009-09-05 21:47:34 +00005219 rows;
5220
cristy3ed852e2009-09-05 21:47:34 +00005221 if (cache_info->active_index_channel == MagickFalse)
5222 return(MagickFalse);
5223 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5224 return(MagickTrue);
5225 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5226 nexus_info->region.x;
5227 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
5228 rows=nexus_info->region.height;
5229 number_pixels=(MagickSizeType) length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005230 p=nexus_info->indexes;
5231 switch (cache_info->type)
5232 {
5233 case MemoryCache:
5234 case MapCache:
5235 {
5236 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005237 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005238
5239 /*
5240 Write indexes to memory.
5241 */
cristydd341db2010-03-04 19:06:38 +00005242 if ((cache_info->columns == nexus_info->region.width) &&
5243 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5244 {
5245 length=number_pixels;
5246 rows=1UL;
5247 }
cristy3ed852e2009-09-05 21:47:34 +00005248 q=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00005249 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005250 {
5251 (void) CopyMagickMemory(q,p,(size_t) length);
5252 p+=nexus_info->region.width;
5253 q+=cache_info->columns;
5254 }
5255 break;
5256 }
5257 case DiskCache:
5258 {
5259 /*
5260 Write indexes to disk.
5261 */
5262 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5263 {
5264 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5265 cache_info->cache_filename);
5266 return(MagickFalse);
5267 }
cristydd341db2010-03-04 19:06:38 +00005268 if ((cache_info->columns == nexus_info->region.width) &&
5269 (number_pixels < MagickMaxBufferExtent))
5270 {
5271 length=number_pixels;
5272 rows=1UL;
5273 }
cristy3ed852e2009-09-05 21:47:34 +00005274 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005275 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005276 {
5277 count=WritePixelCacheRegion(cache_info,cache_info->offset+number_pixels*
5278 sizeof(PixelPacket)+offset*sizeof(*p),length,
5279 (const unsigned char *) p);
5280 if ((MagickSizeType) count < length)
5281 break;
5282 p+=nexus_info->region.width;
5283 offset+=cache_info->columns;
5284 }
cristybb503372010-05-27 20:51:26 +00005285 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005286 {
5287 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5288 cache_info->cache_filename);
5289 return(MagickFalse);
5290 }
5291 break;
5292 }
5293 default:
5294 break;
5295 }
5296 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005297 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005298 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005299 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005300 nexus_info->region.width,(double) nexus_info->region.height,(double)
5301 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005302 return(MagickTrue);
5303}
5304
5305/*
5306%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5307% %
5308% %
5309% %
5310+ W r i t e C a c h e P i x e l s %
5311% %
5312% %
5313% %
5314%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5315%
5316% WritePixelCachePixels() writes image pixels to the specified region of the
5317% pixel cache.
5318%
5319% The format of the WritePixelCachePixels() method is:
5320%
5321% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5322% NexusInfo *nexus_info,ExceptionInfo *exception)
5323%
5324% A description of each parameter follows:
5325%
5326% o cache_info: the pixel cache.
5327%
5328% o nexus_info: the cache nexus to write the pixels.
5329%
5330% o exception: return any errors or warnings in this structure.
5331%
5332*/
5333static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5334 NexusInfo *nexus_info,ExceptionInfo *exception)
5335{
5336 MagickOffsetType
5337 count,
5338 offset;
5339
5340 MagickSizeType
5341 length,
5342 number_pixels;
5343
cristy3ed852e2009-09-05 21:47:34 +00005344 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005345 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005346
cristybb503372010-05-27 20:51:26 +00005347 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005348 y;
5349
cristybb503372010-05-27 20:51:26 +00005350 size_t
cristy3ed852e2009-09-05 21:47:34 +00005351 rows;
5352
cristy3ed852e2009-09-05 21:47:34 +00005353 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5354 return(MagickTrue);
5355 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5356 nexus_info->region.x;
5357 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
5358 rows=nexus_info->region.height;
5359 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005360 p=nexus_info->pixels;
5361 switch (cache_info->type)
5362 {
5363 case MemoryCache:
5364 case MapCache:
5365 {
5366 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005367 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005368
5369 /*
5370 Write pixels to memory.
5371 */
cristydd341db2010-03-04 19:06:38 +00005372 if ((cache_info->columns == nexus_info->region.width) &&
5373 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5374 {
5375 length=number_pixels;
5376 rows=1UL;
5377 }
cristy3ed852e2009-09-05 21:47:34 +00005378 q=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00005379 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005380 {
5381 (void) CopyMagickMemory(q,p,(size_t) length);
5382 p+=nexus_info->region.width;
5383 q+=cache_info->columns;
5384 }
5385 break;
5386 }
5387 case DiskCache:
5388 {
5389 /*
5390 Write pixels to disk.
5391 */
5392 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5393 {
5394 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5395 cache_info->cache_filename);
5396 return(MagickFalse);
5397 }
cristydd341db2010-03-04 19:06:38 +00005398 if ((cache_info->columns == nexus_info->region.width) &&
5399 (number_pixels < MagickMaxBufferExtent))
5400 {
5401 length=number_pixels;
5402 rows=1UL;
5403 }
cristybb503372010-05-27 20:51:26 +00005404 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005405 {
5406 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5407 sizeof(*p),length,(const unsigned char *) p);
5408 if ((MagickSizeType) count < length)
5409 break;
5410 p+=nexus_info->region.width;
5411 offset+=cache_info->columns;
5412 }
cristybb503372010-05-27 20:51:26 +00005413 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005414 {
5415 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5416 cache_info->cache_filename);
5417 return(MagickFalse);
5418 }
5419 break;
5420 }
5421 default:
5422 break;
5423 }
5424 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005425 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005426 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005427 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005428 nexus_info->region.width,(double) nexus_info->region.height,(double)
5429 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005430 return(MagickTrue);
5431}