blob: 670bb1ea47001044f1c4051c4eae391bb9671db9 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% CCCC AAA CCCC H H EEEEE %
7% C A A C H H E %
8% C AAAAA C HHHHH EEE %
9% C A A C H H E %
10% CCCC A A CCCC H H EEEEE %
11% %
12% %
13% MagickCore Pixel Cache Methods %
14% %
15% Software Design %
16% John Cristy %
17% July 1999 %
18% %
19% %
cristy16af1cb2009-12-11 21:38:29 +000020% Copyright 1999-2010 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
26% http://www.imagemagick.org/script/license.php %
27% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37%
38*/
39
40/*
41 Include declarations.
42*/
43#include "magick/studio.h"
44#include "magick/blob.h"
45#include "magick/blob-private.h"
46#include "magick/cache.h"
47#include "magick/cache-private.h"
48#include "magick/color-private.h"
49#include "magick/composite-private.h"
50#include "magick/exception.h"
51#include "magick/exception-private.h"
cristy365e58f2010-02-15 02:00:01 +000052#include "magick/geometry.h"
cristy3ed852e2009-09-05 21:47:34 +000053#include "magick/list.h"
54#include "magick/log.h"
55#include "magick/magick.h"
56#include "magick/memory_.h"
cristy4789f0d2010-01-10 00:01:06 +000057#include "magick/pixel.h"
cristy3ed852e2009-09-05 21:47:34 +000058#include "magick/pixel-private.h"
cristya21afde2010-07-02 00:45:40 +000059#include "magick/policy.h"
cristy3ed852e2009-09-05 21:47:34 +000060#include "magick/quantum.h"
61#include "magick/random_.h"
62#include "magick/resource_.h"
63#include "magick/semaphore.h"
64#include "magick/splay-tree.h"
65#include "magick/string_.h"
cristya21afde2010-07-02 00:45:40 +000066#include "magick/string-private.h"
cristy3ed852e2009-09-05 21:47:34 +000067#include "magick/thread-private.h"
68#include "magick/utility.h"
69#if defined(MAGICKCORE_ZLIB_DELEGATE)
70#include "zlib.h"
71#endif
72
73/*
cristy30097232010-07-01 02:16:30 +000074 Define declarations.
75*/
76#define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
77
78/*
cristy3ed852e2009-09-05 21:47:34 +000079 Typedef declarations.
80*/
81typedef struct _MagickModulo
82{
cristybb503372010-05-27 20:51:26 +000083 ssize_t
cristy3ed852e2009-09-05 21:47:34 +000084 quotient,
85 remainder;
86} MagickModulo;
87
88struct _NexusInfo
89{
90 MagickBooleanType
91 mapped;
92
93 RectangleInfo
94 region;
95
96 MagickSizeType
97 length;
98
99 PixelPacket
100 *cache,
101 *pixels;
102
103 IndexPacket
104 *indexes;
105
cristybb503372010-05-27 20:51:26 +0000106 size_t
cristy3ed852e2009-09-05 21:47:34 +0000107 signature;
108};
109
110/*
111 Forward declarations.
112*/
113#if defined(__cplusplus) || defined(c_plusplus)
114extern "C" {
115#endif
116
117static const IndexPacket
118 *GetVirtualIndexesFromCache(const Image *);
119
120static const PixelPacket
cristybb503372010-05-27 20:51:26 +0000121 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
122 const ssize_t,const size_t,const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000123 *GetVirtualPixelsCache(const Image *);
124
125static MagickBooleanType
cristy09c1c4d2010-06-30 18:23:16 +0000126 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,
127 PixelPacket *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000128 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
cristybb503372010-05-27 20:51:26 +0000129 const ssize_t,const ssize_t,PixelPacket *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000130 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
131 ReadPixelCacheIndexes(CacheInfo *,NexusInfo *,ExceptionInfo *),
132 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
133 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
134 WritePixelCacheIndexes(CacheInfo *,NexusInfo *,ExceptionInfo *),
135 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
136
137static PixelPacket
cristybb503372010-05-27 20:51:26 +0000138 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
139 const size_t,ExceptionInfo *),
140 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
141 const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000142 *SetPixelCacheNexusPixels(const Image *,const RectangleInfo *,NexusInfo *,
cristya4af2e32010-03-08 00:51:56 +0000143 ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +0000144
145#if defined(__cplusplus) || defined(c_plusplus)
146}
147#endif
148
149/*
150 Global declarations.
151*/
152static volatile MagickBooleanType
153 instantiate_cache = MagickFalse;
154
155static SemaphoreInfo
156 *cache_semaphore = (SemaphoreInfo *) NULL;
157
158static SplayTreeInfo
159 *cache_resources = (SplayTreeInfo *) NULL;
cristy3ed852e2009-09-05 21:47:34 +0000160
161/*
162%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
163% %
164% %
165% %
166+ A c q u i r e P i x e l C a c h e %
167% %
168% %
169% %
170%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
171%
172% AcquirePixelCache() acquires a pixel cache.
173%
174% The format of the AcquirePixelCache() method is:
175%
cristybb503372010-05-27 20:51:26 +0000176% Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000177%
178% A description of each parameter follows:
179%
180% o number_threads: the number of nexus threads.
181%
182*/
cristybb503372010-05-27 20:51:26 +0000183MagickExport Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000184{
185 CacheInfo
186 *cache_info;
187
188 cache_info=(CacheInfo *) AcquireAlignedMemory(1,sizeof(*cache_info));
189 if (cache_info == (CacheInfo *) NULL)
190 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
191 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
192 cache_info->type=UndefinedCache;
cristy87528ea2009-09-10 14:53:56 +0000193 cache_info->mode=IOMode;
cristy3ed852e2009-09-05 21:47:34 +0000194 cache_info->colorspace=RGBColorspace;
195 cache_info->file=(-1);
196 cache_info->id=GetMagickThreadId();
197 cache_info->number_threads=number_threads;
198 if (number_threads == 0)
199 cache_info->number_threads=GetOpenMPMaximumThreads();
200 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
201 if (cache_info->nexus_info == (NexusInfo **) NULL)
202 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristy3ed852e2009-09-05 21:47:34 +0000203 cache_info->semaphore=AllocateSemaphoreInfo();
cristy93505cf2010-08-10 21:37:49 +0000204 cache_info->reference_count=1;
cristy3ed852e2009-09-05 21:47:34 +0000205 cache_info->disk_semaphore=AllocateSemaphoreInfo();
206 cache_info->debug=IsEventLogging();
207 cache_info->signature=MagickSignature;
208 if ((cache_resources == (SplayTreeInfo *) NULL) &&
209 (instantiate_cache == MagickFalse))
210 {
cristy4e1dff62009-10-25 20:36:03 +0000211 if (cache_semaphore == (SemaphoreInfo *) NULL)
212 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000213 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000214 if ((cache_resources == (SplayTreeInfo *) NULL) &&
215 (instantiate_cache == MagickFalse))
216 {
217 cache_resources=NewSplayTree((int (*)(const void *,const void *))
218 NULL,(void *(*)(void *)) NULL,(void *(*)(void *)) NULL);
219 instantiate_cache=MagickTrue;
220 }
cristyf84a1932010-01-03 18:00:18 +0000221 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000222 }
223 (void) AddValueToSplayTree(cache_resources,cache_info,cache_info);
224 return((Cache ) cache_info);
225}
226
227/*
228%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
229% %
230% %
231% %
232% A c q u i r e P i x e l C a c h e N e x u s %
233% %
234% %
235% %
236%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
237%
238% AcquirePixelCacheNexus() allocates the NexusInfo structure.
239%
240% The format of the AcquirePixelCacheNexus method is:
241%
cristybb503372010-05-27 20:51:26 +0000242% NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000243%
244% A description of each parameter follows:
245%
246% o number_threads: the number of nexus threads.
247%
248*/
cristy2cd7a752010-08-23 00:48:54 +0000249MagickExport NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000250{
cristy3ed852e2009-09-05 21:47:34 +0000251 NexusInfo
252 **nexus_info;
253
cristye076a6e2010-08-15 19:59:43 +0000254 register ssize_t
255 i;
256
cristy3ed852e2009-09-05 21:47:34 +0000257 nexus_info=(NexusInfo **) AcquireAlignedMemory(number_threads,
258 sizeof(*nexus_info));
259 if (nexus_info == (NexusInfo **) NULL)
260 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristybb503372010-05-27 20:51:26 +0000261 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000262 {
263 nexus_info[i]=(NexusInfo *) AcquireAlignedMemory(1,sizeof(**nexus_info));
264 if (nexus_info[i] == (NexusInfo *) NULL)
265 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
266 (void) ResetMagickMemory(nexus_info[i],0,sizeof(*nexus_info[i]));
267 nexus_info[i]->signature=MagickSignature;
268 }
269 return(nexus_info);
270}
271
272/*
273%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
274% %
275% %
276% %
cristyd43a46b2010-01-21 02:13:41 +0000277+ A c q u i r e P i x e l C a c h e P i x e l s %
278% %
279% %
280% %
281%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
282%
283% AcquirePixelCachePixels() returns the pixels associated with the specified
284% image.
285%
286% The format of the AcquirePixelCachePixels() method is:
287%
288% const void *AcquirePixelCachePixels(const Image *image,
289% MagickSizeType *length,ExceptionInfo *exception)
290%
291% A description of each parameter follows:
292%
293% o image: the image.
294%
295% o length: the pixel cache length.
296%
297% o exception: return any errors or warnings in this structure.
298%
299*/
300MagickExport const void *AcquirePixelCachePixels(const Image *image,
301 MagickSizeType *length,ExceptionInfo *exception)
302{
303 CacheInfo
304 *cache_info;
305
306 assert(image != (const Image *) NULL);
307 assert(image->signature == MagickSignature);
cristyd43a46b2010-01-21 02:13:41 +0000308 assert(exception != (ExceptionInfo *) NULL);
309 assert(exception->signature == MagickSignature);
310 assert(image->cache != (Cache) NULL);
311 cache_info=(CacheInfo *) image->cache;
312 assert(cache_info->signature == MagickSignature);
313 *length=0;
314 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
315 return((const void *) NULL);
316 *length=cache_info->length;
317 return((const void *) cache_info->pixels);
318}
319
320/*
321%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
322% %
323% %
324% %
cristyf34a1452009-10-24 22:29:27 +0000325+ C a c h e C o m p o n e n t G e n e s i s %
326% %
327% %
328% %
329%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
330%
331% CacheComponentGenesis() instantiates the cache component.
332%
333% The format of the CacheComponentGenesis method is:
334%
335% MagickBooleanType CacheComponentGenesis(void)
336%
337*/
338MagickExport MagickBooleanType CacheComponentGenesis(void)
339{
cristy165b6092009-10-26 13:52:10 +0000340 AcquireSemaphoreInfo(&cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000341 return(MagickTrue);
342}
343
344/*
345%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
346% %
347% %
348% %
349+ C a c h e C o m p o n e n t T e r m i n u s %
350% %
351% %
352% %
353%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
354%
355% CacheComponentTerminus() destroys the cache component.
356%
357% The format of the CacheComponentTerminus() method is:
358%
359% CacheComponentTerminus(void)
360%
361*/
362MagickExport void CacheComponentTerminus(void)
363{
cristy18b17442009-10-25 18:36:48 +0000364 if (cache_semaphore == (SemaphoreInfo *) NULL)
365 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000366 LockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000367 if (cache_resources != (SplayTreeInfo *) NULL)
368 cache_resources=DestroySplayTree(cache_resources);
369 instantiate_cache=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +0000370 UnlockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000371 DestroySemaphoreInfo(&cache_semaphore);
372}
373
374/*
375%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
376% %
377% %
378% %
cristy3ed852e2009-09-05 21:47:34 +0000379+ C l i p P i x e l C a c h e N e x u s %
380% %
381% %
382% %
383%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
384%
385% ClipPixelCacheNexus() clips the cache nexus as defined by the image clip
386% mask. The method returns MagickTrue if the pixel region is clipped,
387% otherwise MagickFalse.
388%
389% The format of the ClipPixelCacheNexus() method is:
390%
391% MagickBooleanType ClipPixelCacheNexus(Image *image,NexusInfo *nexus_info,
392% ExceptionInfo *exception)
393%
394% A description of each parameter follows:
395%
396% o image: the image.
397%
398% o nexus_info: the cache nexus to clip.
399%
400% o exception: return any errors or warnings in this structure.
401%
402*/
403static MagickBooleanType ClipPixelCacheNexus(Image *image,
404 NexusInfo *nexus_info,ExceptionInfo *exception)
405{
406 CacheInfo
407 *cache_info;
408
409 MagickSizeType
410 number_pixels;
411
412 NexusInfo
413 **clip_nexus,
414 **image_nexus;
415
416 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000417 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +0000418
419 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +0000420 *restrict nexus_indexes,
421 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +0000422
cristy3ed852e2009-09-05 21:47:34 +0000423 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000424 *restrict p,
425 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000426
cristye076a6e2010-08-15 19:59:43 +0000427 register ssize_t
428 i;
429
cristy3ed852e2009-09-05 21:47:34 +0000430 /*
431 Apply clip mask.
432 */
433 if (image->debug != MagickFalse)
434 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
435 if (image->clip_mask == (Image *) NULL)
436 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +0000437 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +0000438 if (cache_info == (Cache) NULL)
439 return(MagickFalse);
440 image_nexus=AcquirePixelCacheNexus(1);
441 clip_nexus=AcquirePixelCacheNexus(1);
442 if ((image_nexus == (NexusInfo **) NULL) ||
443 (clip_nexus == (NexusInfo **) NULL))
444 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
445 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,nexus_info->region.y,
446 nexus_info->region.width,nexus_info->region.height,image_nexus[0],
447 exception);
448 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
449 q=nexus_info->pixels;
450 nexus_indexes=nexus_info->indexes;
451 r=GetVirtualPixelsFromNexus(image->clip_mask,MaskVirtualPixelMethod,
452 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
453 nexus_info->region.height,clip_nexus[0],exception);
454 number_pixels=(MagickSizeType) nexus_info->region.width*
455 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +0000456 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000457 {
458 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
459 break;
460 if (PixelIntensityToQuantum(r) > ((Quantum) QuantumRange/2))
461 {
cristyce70c172010-01-07 17:15:30 +0000462 SetRedPixelComponent(q,GetRedPixelComponent(p));
463 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
464 SetBluePixelComponent(q,GetBluePixelComponent(p));
465 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
cristy3ed852e2009-09-05 21:47:34 +0000466 if (cache_info->active_index_channel != MagickFalse)
467 nexus_indexes[i]=indexes[i];
468 }
469 p++;
470 q++;
471 r++;
472 }
473 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
474 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +0000475 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +0000476 return(MagickFalse);
477 return(MagickTrue);
478}
479
480/*
481%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
482% %
483% %
484% %
485+ C l o n e P i x e l C a c h e %
486% %
487% %
488% %
489%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
490%
491% ClonePixelCache() clones a pixel cache.
492%
493% The format of the ClonePixelCache() method is:
494%
495% Cache ClonePixelCache(const Cache cache)
496%
497% A description of each parameter follows:
498%
499% o cache: the pixel cache.
500%
501*/
502MagickExport Cache ClonePixelCache(const Cache cache)
503{
504 CacheInfo
505 *clone_info;
506
507 const CacheInfo
508 *cache_info;
509
510 assert(cache != (const Cache) NULL);
511 cache_info=(const CacheInfo *) cache;
512 assert(cache_info->signature == MagickSignature);
513 if (cache_info->debug != MagickFalse)
514 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
515 cache_info->filename);
516 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
517 if (clone_info == (Cache) NULL)
518 return((Cache) NULL);
519 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
520 return((Cache ) clone_info);
521}
522
523/*
524%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
525% %
526% %
527% %
cristy60c44a82009-10-07 00:58:49 +0000528+ C l o n e P i x e l C a c h e P i x e l s %
cristy3ed852e2009-09-05 21:47:34 +0000529% %
530% %
531% %
532%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
533% ClonePixelCachePixels() clones the source pixel cache to the destination
534% cache.
535%
536% The format of the ClonePixelCachePixels() method is:
537%
538% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
539% CacheInfo *source_info,ExceptionInfo *exception)
540%
541% A description of each parameter follows:
542%
543% o cache_info: the pixel cache.
544%
545% o source_info: the source pixel cache.
546%
547% o exception: return any errors or warnings in this structure.
548%
549*/
550
551static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
552{
553 int
554 status;
555
cristy5ee247a2010-02-12 15:42:34 +0000556 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000557 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000558 if (cache_info->file != -1)
559 status=close(cache_info->file);
cristy3ed852e2009-09-05 21:47:34 +0000560 cache_info->file=(-1);
561 RelinquishMagickResource(FileResource,1);
cristyf84a1932010-01-03 18:00:18 +0000562 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000563 return(status == -1 ? MagickFalse : MagickTrue);
564}
565
566static void LimitPixelCacheDescriptors(void)
567{
568 register CacheInfo
569 *p,
570 *q;
571
572 /*
573 Limit # of open file descriptors.
574 */
575 if (GetMagickResource(FileResource) < GetMagickResourceLimit(FileResource))
576 return;
cristyf84a1932010-01-03 18:00:18 +0000577 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000578 if (cache_resources == (SplayTreeInfo *) NULL)
579 {
cristyf84a1932010-01-03 18:00:18 +0000580 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000581 return;
582 }
583 ResetSplayTreeIterator(cache_resources);
584 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
585 while (p != (CacheInfo *) NULL)
586 {
587 if ((p->type == DiskCache) && (p->file != -1))
cristy508d9312010-02-10 21:10:30 +0000588 break;
cristy3ed852e2009-09-05 21:47:34 +0000589 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
590 }
591 for (q=p; p != (CacheInfo *) NULL; )
592 {
593 if ((p->type == DiskCache) && (p->file != -1) &&
594 (p->timestamp < q->timestamp))
cristy508d9312010-02-10 21:10:30 +0000595 q=p;
cristy3ed852e2009-09-05 21:47:34 +0000596 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
597 }
598 if (q != (CacheInfo *) NULL)
cristy9e116922010-02-12 20:58:13 +0000599 {
600 /*
601 Close least recently used cache.
602 */
603 (void) close(q->file);
604 q->file=(-1);
605 }
cristyf84a1932010-01-03 18:00:18 +0000606 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000607}
608
609static inline MagickSizeType MagickMax(const MagickSizeType x,
610 const MagickSizeType y)
611{
612 if (x > y)
613 return(x);
614 return(y);
615}
616
617static inline MagickSizeType MagickMin(const MagickSizeType x,
618 const MagickSizeType y)
619{
620 if (x < y)
621 return(x);
622 return(y);
623}
624
625static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
626 const MapMode mode)
627{
628 int
629 file;
630
631 /*
632 Open pixel cache on disk.
633 */
cristyf84a1932010-01-03 18:00:18 +0000634 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000635 if (cache_info->file != -1)
636 {
cristyf84a1932010-01-03 18:00:18 +0000637 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000638 return(MagickTrue); /* cache already open */
639 }
640 LimitPixelCacheDescriptors();
641 if (*cache_info->cache_filename == '\0')
642 file=AcquireUniqueFileResource(cache_info->cache_filename);
643 else
644 switch (mode)
645 {
646 case ReadMode:
647 {
648 file=open(cache_info->cache_filename,O_RDONLY | O_BINARY);
649 break;
650 }
651 case WriteMode:
652 {
653 file=open(cache_info->cache_filename,O_WRONLY | O_CREAT | O_BINARY |
654 O_EXCL,S_MODE);
655 if (file == -1)
656 file=open(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
657 break;
658 }
659 case IOMode:
660 default:
661 {
662 file=open(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
663 O_EXCL,S_MODE);
664 if (file == -1)
665 file=open(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
666 break;
667 }
668 }
669 if (file == -1)
670 {
cristyf84a1932010-01-03 18:00:18 +0000671 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000672 return(MagickFalse);
673 }
674 (void) AcquireMagickResource(FileResource,1);
675 cache_info->file=file;
676 cache_info->timestamp=time(0);
cristyf84a1932010-01-03 18:00:18 +0000677 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000678 return(MagickTrue);
679}
680
681static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
682 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000683 unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000684{
685 register MagickOffsetType
686 i;
687
688 ssize_t
689 count;
690
cristy08a88202010-03-04 19:18:05 +0000691 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000692#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000693 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000694 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
695 {
cristyf84a1932010-01-03 18:00:18 +0000696 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000697 return((MagickOffsetType) -1);
698 }
699#endif
700 count=0;
701 for (i=0; i < (MagickOffsetType) length; i+=count)
702 {
703#if !defined(MAGICKCORE_HAVE_PREAD)
704 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
705 (MagickSizeType) SSIZE_MAX));
706#else
707 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
708 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
709#endif
710 if (count > 0)
711 continue;
712 count=0;
713 if (errno != EINTR)
714 {
715 i=(-1);
716 break;
717 }
718 }
719#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000720 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000721#endif
722 return(i);
723}
724
725static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
726 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000727 const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000728{
729 register MagickOffsetType
730 i;
731
732 ssize_t
733 count;
734
cristy08a88202010-03-04 19:18:05 +0000735 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000736#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000737 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000738 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
739 {
cristyf84a1932010-01-03 18:00:18 +0000740 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000741 return((MagickOffsetType) -1);
742 }
743#endif
744 count=0;
745 for (i=0; i < (MagickOffsetType) length; i+=count)
746 {
747#if !defined(MAGICKCORE_HAVE_PWRITE)
748 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
749 (MagickSizeType) SSIZE_MAX));
750#else
751 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
752 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
753#endif
754 if (count > 0)
755 continue;
756 count=0;
757 if (errno != EINTR)
758 {
759 i=(-1);
760 break;
761 }
762 }
763#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000764 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000765#endif
766 return(i);
767}
768
769static MagickBooleanType CloneDiskToDiskPixelCache(CacheInfo *clone_info,
770 CacheInfo *cache_info,ExceptionInfo *exception)
771{
772 MagickOffsetType
773 count,
774 offset,
775 source_offset;
776
777 MagickSizeType
778 length;
779
cristy3ed852e2009-09-05 21:47:34 +0000780 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000781 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +0000782
cristye076a6e2010-08-15 19:59:43 +0000783 register ssize_t
784 y;
785
cristybb503372010-05-27 20:51:26 +0000786 size_t
cristy3ed852e2009-09-05 21:47:34 +0000787 columns,
788 rows;
789
790 if (cache_info->debug != MagickFalse)
791 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
792 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
793 {
794 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
795 clone_info->cache_filename);
796 return(MagickFalse);
797 }
798 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
799 {
800 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
801 cache_info->cache_filename);
802 return(MagickFalse);
803 }
cristybb503372010-05-27 20:51:26 +0000804 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
805 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +0000806 if ((clone_info->active_index_channel != MagickFalse) &&
807 (cache_info->active_index_channel != MagickFalse))
808 {
809 register IndexPacket
810 *indexes;
811
812 /*
813 Clone cache indexes.
814 */
815 length=MagickMax(clone_info->columns,cache_info->columns)*
816 sizeof(*indexes);
817 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
818 if (indexes == (IndexPacket *) NULL)
819 {
820 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
821 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
822 return(MagickFalse);
823 }
824 (void) ResetMagickMemory(indexes,0,(size_t) length);
825 length=columns*sizeof(*indexes);
826 source_offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
827 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
828 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
829 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +0000830 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000831 {
832 source_offset-=cache_info->columns*sizeof(*indexes);
833 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
834 length,(unsigned char *) indexes);
835 if ((MagickSizeType) count != length)
836 break;
837 offset-=clone_info->columns*sizeof(*indexes);
838 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
839 (unsigned char *) indexes);
840 if ((MagickSizeType) count != length)
841 break;
842 }
cristybb503372010-05-27 20:51:26 +0000843 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000844 {
845 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
846 ThrowFileException(exception,CacheError,"UnableToCloneCache",
847 cache_info->cache_filename);
848 return(MagickFalse);
849 }
850 if (clone_info->columns > cache_info->columns)
851 {
852 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
853 (void) ResetMagickMemory(indexes,0,(size_t) length);
854 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
855 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +0000856 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000857 {
858 offset-=clone_info->columns*sizeof(*indexes);
859 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
860 length,(unsigned char *) indexes);
861 if ((MagickSizeType) count != length)
862 break;
863 }
cristybb503372010-05-27 20:51:26 +0000864 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000865 {
866 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
867 ThrowFileException(exception,CacheError,"UnableToCloneCache",
868 cache_info->cache_filename);
869 return(MagickFalse);
870 }
871 }
872 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
873 }
874 /*
875 Clone cache pixels.
876 */
877 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
878 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
879 if (pixels == (PixelPacket *) NULL)
880 {
881 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
882 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
883 return(MagickFalse);
884 }
885 (void) ResetMagickMemory(pixels,0,(size_t) length);
886 length=columns*sizeof(*pixels);
887 source_offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
888 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +0000889 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000890 {
891 source_offset-=cache_info->columns*sizeof(*pixels);
892 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
893 length,(unsigned char *) pixels);
894 if ((MagickSizeType) count != length)
895 break;
896 offset-=clone_info->columns*sizeof(*pixels);
897 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
898 (unsigned char *) pixels);
899 if ((MagickSizeType) count != length)
900 break;
901 }
cristybb503372010-05-27 20:51:26 +0000902 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000903 {
904 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
905 ThrowFileException(exception,CacheError,"UnableToCloneCache",
906 cache_info->cache_filename);
907 return(MagickFalse);
908 }
909 if (clone_info->columns > cache_info->columns)
910 {
911 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
912 sizeof(*pixels);
913 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
914 (void) ResetMagickMemory(pixels,0,(size_t) length);
cristybb503372010-05-27 20:51:26 +0000915 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000916 {
917 offset-=clone_info->columns*sizeof(*pixels);
918 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
919 (unsigned char *) pixels);
920 if ((MagickSizeType) count != length)
921 break;
922 }
cristybb503372010-05-27 20:51:26 +0000923 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000924 {
925 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
926 ThrowFileException(exception,CacheError,"UnableToCloneCache",
927 cache_info->cache_filename);
928 return(MagickFalse);
929 }
930 }
931 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
932 return(MagickTrue);
933}
934
935static MagickBooleanType CloneDiskToMemoryPixelCache(CacheInfo *clone_info,
936 CacheInfo *cache_info,ExceptionInfo *exception)
937{
938 MagickOffsetType
939 count,
940 offset;
941
942 MagickSizeType
943 length;
944
cristy3ed852e2009-09-05 21:47:34 +0000945 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000946 *restrict pixels,
947 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000948
cristye076a6e2010-08-15 19:59:43 +0000949 register ssize_t
950 y;
951
cristybb503372010-05-27 20:51:26 +0000952 size_t
cristy3ed852e2009-09-05 21:47:34 +0000953 columns,
954 rows;
955
956 if (cache_info->debug != MagickFalse)
957 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
958 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
959 {
960 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
961 cache_info->cache_filename);
962 return(MagickFalse);
963 }
cristybb503372010-05-27 20:51:26 +0000964 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
965 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +0000966 if ((clone_info->active_index_channel != MagickFalse) &&
967 (cache_info->active_index_channel != MagickFalse))
968 {
969 register IndexPacket
970 *indexes,
971 *q;
972
973 /*
974 Clone cache indexes.
975 */
976 length=MagickMax(clone_info->columns,cache_info->columns)*
977 sizeof(*indexes);
978 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
979 if (indexes == (IndexPacket *) NULL)
980 {
981 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
982 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
983 return(MagickFalse);
984 }
985 (void) ResetMagickMemory(indexes,0,(size_t) length);
986 length=columns*sizeof(IndexPacket);
987 offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
988 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
989 q=clone_info->indexes+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +0000990 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000991 {
992 offset-=cache_info->columns*sizeof(IndexPacket);
993 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,
994 length,(unsigned char *) indexes);
995 if ((MagickSizeType) count != length)
996 break;
997 q-=clone_info->columns;
cristy8f036fe2010-09-18 02:02:00 +0000998 (void) memcpy(q,indexes,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +0000999 if ((MagickSizeType) count != length)
1000 break;
1001 }
cristybb503372010-05-27 20:51:26 +00001002 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001003 {
1004 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1005 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1006 cache_info->cache_filename);
1007 return(MagickFalse);
1008 }
1009 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1010 }
1011 /*
1012 Clone cache pixels.
1013 */
1014 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1015 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1016 if (pixels == (PixelPacket *) NULL)
1017 {
1018 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1019 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1020 return(MagickFalse);
1021 }
1022 (void) ResetMagickMemory(pixels,0,(size_t) length);
1023 length=columns*sizeof(*pixels);
1024 offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
1025 q=clone_info->pixels+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001026 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001027 {
1028 offset-=cache_info->columns*sizeof(*pixels);
1029 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,length,
1030 (unsigned char *) pixels);
1031 if ((MagickSizeType) count != length)
1032 break;
1033 q-=clone_info->columns;
cristy8f036fe2010-09-18 02:02:00 +00001034 (void) memcpy(q,pixels,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00001035 }
cristybb503372010-05-27 20:51:26 +00001036 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001037 {
1038 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1039 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1040 cache_info->cache_filename);
1041 return(MagickFalse);
1042 }
1043 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1044 return(MagickTrue);
1045}
1046
1047static MagickBooleanType CloneMemoryToDiskPixelCache(CacheInfo *clone_info,
1048 CacheInfo *cache_info,ExceptionInfo *exception)
1049{
1050 MagickOffsetType
1051 count,
1052 offset;
1053
1054 MagickSizeType
1055 length;
1056
cristy3ed852e2009-09-05 21:47:34 +00001057 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001058 *restrict p,
1059 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +00001060
cristye076a6e2010-08-15 19:59:43 +00001061 register ssize_t
1062 y;
1063
cristybb503372010-05-27 20:51:26 +00001064 size_t
cristy3ed852e2009-09-05 21:47:34 +00001065 columns,
1066 rows;
1067
1068 if (cache_info->debug != MagickFalse)
1069 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
1070 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
1071 {
1072 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1073 clone_info->cache_filename);
1074 return(MagickFalse);
1075 }
cristybb503372010-05-27 20:51:26 +00001076 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1077 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001078 if ((clone_info->active_index_channel != MagickFalse) &&
1079 (cache_info->active_index_channel != MagickFalse))
1080 {
1081 register IndexPacket
1082 *p,
1083 *indexes;
1084
1085 /*
1086 Clone cache indexes.
1087 */
1088 length=MagickMax(clone_info->columns,cache_info->columns)*
1089 sizeof(*indexes);
1090 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
1091 if (indexes == (IndexPacket *) NULL)
1092 {
1093 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1094 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1095 return(MagickFalse);
1096 }
1097 (void) ResetMagickMemory(indexes,0,(size_t) length);
1098 length=columns*sizeof(*indexes);
1099 p=cache_info->indexes+cache_info->columns*rows;
1100 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1101 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +00001102 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001103 {
1104 p-=cache_info->columns;
cristy8f036fe2010-09-18 02:02:00 +00001105 (void) memcpy(indexes,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00001106 offset-=clone_info->columns*sizeof(*indexes);
1107 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1108 (unsigned char *) indexes);
1109 if ((MagickSizeType) count != length)
1110 break;
1111 }
cristybb503372010-05-27 20:51:26 +00001112 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001113 {
1114 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1115 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1116 cache_info->cache_filename);
1117 return(MagickFalse);
1118 }
1119 if (clone_info->columns > cache_info->columns)
1120 {
1121 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
1122 (void) ResetMagickMemory(indexes,0,(size_t) length);
1123 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1124 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +00001125 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001126 {
1127 offset-=clone_info->columns*sizeof(*indexes);
1128 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
1129 length,(unsigned char *) indexes);
1130 if ((MagickSizeType) count != length)
1131 break;
1132 }
cristybb503372010-05-27 20:51:26 +00001133 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001134 {
1135 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1136 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1137 cache_info->cache_filename);
1138 return(MagickFalse);
1139 }
1140 }
1141 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1142 }
1143 /*
1144 Clone cache pixels.
1145 */
1146 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1147 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1148 if (pixels == (PixelPacket *) NULL)
1149 {
1150 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1151 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1152 return(MagickFalse);
1153 }
1154 (void) ResetMagickMemory(pixels,0,(size_t) length);
1155 length=columns*sizeof(*pixels);
1156 p=cache_info->pixels+cache_info->columns*rows;
1157 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +00001158 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001159 {
1160 p-=cache_info->columns;
cristy8f036fe2010-09-18 02:02:00 +00001161 (void) memcpy(pixels,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00001162 offset-=clone_info->columns*sizeof(*pixels);
1163 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1164 (unsigned char *) pixels);
1165 if ((MagickSizeType) count != length)
1166 break;
1167 }
cristybb503372010-05-27 20:51:26 +00001168 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001169 {
1170 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1171 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1172 cache_info->cache_filename);
1173 return(MagickFalse);
1174 }
1175 if (clone_info->columns > cache_info->columns)
1176 {
1177 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
1178 sizeof(*pixels);
1179 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1180 (void) ResetMagickMemory(pixels,0,(size_t) length);
cristybb503372010-05-27 20:51:26 +00001181 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001182 {
1183 offset-=clone_info->columns*sizeof(*pixels);
1184 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1185 (unsigned char *) pixels);
1186 if ((MagickSizeType) count != length)
1187 break;
1188 }
cristybb503372010-05-27 20:51:26 +00001189 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001190 {
1191 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1192 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1193 cache_info->cache_filename);
1194 return(MagickFalse);
1195 }
1196 }
1197 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1198 return(MagickTrue);
1199}
1200
1201static MagickBooleanType CloneMemoryToMemoryPixelCache(CacheInfo *clone_info,
1202 CacheInfo *cache_info,ExceptionInfo *magick_unused(exception))
1203{
cristy3ed852e2009-09-05 21:47:34 +00001204 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001205 *restrict pixels,
1206 *restrict source_pixels;
cristy3ed852e2009-09-05 21:47:34 +00001207
cristye076a6e2010-08-15 19:59:43 +00001208 register ssize_t
1209 y;
cristy3ed852e2009-09-05 21:47:34 +00001210
cristybb503372010-05-27 20:51:26 +00001211 size_t
cristy3ed852e2009-09-05 21:47:34 +00001212 columns,
cristye076a6e2010-08-15 19:59:43 +00001213 length,
cristy3ed852e2009-09-05 21:47:34 +00001214 rows;
1215
1216 if (cache_info->debug != MagickFalse)
1217 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
cristybb503372010-05-27 20:51:26 +00001218 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1219 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001220 if ((clone_info->active_index_channel != MagickFalse) &&
1221 (cache_info->active_index_channel != MagickFalse))
1222 {
1223 register IndexPacket
1224 *indexes,
1225 *source_indexes;
1226
1227 /*
1228 Clone cache indexes.
1229 */
1230 length=columns*sizeof(*indexes);
1231 if (clone_info->columns == cache_info->columns)
cristy8f036fe2010-09-18 02:02:00 +00001232 (void) memcpy(clone_info->indexes,cache_info->indexes,length*rows);
cristy3ed852e2009-09-05 21:47:34 +00001233 else
1234 {
1235 source_indexes=cache_info->indexes+cache_info->columns*rows;
1236 indexes=clone_info->indexes+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001237 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001238 {
1239 source_indexes-=cache_info->columns;
1240 indexes-=clone_info->columns;
cristy8f036fe2010-09-18 02:02:00 +00001241 (void) memcpy(indexes,source_indexes,length);
cristy3ed852e2009-09-05 21:47:34 +00001242 }
1243 if (clone_info->columns > cache_info->columns)
1244 {
1245 length=(clone_info->columns-cache_info->columns)*
1246 sizeof(*indexes);
1247 indexes=clone_info->indexes+clone_info->columns*rows+
1248 cache_info->columns;
cristybb503372010-05-27 20:51:26 +00001249 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001250 {
1251 indexes-=clone_info->columns;
1252 (void) ResetMagickMemory(indexes,0,length);
1253 }
1254 }
1255 }
1256 }
1257 /*
1258 Clone cache pixels.
1259 */
1260 length=columns*sizeof(*pixels);
1261 if (clone_info->columns == cache_info->columns)
cristy8f036fe2010-09-18 02:02:00 +00001262 (void) memcpy(clone_info->pixels,cache_info->pixels,length*rows);
cristy3ed852e2009-09-05 21:47:34 +00001263 else
1264 {
1265 source_pixels=cache_info->pixels+cache_info->columns*rows;
1266 pixels=clone_info->pixels+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001267 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001268 {
1269 source_pixels-=cache_info->columns;
1270 pixels-=clone_info->columns;
cristy8f036fe2010-09-18 02:02:00 +00001271 (void) memcpy(pixels,source_pixels,length);
cristy3ed852e2009-09-05 21:47:34 +00001272 }
1273 if (clone_info->columns > cache_info->columns)
1274 {
1275 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1276 pixels=clone_info->pixels+clone_info->columns*rows+
1277 cache_info->columns;
cristybb503372010-05-27 20:51:26 +00001278 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001279 {
1280 pixels-=clone_info->columns;
1281 (void) ResetMagickMemory(pixels,0,length);
1282 }
1283 }
1284 }
1285 return(MagickTrue);
1286}
1287
1288static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1289 CacheInfo *cache_info,ExceptionInfo *exception)
1290{
1291 if ((clone_info->type != DiskCache) && (cache_info->type != DiskCache))
1292 return(CloneMemoryToMemoryPixelCache(clone_info,cache_info,exception));
1293 if ((clone_info->type == DiskCache) && (cache_info->type == DiskCache))
1294 return(CloneDiskToDiskPixelCache(clone_info,cache_info,exception));
1295 if (cache_info->type == DiskCache)
1296 return(CloneDiskToMemoryPixelCache(clone_info,cache_info,exception));
1297 return(CloneMemoryToDiskPixelCache(clone_info,cache_info,exception));
1298}
1299
1300/*
1301%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1302% %
1303% %
1304% %
1305+ C l o n e P i x e l C a c h e M e t h o d s %
1306% %
1307% %
1308% %
1309%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1310%
1311% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1312% another.
1313%
1314% The format of the ClonePixelCacheMethods() method is:
1315%
1316% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1317%
1318% A description of each parameter follows:
1319%
1320% o clone: Specifies a pointer to a Cache structure.
1321%
1322% o cache: the pixel cache.
1323%
1324*/
1325MagickExport void ClonePixelCacheMethods(Cache clone,const Cache cache)
1326{
1327 CacheInfo
1328 *cache_info,
1329 *source_info;
1330
1331 assert(clone != (Cache) NULL);
1332 source_info=(CacheInfo *) clone;
1333 assert(source_info->signature == MagickSignature);
1334 if (source_info->debug != MagickFalse)
1335 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1336 source_info->filename);
1337 assert(cache != (Cache) NULL);
1338 cache_info=(CacheInfo *) cache;
1339 assert(cache_info->signature == MagickSignature);
1340 source_info->methods=cache_info->methods;
1341}
1342
1343/*
1344%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1345% %
1346% %
1347% %
1348+ D e s t r o y I m a g e P i x e l C a c h e %
1349% %
1350% %
1351% %
1352%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1353%
1354% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1355%
1356% The format of the DestroyImagePixelCache() method is:
1357%
1358% void DestroyImagePixelCache(Image *image)
1359%
1360% A description of each parameter follows:
1361%
1362% o image: the image.
1363%
1364*/
1365static void DestroyImagePixelCache(Image *image)
1366{
1367 assert(image != (Image *) NULL);
1368 assert(image->signature == MagickSignature);
1369 if (image->debug != MagickFalse)
1370 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1371 if (image->cache == (void *) NULL)
1372 return;
1373 image->cache=DestroyPixelCache(image->cache);
1374}
1375
1376/*
1377%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1378% %
1379% %
1380% %
1381+ D e s t r o y I m a g e P i x e l s %
1382% %
1383% %
1384% %
1385%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1386%
1387% DestroyImagePixels() deallocates memory associated with the pixel cache.
1388%
1389% The format of the DestroyImagePixels() method is:
1390%
1391% void DestroyImagePixels(Image *image)
1392%
1393% A description of each parameter follows:
1394%
1395% o image: the image.
1396%
1397*/
1398MagickExport void DestroyImagePixels(Image *image)
1399{
1400 CacheInfo
1401 *cache_info;
1402
1403 assert(image != (const Image *) NULL);
1404 assert(image->signature == MagickSignature);
1405 if (image->debug != MagickFalse)
1406 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1407 assert(image->cache != (Cache) NULL);
1408 cache_info=(CacheInfo *) image->cache;
1409 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001410 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1411 {
1412 cache_info->methods.destroy_pixel_handler(image);
1413 return;
1414 }
1415 DestroyImagePixelCache(image);
cristy3ed852e2009-09-05 21:47:34 +00001416}
1417
1418/*
1419%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1420% %
1421% %
1422% %
1423+ D e s t r o y P i x e l C a c h e %
1424% %
1425% %
1426% %
1427%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1428%
1429% DestroyPixelCache() deallocates memory associated with the pixel cache.
1430%
1431% The format of the DestroyPixelCache() method is:
1432%
1433% Cache DestroyPixelCache(Cache cache)
1434%
1435% A description of each parameter follows:
1436%
1437% o cache: the pixel cache.
1438%
1439*/
1440
1441static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1442{
1443 switch (cache_info->type)
1444 {
1445 case MemoryCache:
1446 {
1447 if (cache_info->mapped == MagickFalse)
1448 cache_info->pixels=(PixelPacket *) RelinquishMagickMemory(
1449 cache_info->pixels);
1450 else
1451 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,
1452 (size_t) cache_info->length);
1453 RelinquishMagickResource(MemoryResource,cache_info->length);
1454 break;
1455 }
1456 case MapCache:
1457 {
1458 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,(size_t)
1459 cache_info->length);
1460 RelinquishMagickResource(MapResource,cache_info->length);
1461 }
1462 case DiskCache:
1463 {
1464 if (cache_info->file != -1)
1465 (void) ClosePixelCacheOnDisk(cache_info);
1466 RelinquishMagickResource(DiskResource,cache_info->length);
1467 break;
1468 }
1469 default:
1470 break;
1471 }
1472 cache_info->type=UndefinedCache;
1473 cache_info->mapped=MagickFalse;
1474 cache_info->indexes=(IndexPacket *) NULL;
1475}
1476
1477MagickExport Cache DestroyPixelCache(Cache cache)
1478{
1479 CacheInfo
1480 *cache_info;
1481
cristy3ed852e2009-09-05 21:47:34 +00001482 assert(cache != (Cache) NULL);
1483 cache_info=(CacheInfo *) cache;
1484 assert(cache_info->signature == MagickSignature);
1485 if (cache_info->debug != MagickFalse)
1486 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1487 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001488 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001489 cache_info->reference_count--;
1490 if (cache_info->reference_count != 0)
1491 {
cristyf84a1932010-01-03 18:00:18 +00001492 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001493 return((Cache) NULL);
1494 }
cristyf84a1932010-01-03 18:00:18 +00001495 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001496 if (cache_resources != (SplayTreeInfo *) NULL)
1497 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
cristy5b8de732009-09-10 23:50:40 +00001498 if (cache_info->debug != MagickFalse)
1499 {
1500 char
1501 message[MaxTextExtent];
1502
1503 (void) FormatMagickString(message,MaxTextExtent,"destroy %s",
1504 cache_info->filename);
1505 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1506 }
cristyc2e1bdd2009-09-10 23:43:34 +00001507 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1508 (cache_info->type != DiskCache)))
1509 RelinquishPixelCachePixels(cache_info);
1510 else
1511 {
1512 RelinquishPixelCachePixels(cache_info);
1513 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1514 }
cristy3ed852e2009-09-05 21:47:34 +00001515 *cache_info->cache_filename='\0';
1516 if (cache_info->nexus_info != (NexusInfo **) NULL)
1517 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1518 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001519 if (cache_info->random_info != (RandomInfo *) NULL)
1520 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001521 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1522 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1523 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1524 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001525 cache_info->signature=(~MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001526 cache_info=(CacheInfo *) RelinquishAlignedMemory(cache_info);
1527 cache=(Cache) NULL;
1528 return(cache);
1529}
1530
1531/*
1532%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1533% %
1534% %
1535% %
1536+ D e s t r o y P i x e l C a c h e N e x u s %
1537% %
1538% %
1539% %
1540%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1541%
1542% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1543%
1544% The format of the DestroyPixelCacheNexus() method is:
1545%
1546% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001547% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001548%
1549% A description of each parameter follows:
1550%
1551% o nexus_info: the nexus to destroy.
1552%
1553% o number_threads: the number of nexus threads.
1554%
1555*/
1556
1557static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1558{
1559 if (nexus_info->mapped == MagickFalse)
1560 (void) RelinquishMagickMemory(nexus_info->cache);
1561 else
1562 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1563 nexus_info->cache=(PixelPacket *) NULL;
1564 nexus_info->pixels=(PixelPacket *) NULL;
1565 nexus_info->indexes=(IndexPacket *) NULL;
1566 nexus_info->length=0;
1567 nexus_info->mapped=MagickFalse;
1568}
1569
1570MagickExport NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001571 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001572{
cristybb503372010-05-27 20:51:26 +00001573 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001574 i;
1575
1576 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001577 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001578 {
1579 if (nexus_info[i]->cache != (PixelPacket *) NULL)
1580 RelinquishCacheNexusPixels(nexus_info[i]);
1581 nexus_info[i]->signature=(~MagickSignature);
1582 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
1583 }
1584 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
1585 return(nexus_info);
1586}
1587
1588/*
1589%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1590% %
1591% %
1592% %
cristy3ed852e2009-09-05 21:47:34 +00001593+ G e t A u t h e n t i c I n d e x e s F r o m C a c h e %
1594% %
1595% %
1596% %
1597%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1598%
1599% GetAuthenticIndexesFromCache() returns the indexes associated with the last
1600% call to QueueAuthenticPixelsCache() or GetAuthenticPixelsCache().
1601%
1602% The format of the GetAuthenticIndexesFromCache() method is:
1603%
1604% IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1605%
1606% A description of each parameter follows:
1607%
1608% o image: the image.
1609%
1610*/
1611static IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1612{
1613 CacheInfo
1614 *cache_info;
1615
cristy5c9e6f22010-09-17 17:31:01 +00001616 const int
1617 id = GetOpenMPThreadId();
1618
cristy3ed852e2009-09-05 21:47:34 +00001619 cache_info=(CacheInfo *) image->cache;
cristy6ebe97c2010-07-03 01:17:28 +00001620 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001621 return(GetPixelCacheNexusIndexes(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001622}
1623
1624/*
1625%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1626% %
1627% %
1628% %
1629% G e t A u t h e n t i c I n d e x Q u e u e %
1630% %
1631% %
1632% %
1633%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1634%
1635% GetAuthenticIndexQueue() returns the authentic black channel or the colormap
1636% indexes associated with the last call to QueueAuthenticPixels() or
1637% GetVirtualPixels(). NULL is returned if the black channel or colormap
1638% indexes are not available.
1639%
1640% The format of the GetAuthenticIndexQueue() method is:
1641%
1642% IndexPacket *GetAuthenticIndexQueue(const Image *image)
1643%
1644% A description of each parameter follows:
1645%
1646% o image: the image.
1647%
1648*/
1649MagickExport IndexPacket *GetAuthenticIndexQueue(const Image *image)
1650{
1651 CacheInfo
1652 *cache_info;
1653
1654 assert(image != (const Image *) NULL);
1655 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001656 assert(image->cache != (Cache) NULL);
1657 cache_info=(CacheInfo *) image->cache;
1658 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001659 if (cache_info->methods.get_authentic_indexes_from_handler !=
cristy3ed852e2009-09-05 21:47:34 +00001660 (GetAuthenticIndexesFromHandler) NULL)
cristyd317f372010-09-18 01:42:20 +00001661 return(cache_info->methods.get_authentic_indexes_from_handler(image));
1662 return(GetAuthenticIndexesFromCache(image));
cristy3ed852e2009-09-05 21:47:34 +00001663}
1664
1665/*
1666%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1667% %
1668% %
1669% %
1670+ 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 %
1671% %
1672% %
1673% %
1674%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1675%
1676% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1677% disk pixel cache as defined by the geometry parameters. A pointer to the
1678% pixels is returned if the pixels are transferred, otherwise a NULL is
1679% returned.
1680%
1681% The format of the GetAuthenticPixelCacheNexus() method is:
1682%
cristybb503372010-05-27 20:51:26 +00001683% PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1684% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001685% NexusInfo *nexus_info,ExceptionInfo *exception)
1686%
1687% A description of each parameter follows:
1688%
1689% o image: the image.
1690%
1691% o x,y,columns,rows: These values define the perimeter of a region of
1692% pixels.
1693%
1694% o nexus_info: the cache nexus to return.
1695%
1696% o exception: return any errors or warnings in this structure.
1697%
1698*/
1699
1700static inline MagickBooleanType IsNexusInCore(const CacheInfo *cache_info,
1701 NexusInfo *nexus_info)
1702{
1703 MagickOffsetType
1704 offset;
1705
cristy73724512010-04-12 14:43:14 +00001706 if (cache_info->type == PingCache)
1707 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001708 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1709 nexus_info->region.x;
1710 if (nexus_info->pixels != (cache_info->pixels+offset))
1711 return(MagickFalse);
1712 return(MagickTrue);
1713}
1714
cristye076a6e2010-08-15 19:59:43 +00001715MagickExport PixelPacket *GetAuthenticPixelCacheNexus(Image *image,
1716 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001717 NexusInfo *nexus_info,ExceptionInfo *exception)
1718{
1719 CacheInfo
1720 *cache_info;
1721
1722 PixelPacket
1723 *pixels;
1724
1725 /*
1726 Transfer pixels from the cache.
1727 */
1728 assert(image != (Image *) NULL);
1729 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001730 pixels=QueueAuthenticNexus(image,x,y,columns,rows,nexus_info,exception);
1731 if (pixels == (PixelPacket *) NULL)
1732 return((PixelPacket *) NULL);
1733 cache_info=(CacheInfo *) image->cache;
1734 assert(cache_info->signature == MagickSignature);
1735 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
1736 return(pixels);
1737 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1738 return((PixelPacket *) NULL);
1739 if (cache_info->active_index_channel != MagickFalse)
1740 if (ReadPixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse)
1741 return((PixelPacket *) NULL);
1742 return(pixels);
1743}
1744
1745/*
1746%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1747% %
1748% %
1749% %
1750+ 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 %
1751% %
1752% %
1753% %
1754%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1755%
1756% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1757% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1758%
1759% The format of the GetAuthenticPixelsFromCache() method is:
1760%
1761% PixelPacket *GetAuthenticPixelsFromCache(const Image image)
1762%
1763% A description of each parameter follows:
1764%
1765% o image: the image.
1766%
1767*/
1768static PixelPacket *GetAuthenticPixelsFromCache(const Image *image)
1769{
1770 CacheInfo
1771 *cache_info;
1772
cristy5c9e6f22010-09-17 17:31:01 +00001773 const int
1774 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001775
cristy3ed852e2009-09-05 21:47:34 +00001776 cache_info=(CacheInfo *) image->cache;
cristy6ebe97c2010-07-03 01:17:28 +00001777 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001778 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001779}
1780
1781/*
1782%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1783% %
1784% %
1785% %
1786% G e t A u t h e n t i c P i x e l Q u e u e %
1787% %
1788% %
1789% %
1790%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1791%
1792% GetAuthenticPixelQueue() returns the authentic pixels associated with the
1793% last call to QueueAuthenticPixels() or GetAuthenticPixels().
1794%
1795% The format of the GetAuthenticPixelQueue() method is:
1796%
1797% PixelPacket *GetAuthenticPixelQueue(const Image image)
1798%
1799% A description of each parameter follows:
1800%
1801% o image: the image.
1802%
1803*/
1804MagickExport PixelPacket *GetAuthenticPixelQueue(const Image *image)
1805{
1806 CacheInfo
1807 *cache_info;
1808
1809 assert(image != (const Image *) NULL);
1810 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001811 assert(image->cache != (Cache) NULL);
1812 cache_info=(CacheInfo *) image->cache;
1813 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001814 if (cache_info->methods.get_authentic_pixels_from_handler !=
1815 (GetAuthenticPixelsFromHandler) NULL)
1816 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1817 return(GetAuthenticPixelsFromCache(image));
cristy3ed852e2009-09-05 21:47:34 +00001818}
1819
1820/*
1821%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1822% %
1823% %
1824% %
1825% G e t A u t h e n t i c P i x e l s %
1826% %
1827% %
1828% %
1829%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1830%
1831% GetAuthenticPixels() obtains a pixel region for read/write access. If the
1832% region is successfully accessed, a pointer to a PixelPacket array
1833% representing the region is returned, otherwise NULL is returned.
1834%
1835% The returned pointer may point to a temporary working copy of the pixels
1836% or it may point to the original pixels in memory. Performance is maximized
1837% if the selected region is part of one row, or one or more full rows, since
1838% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001839% if the image is in memory, or in a memory-mapped file. The returned pointer
1840% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001841%
1842% Pixels accessed via the returned pointer represent a simple array of type
1843% PixelPacket. If the image type is CMYK or if the storage class is
1844% PseduoClass, call GetAuthenticIndexQueue() after invoking
1845% GetAuthenticPixels() to obtain the black color component or colormap indexes
1846% (of type IndexPacket) corresponding to the region. Once the PixelPacket
1847% (and/or IndexPacket) array has been updated, the changes must be saved back
1848% to the underlying image using SyncAuthenticPixels() or they may be lost.
1849%
1850% The format of the GetAuthenticPixels() method is:
1851%
cristy5f959472010-05-27 22:19:46 +00001852% PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1853% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001854% ExceptionInfo *exception)
1855%
1856% A description of each parameter follows:
1857%
1858% o image: the image.
1859%
1860% o x,y,columns,rows: These values define the perimeter of a region of
1861% pixels.
1862%
1863% o exception: return any errors or warnings in this structure.
1864%
1865*/
cristybb503372010-05-27 20:51:26 +00001866MagickExport PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1867 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001868 ExceptionInfo *exception)
1869{
1870 CacheInfo
1871 *cache_info;
1872
cristy3ed852e2009-09-05 21:47:34 +00001873 assert(image != (Image *) NULL);
1874 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001875 assert(image->cache != (Cache) NULL);
1876 cache_info=(CacheInfo *) image->cache;
1877 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001878 if (cache_info->methods.get_authentic_pixels_handler !=
1879 (GetAuthenticPixelsHandler) NULL)
1880 return(cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1881 rows,exception));
1882 return(GetAuthenticPixelsCache(image,x,y,columns,rows,exception));
cristy3ed852e2009-09-05 21:47:34 +00001883}
1884
1885/*
1886%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1887% %
1888% %
1889% %
1890+ G e t A u t h e n t i c P i x e l s C a c h e %
1891% %
1892% %
1893% %
1894%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1895%
1896% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1897% as defined by the geometry parameters. A pointer to the pixels is returned
1898% if the pixels are transferred, otherwise a NULL is returned.
1899%
1900% The format of the GetAuthenticPixelsCache() method is:
1901%
cristybb503372010-05-27 20:51:26 +00001902% PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1903% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001904% ExceptionInfo *exception)
1905%
1906% A description of each parameter follows:
1907%
1908% o image: the image.
1909%
1910% o x,y,columns,rows: These values define the perimeter of a region of
1911% pixels.
1912%
1913% o exception: return any errors or warnings in this structure.
1914%
1915*/
cristybb503372010-05-27 20:51:26 +00001916static PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1917 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001918 ExceptionInfo *exception)
1919{
1920 CacheInfo
1921 *cache_info;
1922
cristy5c9e6f22010-09-17 17:31:01 +00001923 const int
1924 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001925
cristy77ff0282010-09-13 00:51:10 +00001926 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001927 if (cache_info == (Cache) NULL)
1928 return((PixelPacket *) NULL);
cristy6ebe97c2010-07-03 01:17:28 +00001929 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001930 return(GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1931 cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00001932}
1933
1934/*
1935%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1936% %
1937% %
1938% %
1939+ G e t I m a g e E x t e n t %
1940% %
1941% %
1942% %
1943%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1944%
1945% GetImageExtent() returns the extent of the pixels associated with the
1946% last call to QueueAuthenticPixels() or GetAuthenticPixels().
1947%
1948% The format of the GetImageExtent() method is:
1949%
1950% MagickSizeType GetImageExtent(const Image *image)
1951%
1952% A description of each parameter follows:
1953%
1954% o image: the image.
1955%
1956*/
1957MagickExport MagickSizeType GetImageExtent(const Image *image)
1958{
1959 CacheInfo
1960 *cache_info;
1961
cristy5c9e6f22010-09-17 17:31:01 +00001962 const int
1963 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001964
cristy3ed852e2009-09-05 21:47:34 +00001965 assert(image != (Image *) NULL);
1966 assert(image->signature == MagickSignature);
1967 if (image->debug != MagickFalse)
1968 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1969 assert(image->cache != (Cache) NULL);
1970 cache_info=(CacheInfo *) image->cache;
1971 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001972 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001973 return(GetPixelCacheNexusExtent(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001974}
1975
1976/*
1977%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1978% %
1979% %
1980% %
1981+ G e t I m a g e P i x e l C a c h e %
1982% %
1983% %
1984% %
1985%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1986%
1987% GetImagePixelCache() ensures that there is only a single reference to the
1988% pixel cache to be modified, updating the provided cache pointer to point to
1989% a clone of the original pixel cache if necessary.
1990%
1991% The format of the GetImagePixelCache method is:
1992%
1993% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1994% ExceptionInfo *exception)
1995%
1996% A description of each parameter follows:
1997%
1998% o image: the image.
1999%
2000% o clone: any value other than MagickFalse clones the cache pixels.
2001%
2002% o exception: return any errors or warnings in this structure.
2003%
2004*/
cristy3ed852e2009-09-05 21:47:34 +00002005static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
2006{
2007 CacheInfo
2008 *cache_info;
2009
2010 /*
2011 Does the image match the pixel cache morphology?
2012 */
2013 cache_info=(CacheInfo *) image->cache;
2014 if ((image->storage_class != cache_info->storage_class) ||
2015 (image->colorspace != cache_info->colorspace) ||
2016 (image->columns != cache_info->columns) ||
2017 (image->rows != cache_info->rows) ||
2018 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2019 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2020 return(MagickFalse);
2021 return(MagickTrue);
2022}
2023
cristy77ff0282010-09-13 00:51:10 +00002024static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2025 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002026{
2027 CacheInfo
2028 *cache_info;
2029
cristy3ed852e2009-09-05 21:47:34 +00002030 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00002031 destroy,
cristy3ed852e2009-09-05 21:47:34 +00002032 status;
2033
cristy50a10922010-02-15 18:35:25 +00002034 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00002035 cpu_throttle = 0,
2036 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00002037 time_limit = 0;
2038
cristy1ea34962010-07-01 19:49:21 +00002039 static time_t
cristya21afde2010-07-02 00:45:40 +00002040 cache_genesis = 0;
cristy1ea34962010-07-01 19:49:21 +00002041
cristyc4f9f132010-03-04 18:50:01 +00002042 status=MagickTrue;
2043 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00002044 if (cpu_throttle == 0)
2045 {
2046 char
2047 *limit;
2048
2049 /*
2050 Set CPU throttle in milleseconds.
2051 */
2052 cpu_throttle=MagickResourceInfinity;
2053 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2054 if (limit == (char *) NULL)
2055 limit=GetPolicyValue("throttle");
2056 if (limit != (char *) NULL)
2057 {
2058 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2059 limit=DestroyString(limit);
2060 }
2061 }
2062 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2063 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00002064 if (time_limit == 0)
2065 {
cristy6ebe97c2010-07-03 01:17:28 +00002066 /*
2067 Set the exire time in seconds.
2068 */
cristy1ea34962010-07-01 19:49:21 +00002069 time_limit=GetMagickResourceLimit(TimeResource);
cristya21afde2010-07-02 00:45:40 +00002070 cache_genesis=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00002071 }
2072 if ((time_limit != MagickResourceInfinity) &&
cristya21afde2010-07-02 00:45:40 +00002073 ((MagickSizeType) (time((time_t *) NULL)-cache_genesis) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00002074 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00002075 assert(image->cache != (Cache) NULL);
2076 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002077 destroy=MagickFalse;
cristy01b7eb02009-09-10 23:10:14 +00002078 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002079 {
cristyaaa0cb62010-02-15 17:47:27 +00002080 LockSemaphoreInfo(cache_info->semaphore);
2081 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002082 {
cristyaaa0cb62010-02-15 17:47:27 +00002083 Image
2084 clone_image;
2085
2086 CacheInfo
2087 *clone_info;
2088
2089 /*
2090 Clone pixel cache.
2091 */
2092 clone_image=(*image);
cristy93505cf2010-08-10 21:37:49 +00002093 clone_image.semaphore=AllocateSemaphoreInfo();
2094 clone_image.reference_count=1;
cristyaaa0cb62010-02-15 17:47:27 +00002095 clone_image.cache=ClonePixelCache(cache_info);
2096 clone_info=(CacheInfo *) clone_image.cache;
cristyabd6e372010-09-15 19:11:26 +00002097 status=OpenPixelCache(&clone_image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00002098 if (status != MagickFalse)
2099 {
cristyabd6e372010-09-15 19:11:26 +00002100 if (clone != MagickFalse)
2101 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00002102 if (status != MagickFalse)
2103 {
cristyabd6e372010-09-15 19:11:26 +00002104 destroy=MagickTrue;
2105 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00002106 }
2107 }
cristy93505cf2010-08-10 21:37:49 +00002108 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002109 }
cristyaaa0cb62010-02-15 17:47:27 +00002110 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002111 }
cristy4320e0e2009-09-10 15:00:08 +00002112 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002113 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002114 if (status != MagickFalse)
2115 {
2116 /*
2117 Ensure the image matches the pixel cache morphology.
2118 */
2119 image->taint=MagickTrue;
2120 image->type=UndefinedType;
cristydd438462010-05-06 13:44:04 +00002121 if (image->colorspace == GRAYColorspace)
2122 image->colorspace=RGBColorspace;
cristy3ed852e2009-09-05 21:47:34 +00002123 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2124 status=OpenPixelCache(image,IOMode,exception);
2125 }
cristyf84a1932010-01-03 18:00:18 +00002126 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002127 if (status == MagickFalse)
2128 return((Cache) NULL);
2129 return(image->cache);
2130}
2131
2132/*
2133%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2134% %
2135% %
2136% %
2137% G e t O n e A u t h e n t i c P i x e l %
2138% %
2139% %
2140% %
2141%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2142%
2143% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2144% location. The image background color is returned if an error occurs.
2145%
2146% The format of the GetOneAuthenticPixel() method is:
2147%
cristybb503372010-05-27 20:51:26 +00002148% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2149% const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002150%
2151% A description of each parameter follows:
2152%
2153% o image: the image.
2154%
2155% o x,y: These values define the location of the pixel to return.
2156%
2157% o pixel: return a pixel at the specified (x,y) location.
2158%
2159% o exception: return any errors or warnings in this structure.
2160%
2161*/
cristyacbbb7c2010-06-30 18:56:48 +00002162MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2163 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002164{
2165 CacheInfo
2166 *cache_info;
2167
cristy3ed852e2009-09-05 21:47:34 +00002168 assert(image != (Image *) NULL);
2169 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002170 assert(image->cache != (Cache) NULL);
2171 cache_info=(CacheInfo *) image->cache;
2172 assert(cache_info->signature == MagickSignature);
2173 *pixel=image->background_color;
cristyd317f372010-09-18 01:42:20 +00002174 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2175 (GetOneAuthenticPixelFromHandler) NULL)
2176 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2177 pixel,exception));
2178 return(GetOneAuthenticPixelFromCache(image,x,y,pixel,exception));
cristy3ed852e2009-09-05 21:47:34 +00002179}
2180
2181/*
2182%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2183% %
2184% %
2185% %
2186+ 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 %
2187% %
2188% %
2189% %
2190%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2191%
2192% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2193% location. The image background color is returned if an error occurs.
2194%
2195% The format of the GetOneAuthenticPixelFromCache() method is:
2196%
2197% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy5f959472010-05-27 22:19:46 +00002198% const ssize_t x,const ssize_t y,PixelPacket *pixel,
2199% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002200%
2201% A description of each parameter follows:
2202%
2203% o image: the image.
2204%
2205% o x,y: These values define the location of the pixel to return.
2206%
2207% o pixel: return a pixel at the specified (x,y) location.
2208%
2209% o exception: return any errors or warnings in this structure.
2210%
2211*/
2212static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristybb503372010-05-27 20:51:26 +00002213 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002214{
2215 PixelPacket
2216 *pixels;
2217
cristy3ed852e2009-09-05 21:47:34 +00002218 *pixel=image->background_color;
2219 pixels=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2220 if (pixels == (PixelPacket *) NULL)
2221 return(MagickFalse);
2222 *pixel=(*pixels);
2223 return(MagickTrue);
2224}
2225
2226/*
2227%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2228% %
2229% %
2230% %
2231% G e t O n e V i r t u a l M a g i c k P i x e l %
2232% %
2233% %
2234% %
2235%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2236%
2237% GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2238% location. The image background color is returned if an error occurs. If
2239% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2240%
2241% The format of the GetOneVirtualMagickPixel() method is:
2242%
2243% MagickBooleanType GetOneVirtualMagickPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002244% const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
cristy3ed852e2009-09-05 21:47:34 +00002245% ExceptionInfo exception)
2246%
2247% A description of each parameter follows:
2248%
2249% o image: the image.
2250%
2251% o x,y: these values define the location of the pixel to return.
2252%
2253% o pixel: return a pixel at the specified (x,y) location.
2254%
2255% o exception: return any errors or warnings in this structure.
2256%
2257*/
2258MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
cristyacbbb7c2010-06-30 18:56:48 +00002259 const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
2260 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002261{
2262 CacheInfo
2263 *cache_info;
2264
2265 register const IndexPacket
2266 *indexes;
2267
2268 register const PixelPacket
2269 *p;
2270
2271 assert(image != (const Image *) NULL);
2272 assert(image->signature == MagickSignature);
2273 assert(image->cache != (Cache) NULL);
2274 cache_info=(CacheInfo *) image->cache;
2275 assert(cache_info->signature == MagickSignature);
2276 GetMagickPixelPacket(image,pixel);
2277 p=GetVirtualPixelCache(image,GetPixelCacheVirtualMethod(image),x,y,1,1,
2278 exception);
2279 if (p == (const PixelPacket *) NULL)
2280 return(MagickFalse);
2281 indexes=GetVirtualIndexQueue(image);
2282 SetMagickPixelPacket(image,p,indexes,pixel);
2283 return(MagickTrue);
2284}
2285
2286/*
2287%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2288% %
2289% %
2290% %
2291% G e t O n e V i r t u a l M e t h o d P i x e l %
2292% %
2293% %
2294% %
2295%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2296%
2297% GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2298% location as defined by specified pixel method. The image background color
2299% is returned if an error occurs. If you plan to modify the pixel, use
2300% GetOneAuthenticPixel() instead.
2301%
2302% The format of the GetOneVirtualMethodPixel() method is:
2303%
2304% MagickBooleanType GetOneVirtualMethodPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002305% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2306% const ssize_t y,Pixelpacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002307%
2308% A description of each parameter follows:
2309%
2310% o image: the image.
2311%
2312% o virtual_pixel_method: the virtual pixel method.
2313%
2314% o x,y: These values define the location of the pixel to return.
2315%
2316% o pixel: return a pixel at the specified (x,y) location.
2317%
2318% o exception: return any errors or warnings in this structure.
2319%
2320*/
2321MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002322 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002323 PixelPacket *pixel,ExceptionInfo *exception)
2324{
cristy3ed852e2009-09-05 21:47:34 +00002325 CacheInfo
2326 *cache_info;
2327
cristy3ed852e2009-09-05 21:47:34 +00002328 assert(image != (const Image *) NULL);
2329 assert(image->signature == MagickSignature);
2330 assert(image->cache != (Cache) NULL);
2331 cache_info=(CacheInfo *) image->cache;
2332 assert(cache_info->signature == MagickSignature);
2333 *pixel=image->background_color;
cristyd317f372010-09-18 01:42:20 +00002334 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2335 (GetOneVirtualPixelFromHandler) NULL)
2336 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2337 virtual_pixel_method,x,y,pixel,exception));
2338 return(GetOneVirtualPixelFromCache(image,virtual_pixel_method,x,y,pixel,
2339 exception));
cristy3ed852e2009-09-05 21:47:34 +00002340}
2341
2342/*
2343%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2344% %
2345% %
2346% %
2347% G e t O n e V i r t u a l P i x e l %
2348% %
2349% %
2350% %
2351%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2352%
2353% GetOneVirtualPixel() returns a single virtual pixel at the specified
2354% (x,y) location. The image background color is returned if an error occurs.
2355% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2356%
2357% The format of the GetOneVirtualPixel() method is:
2358%
cristybb503372010-05-27 20:51:26 +00002359% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2360% const ssize_t y,PixelPacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002361%
2362% A description of each parameter follows:
2363%
2364% o image: the image.
2365%
2366% o x,y: These values define the location of the pixel to return.
2367%
2368% o pixel: return a pixel at the specified (x,y) location.
2369%
2370% o exception: return any errors or warnings in this structure.
2371%
2372*/
2373MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002374 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002375{
cristy3ed852e2009-09-05 21:47:34 +00002376 CacheInfo
2377 *cache_info;
2378
cristy3ed852e2009-09-05 21:47:34 +00002379 assert(image != (const Image *) NULL);
2380 assert(image->signature == MagickSignature);
2381 assert(image->cache != (Cache) NULL);
2382 cache_info=(CacheInfo *) image->cache;
2383 assert(cache_info->signature == MagickSignature);
2384 *pixel=image->background_color;
cristyd317f372010-09-18 01:42:20 +00002385 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2386 (GetOneVirtualPixelFromHandler) NULL)
2387 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2388 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
2389 return(GetOneVirtualPixelFromCache(image,GetPixelCacheVirtualMethod(image),
2390 x,y,pixel,exception));
cristy3ed852e2009-09-05 21:47:34 +00002391}
2392
2393/*
2394%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2395% %
2396% %
2397% %
2398+ 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 %
2399% %
2400% %
2401% %
2402%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2403%
2404% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2405% specified (x,y) location. The image background color is returned if an
2406% error occurs.
2407%
2408% The format of the GetOneVirtualPixelFromCache() method is:
2409%
2410% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristybb503372010-05-27 20:51:26 +00002411% const VirtualPixelPacket method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002412% PixelPacket *pixel,ExceptionInfo *exception)
2413%
2414% A description of each parameter follows:
2415%
2416% o image: the image.
2417%
2418% o virtual_pixel_method: the virtual pixel method.
2419%
2420% o x,y: These values define the location of the pixel to return.
2421%
2422% o pixel: return a pixel at the specified (x,y) location.
2423%
2424% o exception: return any errors or warnings in this structure.
2425%
2426*/
2427static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002428 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002429 PixelPacket *pixel,ExceptionInfo *exception)
2430{
2431 const PixelPacket
2432 *pixels;
2433
2434 *pixel=image->background_color;
2435 pixels=GetVirtualPixelCache(image,virtual_pixel_method,x,y,1UL,1UL,exception);
2436 if (pixels == (const PixelPacket *) NULL)
2437 return(MagickFalse);
2438 *pixel=(*pixels);
2439 return(MagickTrue);
2440}
2441
2442/*
2443%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2444% %
2445% %
2446% %
2447+ G e t P i x e l C a c h e C o l o r s p a c e %
2448% %
2449% %
2450% %
2451%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2452%
2453% GetPixelCacheColorspace() returns the class type of the pixel cache.
2454%
2455% The format of the GetPixelCacheColorspace() method is:
2456%
2457% Colorspace GetPixelCacheColorspace(Cache cache)
2458%
2459% A description of each parameter follows:
2460%
2461% o cache: the pixel cache.
2462%
2463*/
2464MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
2465{
2466 CacheInfo
2467 *cache_info;
2468
2469 assert(cache != (Cache) NULL);
2470 cache_info=(CacheInfo *) cache;
2471 assert(cache_info->signature == MagickSignature);
2472 if (cache_info->debug != MagickFalse)
2473 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2474 cache_info->filename);
2475 return(cache_info->colorspace);
2476}
2477
2478/*
2479%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2480% %
2481% %
2482% %
2483+ G e t P i x e l C a c h e M e t h o d s %
2484% %
2485% %
2486% %
2487%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2488%
2489% GetPixelCacheMethods() initializes the CacheMethods structure.
2490%
2491% The format of the GetPixelCacheMethods() method is:
2492%
2493% void GetPixelCacheMethods(CacheMethods *cache_methods)
2494%
2495% A description of each parameter follows:
2496%
2497% o cache_methods: Specifies a pointer to a CacheMethods structure.
2498%
2499*/
2500MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
2501{
2502 assert(cache_methods != (CacheMethods *) NULL);
2503 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2504 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2505 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2506 cache_methods->get_virtual_indexes_from_handler=GetVirtualIndexesFromCache;
2507 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2508 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2509 cache_methods->get_authentic_indexes_from_handler=
2510 GetAuthenticIndexesFromCache;
2511 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2512 cache_methods->get_one_authentic_pixel_from_handler=
2513 GetOneAuthenticPixelFromCache;
2514 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2515 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2516 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2517}
2518
2519/*
2520%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2521% %
2522% %
2523% %
2524+ G e t P i x e l C a c h e N e x u s E x t e n t %
2525% %
2526% %
2527% %
2528%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2529%
2530% GetPixelCacheNexusExtent() returns the extent of the pixels associated with
2531% the last call to SetPixelCacheNexusPixels() or GetPixelCacheNexusPixels().
2532%
2533% The format of the GetPixelCacheNexusExtent() method is:
2534%
2535% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2536% NexusInfo *nexus_info)
2537%
2538% A description of each parameter follows:
2539%
2540% o nexus_info: the nexus info.
2541%
2542*/
2543MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2544 NexusInfo *nexus_info)
2545{
2546 CacheInfo
2547 *cache_info;
2548
2549 MagickSizeType
2550 extent;
2551
2552 if (cache == (Cache) NULL)
2553 return(0);
2554 cache_info=(CacheInfo *) cache;
2555 assert(cache_info->signature == MagickSignature);
2556 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2557 if (extent == 0)
2558 return((MagickSizeType) cache_info->columns*cache_info->rows);
2559 return(extent);
2560}
2561
2562/*
2563%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2564% %
2565% %
2566% %
2567+ 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 %
2568% %
2569% %
2570% %
2571%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2572%
2573% GetPixelCacheNexusIndexes() returns the indexes associated with the
2574% specified cache nexus.
2575%
2576% The format of the GetPixelCacheNexusIndexes() method is:
2577%
2578% IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2579% NexusInfo *nexus_info)
2580%
2581% A description of each parameter follows:
2582%
2583% o cache: the pixel cache.
2584%
2585% o nexus_info: the cache nexus to return the colormap indexes.
2586%
2587*/
2588MagickExport IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2589 NexusInfo *nexus_info)
2590{
2591 CacheInfo
2592 *cache_info;
2593
2594 if (cache == (Cache) NULL)
2595 return((IndexPacket *) NULL);
2596 cache_info=(CacheInfo *) cache;
2597 assert(cache_info->signature == MagickSignature);
2598 if (cache_info->storage_class == UndefinedClass)
2599 return((IndexPacket *) NULL);
2600 return(nexus_info->indexes);
2601}
2602
2603/*
2604%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2605% %
2606% %
2607% %
2608+ G e t P i x e l C a c h e N e x u s P i x e l s %
2609% %
2610% %
2611% %
2612%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2613%
2614% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2615% cache nexus.
2616%
2617% The format of the GetPixelCacheNexusPixels() method is:
2618%
2619% PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2620% NexusInfo *nexus_info)
2621%
2622% A description of each parameter follows:
2623%
2624% o cache: the pixel cache.
2625%
2626% o nexus_info: the cache nexus to return the pixels.
2627%
2628*/
2629MagickExport PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2630 NexusInfo *nexus_info)
2631{
2632 CacheInfo
2633 *cache_info;
2634
2635 if (cache == (Cache) NULL)
2636 return((PixelPacket *) NULL);
2637 cache_info=(CacheInfo *) cache;
2638 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002639 if (cache_info->storage_class == UndefinedClass)
2640 return((PixelPacket *) NULL);
2641 return(nexus_info->pixels);
2642}
2643
2644/*
2645%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2646% %
2647% %
2648% %
cristy056ba772010-01-02 23:33:54 +00002649+ G e t P i x e l C a c h e P i x e l s %
2650% %
2651% %
2652% %
2653%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2654%
2655% GetPixelCachePixels() returns the pixels associated with the specified image.
2656%
2657% The format of the GetPixelCachePixels() method is:
2658%
cristyf84a1932010-01-03 18:00:18 +00002659% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2660% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002661%
2662% A description of each parameter follows:
2663%
2664% o image: the image.
2665%
2666% o length: the pixel cache length.
2667%
cristyf84a1932010-01-03 18:00:18 +00002668% o exception: return any errors or warnings in this structure.
2669%
cristy056ba772010-01-02 23:33:54 +00002670*/
cristyf84a1932010-01-03 18:00:18 +00002671MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2672 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002673{
2674 CacheInfo
2675 *cache_info;
2676
2677 assert(image != (const Image *) NULL);
2678 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002679 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00002680 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002681 assert(cache_info->signature == MagickSignature);
2682 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002683 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002684 return((void *) NULL);
2685 *length=cache_info->length;
2686 return((void *) cache_info->pixels);
2687}
2688
2689/*
2690%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2691% %
2692% %
2693% %
cristyb32b90a2009-09-07 21:45:48 +00002694+ 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 +00002695% %
2696% %
2697% %
2698%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2699%
2700% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2701%
2702% The format of the GetPixelCacheStorageClass() method is:
2703%
2704% ClassType GetPixelCacheStorageClass(Cache cache)
2705%
2706% A description of each parameter follows:
2707%
2708% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2709%
2710% o cache: the pixel cache.
2711%
2712*/
2713MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
2714{
2715 CacheInfo
2716 *cache_info;
2717
2718 assert(cache != (Cache) NULL);
2719 cache_info=(CacheInfo *) cache;
2720 assert(cache_info->signature == MagickSignature);
2721 if (cache_info->debug != MagickFalse)
2722 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2723 cache_info->filename);
2724 return(cache_info->storage_class);
2725}
2726
2727/*
2728%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2729% %
2730% %
2731% %
cristyb32b90a2009-09-07 21:45:48 +00002732+ G e t P i x e l C a c h e T i l e S i z e %
2733% %
2734% %
2735% %
2736%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2737%
2738% GetPixelCacheTileSize() returns the pixel cache tile size.
2739%
2740% The format of the GetPixelCacheTileSize() method is:
2741%
cristybb503372010-05-27 20:51:26 +00002742% void GetPixelCacheTileSize(const Image *image,size_t *width,
2743% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002744%
2745% A description of each parameter follows:
2746%
2747% o image: the image.
2748%
2749% o width: the optimize cache tile width in pixels.
2750%
2751% o height: the optimize cache tile height in pixels.
2752%
2753*/
cristybb503372010-05-27 20:51:26 +00002754MagickExport void GetPixelCacheTileSize(const Image *image,size_t *width,
2755 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002756{
2757 CacheInfo
2758 *cache_info;
2759
2760 assert(image != (Image *) NULL);
2761 assert(image->signature == MagickSignature);
2762 if (image->debug != MagickFalse)
2763 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2764 assert(image->cache != (Cache) NULL);
2765 cache_info=(CacheInfo *) image->cache;
2766 assert(cache_info->signature == MagickSignature);
2767 *width=2048UL/sizeof(PixelPacket);
2768 if (GetPixelCacheType(image) == DiskCache)
cristydaa97692009-09-13 02:10:35 +00002769 *width=8192UL/sizeof(PixelPacket);
cristyb32b90a2009-09-07 21:45:48 +00002770 *height=(*width);
2771}
2772
2773/*
2774%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2775% %
2776% %
2777% %
2778+ G e t P i x e l C a c h e T y p e %
2779% %
2780% %
2781% %
2782%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2783%
2784% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2785%
2786% The format of the GetPixelCacheType() method is:
2787%
2788% CacheType GetPixelCacheType(const Image *image)
2789%
2790% A description of each parameter follows:
2791%
2792% o image: the image.
2793%
2794*/
2795MagickExport CacheType GetPixelCacheType(const Image *image)
2796{
2797 CacheInfo
2798 *cache_info;
2799
2800 assert(image != (Image *) NULL);
2801 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002802 assert(image->cache != (Cache) NULL);
2803 cache_info=(CacheInfo *) image->cache;
2804 assert(cache_info->signature == MagickSignature);
2805 return(cache_info->type);
2806}
2807
2808/*
2809%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2810% %
2811% %
2812% %
cristy3ed852e2009-09-05 21:47:34 +00002813+ 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 %
2814% %
2815% %
2816% %
2817%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2818%
2819% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2820% pixel cache. A virtual pixel is any pixel access that is outside the
2821% boundaries of the image cache.
2822%
2823% The format of the GetPixelCacheVirtualMethod() method is:
2824%
2825% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2826%
2827% A description of each parameter follows:
2828%
2829% o image: the image.
2830%
2831*/
2832MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2833{
2834 CacheInfo
2835 *cache_info;
2836
2837 assert(image != (Image *) NULL);
2838 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002839 assert(image->cache != (Cache) NULL);
2840 cache_info=(CacheInfo *) image->cache;
2841 assert(cache_info->signature == MagickSignature);
2842 return(cache_info->virtual_pixel_method);
2843}
2844
2845/*
2846%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2847% %
2848% %
2849% %
2850+ 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 %
2851% %
2852% %
2853% %
2854%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2855%
2856% GetVirtualIndexesFromCache() returns the indexes associated with the last
2857% call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2858%
2859% The format of the GetVirtualIndexesFromCache() method is:
2860%
2861% IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2862%
2863% A description of each parameter follows:
2864%
2865% o image: the image.
2866%
2867*/
2868static const IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2869{
2870 CacheInfo
2871 *cache_info;
2872
cristy5c9e6f22010-09-17 17:31:01 +00002873 const int
2874 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002875
cristy3ed852e2009-09-05 21:47:34 +00002876 cache_info=(CacheInfo *) image->cache;
cristy6ebe97c2010-07-03 01:17:28 +00002877 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00002878 return(GetVirtualIndexesFromNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00002879}
2880
2881/*
2882%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2883% %
2884% %
2885% %
2886+ 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 %
2887% %
2888% %
2889% %
2890%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2891%
2892% GetVirtualIndexesFromNexus() returns the indexes associated with the
2893% specified cache nexus.
2894%
2895% The format of the GetVirtualIndexesFromNexus() method is:
2896%
2897% const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2898% NexusInfo *nexus_info)
2899%
2900% A description of each parameter follows:
2901%
2902% o cache: the pixel cache.
2903%
2904% o nexus_info: the cache nexus to return the colormap indexes.
2905%
2906*/
2907MagickExport const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2908 NexusInfo *nexus_info)
2909{
2910 CacheInfo
2911 *cache_info;
2912
2913 if (cache == (Cache) NULL)
2914 return((IndexPacket *) NULL);
2915 cache_info=(CacheInfo *) cache;
2916 assert(cache_info->signature == MagickSignature);
2917 if (cache_info->storage_class == UndefinedClass)
2918 return((IndexPacket *) NULL);
2919 return(nexus_info->indexes);
2920}
2921
2922/*
2923%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2924% %
2925% %
2926% %
2927% G e t V i r t u a l I n d e x Q u e u e %
2928% %
2929% %
2930% %
2931%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2932%
2933% GetVirtualIndexQueue() returns the virtual black channel or the
2934% colormap indexes associated with the last call to QueueAuthenticPixels() or
2935% GetVirtualPixels(). NULL is returned if the black channel or colormap
2936% indexes are not available.
2937%
2938% The format of the GetVirtualIndexQueue() method is:
2939%
2940% const IndexPacket *GetVirtualIndexQueue(const Image *image)
2941%
2942% A description of each parameter follows:
2943%
2944% o image: the image.
2945%
2946*/
2947MagickExport const IndexPacket *GetVirtualIndexQueue(const Image *image)
2948{
2949 CacheInfo
2950 *cache_info;
2951
2952 assert(image != (const Image *) NULL);
2953 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002954 assert(image->cache != (Cache) NULL);
2955 cache_info=(CacheInfo *) image->cache;
2956 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00002957 if (cache_info->methods.get_virtual_indexes_from_handler !=
2958 (GetVirtualIndexesFromHandler) NULL)
2959 return(cache_info->methods.get_virtual_indexes_from_handler(image));
2960 return(GetVirtualIndexesFromCache(image));
cristy3ed852e2009-09-05 21:47:34 +00002961}
2962
2963/*
2964%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2965% %
2966% %
2967% %
2968+ 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 %
2969% %
2970% %
2971% %
2972%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2973%
2974% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2975% pixel cache as defined by the geometry parameters. A pointer to the pixels
2976% is returned if the pixels are transferred, otherwise a NULL is returned.
2977%
2978% The format of the GetVirtualPixelsFromNexus() method is:
2979%
2980% PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00002981% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00002982% const size_t columns,const size_t rows,NexusInfo *nexus_info,
2983% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002984%
2985% A description of each parameter follows:
2986%
2987% o image: the image.
2988%
2989% o virtual_pixel_method: the virtual pixel method.
2990%
2991% o x,y,columns,rows: These values define the perimeter of a region of
2992% pixels.
2993%
2994% o nexus_info: the cache nexus to acquire.
2995%
2996% o exception: return any errors or warnings in this structure.
2997%
2998*/
2999
cristybb503372010-05-27 20:51:26 +00003000static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003001 DitherMatrix[64] =
3002 {
3003 0, 48, 12, 60, 3, 51, 15, 63,
3004 32, 16, 44, 28, 35, 19, 47, 31,
3005 8, 56, 4, 52, 11, 59, 7, 55,
3006 40, 24, 36, 20, 43, 27, 39, 23,
3007 2, 50, 14, 62, 1, 49, 13, 61,
3008 34, 18, 46, 30, 33, 17, 45, 29,
3009 10, 58, 6, 54, 9, 57, 5, 53,
3010 42, 26, 38, 22, 41, 25, 37, 21
3011 };
3012
cristybb503372010-05-27 20:51:26 +00003013static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003014{
cristybb503372010-05-27 20:51:26 +00003015 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003016 index;
3017
3018 index=x+DitherMatrix[x & 0x07]-32L;
3019 if (index < 0L)
3020 return(0L);
cristybb503372010-05-27 20:51:26 +00003021 if (index >= (ssize_t) columns)
3022 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00003023 return(index);
3024}
3025
cristybb503372010-05-27 20:51:26 +00003026static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003027{
cristybb503372010-05-27 20:51:26 +00003028 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003029 index;
3030
3031 index=y+DitherMatrix[y & 0x07]-32L;
3032 if (index < 0L)
3033 return(0L);
cristybb503372010-05-27 20:51:26 +00003034 if (index >= (ssize_t) rows)
3035 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00003036 return(index);
3037}
3038
cristybb503372010-05-27 20:51:26 +00003039static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003040{
3041 if (x < 0L)
3042 return(0L);
cristybb503372010-05-27 20:51:26 +00003043 if (x >= (ssize_t) columns)
3044 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003045 return(x);
3046}
3047
cristybb503372010-05-27 20:51:26 +00003048static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003049{
3050 if (y < 0L)
3051 return(0L);
cristybb503372010-05-27 20:51:26 +00003052 if (y >= (ssize_t) rows)
3053 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003054 return(y);
3055}
3056
cristybb503372010-05-27 20:51:26 +00003057static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003058{
cristybb503372010-05-27 20:51:26 +00003059 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003060}
3061
cristybb503372010-05-27 20:51:26 +00003062static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003063{
cristybb503372010-05-27 20:51:26 +00003064 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003065}
3066
3067/*
3068 VirtualPixelModulo() computes the remainder of dividing offset by extent. It
3069 returns not only the quotient (tile the offset falls in) but also the positive
3070 remainer within that tile such that 0 <= remainder < extent. This method is
3071 essentially a ldiv() using a floored modulo division rather than the normal
3072 default truncated modulo division.
3073*/
cristybb503372010-05-27 20:51:26 +00003074static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3075 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003076{
3077 MagickModulo
3078 modulo;
3079
cristybb503372010-05-27 20:51:26 +00003080 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003081 if (offset < 0L)
3082 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003083 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003084 return(modulo);
3085}
3086
3087MagickExport const PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003088 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3089 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003090 ExceptionInfo *exception)
3091{
3092 CacheInfo
3093 *cache_info;
3094
cristyc3ec0d42010-04-07 01:18:08 +00003095 IndexPacket
3096 virtual_index;
3097
cristy3ed852e2009-09-05 21:47:34 +00003098 MagickOffsetType
3099 offset;
3100
3101 MagickSizeType
3102 length,
3103 number_pixels;
3104
3105 NexusInfo
3106 **virtual_nexus;
3107
3108 PixelPacket
3109 *pixels,
3110 virtual_pixel;
3111
3112 RectangleInfo
3113 region;
3114
3115 register const IndexPacket
cristyc3ec0d42010-04-07 01:18:08 +00003116 *restrict virtual_indexes;
cristy3ed852e2009-09-05 21:47:34 +00003117
3118 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003119 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003120
3121 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003122 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003123
cristye076a6e2010-08-15 19:59:43 +00003124 register PixelPacket
3125 *restrict q;
3126
cristybb503372010-05-27 20:51:26 +00003127 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003128 u,
3129 v;
3130
cristy3ed852e2009-09-05 21:47:34 +00003131 /*
3132 Acquire pixels.
3133 */
cristy3ed852e2009-09-05 21:47:34 +00003134 cache_info=(CacheInfo *) image->cache;
cristy4cfbb3f2010-03-14 20:40:23 +00003135 if (cache_info->type == UndefinedCache)
cristy3ed852e2009-09-05 21:47:34 +00003136 return((const PixelPacket *) NULL);
3137 region.x=x;
3138 region.y=y;
3139 region.width=columns;
3140 region.height=rows;
3141 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
3142 if (pixels == (PixelPacket *) NULL)
3143 return((const PixelPacket *) NULL);
cristydf415c82010-03-11 16:47:50 +00003144 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3145 nexus_info->region.x;
3146 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3147 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003148 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3149 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003150 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3151 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003152 {
3153 MagickBooleanType
3154 status;
3155
3156 /*
3157 Pixel request is inside cache extents.
3158 */
3159 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
3160 return(pixels);
3161 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3162 if (status == MagickFalse)
3163 return((const PixelPacket *) NULL);
3164 if ((cache_info->storage_class == PseudoClass) ||
3165 (cache_info->colorspace == CMYKColorspace))
3166 {
3167 status=ReadPixelCacheIndexes(cache_info,nexus_info,exception);
3168 if (status == MagickFalse)
3169 return((const PixelPacket *) NULL);
3170 }
3171 return(pixels);
3172 }
3173 /*
3174 Pixel request is outside cache extents.
3175 */
3176 q=pixels;
3177 indexes=GetPixelCacheNexusIndexes(cache_info,nexus_info);
3178 virtual_nexus=AcquirePixelCacheNexus(1);
3179 if (virtual_nexus == (NexusInfo **) NULL)
3180 {
3181 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3182 "UnableToGetCacheNexus","`%s'",image->filename);
3183 return((const PixelPacket *) NULL);
3184 }
3185 switch (virtual_pixel_method)
3186 {
3187 case BlackVirtualPixelMethod:
3188 {
cristy4789f0d2010-01-10 00:01:06 +00003189 SetRedPixelComponent(&virtual_pixel,0);
3190 SetGreenPixelComponent(&virtual_pixel,0);
3191 SetBluePixelComponent(&virtual_pixel,0);
3192 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003193 break;
3194 }
3195 case GrayVirtualPixelMethod:
3196 {
cristy4789f0d2010-01-10 00:01:06 +00003197 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3198 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3199 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3200 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003201 break;
3202 }
3203 case TransparentVirtualPixelMethod:
3204 {
cristy4789f0d2010-01-10 00:01:06 +00003205 SetRedPixelComponent(&virtual_pixel,0);
3206 SetGreenPixelComponent(&virtual_pixel,0);
3207 SetBluePixelComponent(&virtual_pixel,0);
3208 SetOpacityPixelComponent(&virtual_pixel,TransparentOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003209 break;
3210 }
3211 case MaskVirtualPixelMethod:
3212 case WhiteVirtualPixelMethod:
3213 {
cristy4789f0d2010-01-10 00:01:06 +00003214 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3215 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3216 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3217 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003218 break;
3219 }
3220 default:
3221 {
3222 virtual_pixel=image->background_color;
3223 break;
3224 }
3225 }
cristyc3ec0d42010-04-07 01:18:08 +00003226 virtual_index=0;
cristybb503372010-05-27 20:51:26 +00003227 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003228 {
cristybb503372010-05-27 20:51:26 +00003229 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003230 {
3231 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003232 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003233 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3234 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003235 {
3236 MagickModulo
3237 x_modulo,
3238 y_modulo;
3239
3240 /*
3241 Transfer a single pixel.
3242 */
3243 length=(MagickSizeType) 1;
3244 switch (virtual_pixel_method)
3245 {
3246 case BackgroundVirtualPixelMethod:
3247 case ConstantVirtualPixelMethod:
3248 case BlackVirtualPixelMethod:
3249 case GrayVirtualPixelMethod:
3250 case TransparentVirtualPixelMethod:
3251 case MaskVirtualPixelMethod:
3252 case WhiteVirtualPixelMethod:
3253 {
3254 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003255 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003256 break;
3257 }
3258 case EdgeVirtualPixelMethod:
3259 default:
3260 {
3261 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003262 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003263 1UL,1UL,virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003264 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3265 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003266 break;
3267 }
3268 case RandomVirtualPixelMethod:
3269 {
3270 if (cache_info->random_info == (RandomInfo *) NULL)
3271 cache_info->random_info=AcquireRandomInfo();
3272 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003273 RandomX(cache_info->random_info,cache_info->columns),
3274 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003275 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003276 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3277 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003278 break;
3279 }
3280 case DitherVirtualPixelMethod:
3281 {
3282 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003283 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003284 1UL,1UL,virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003285 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3286 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003287 break;
3288 }
3289 case TileVirtualPixelMethod:
3290 {
3291 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3292 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3293 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3294 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3295 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003296 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3297 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003298 break;
3299 }
3300 case MirrorVirtualPixelMethod:
3301 {
3302 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3303 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003304 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003305 x_modulo.remainder-1L;
3306 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3307 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003308 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003309 y_modulo.remainder-1L;
3310 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3311 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3312 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 CheckerTileVirtualPixelMethod:
3318 {
3319 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3320 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3321 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3322 {
3323 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003324 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003325 break;
3326 }
3327 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3328 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3329 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003330 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3331 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003332 break;
3333 }
3334 case HorizontalTileVirtualPixelMethod:
3335 {
cristybb503372010-05-27 20:51:26 +00003336 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003337 {
3338 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003339 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003340 break;
3341 }
3342 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3343 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3344 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3345 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3346 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003347 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3348 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003349 break;
3350 }
3351 case VerticalTileVirtualPixelMethod:
3352 {
cristybb503372010-05-27 20:51:26 +00003353 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
cristy3ed852e2009-09-05 21:47:34 +00003354 {
3355 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003356 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003357 break;
3358 }
3359 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3360 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3361 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3362 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3363 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003364 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3365 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003366 break;
3367 }
3368 case HorizontalTileEdgeVirtualPixelMethod:
3369 {
3370 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3371 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003372 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003373 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003374 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3375 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003376 break;
3377 }
3378 case VerticalTileEdgeVirtualPixelMethod:
3379 {
3380 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3381 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003382 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003383 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003384 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3385 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003386 break;
3387 }
3388 }
3389 if (p == (const PixelPacket *) NULL)
3390 break;
3391 *q++=(*p);
cristyc3ec0d42010-04-07 01:18:08 +00003392 if ((indexes != (IndexPacket *) NULL) &&
3393 (virtual_indexes != (const IndexPacket *) NULL))
3394 *indexes++=(*virtual_indexes);
cristy3ed852e2009-09-05 21:47:34 +00003395 continue;
3396 }
3397 /*
3398 Transfer a run of pixels.
3399 */
3400 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,
cristybb503372010-05-27 20:51:26 +00003401 (size_t) length,1UL,virtual_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003402 if (p == (const PixelPacket *) NULL)
3403 break;
cristyc3ec0d42010-04-07 01:18:08 +00003404 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,virtual_nexus[0]);
cristy8f036fe2010-09-18 02:02:00 +00003405 (void) memcpy(q,p,(size_t) length*sizeof(*p));
cristy3ed852e2009-09-05 21:47:34 +00003406 q+=length;
cristyc3ec0d42010-04-07 01:18:08 +00003407 if ((indexes != (IndexPacket *) NULL) &&
3408 (virtual_indexes != (const IndexPacket *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003409 {
cristy8f036fe2010-09-18 02:02:00 +00003410 (void) memcpy(indexes,virtual_indexes,(size_t) length*
cristyc3ec0d42010-04-07 01:18:08 +00003411 sizeof(*virtual_indexes));
3412 indexes+=length;
cristy3ed852e2009-09-05 21:47:34 +00003413 }
3414 }
3415 }
3416 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3417 return(pixels);
3418}
3419
3420/*
3421%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3422% %
3423% %
3424% %
3425+ G e t V i r t u a l P i x e l C a c h e %
3426% %
3427% %
3428% %
3429%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3430%
3431% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3432% cache as defined by the geometry parameters. A pointer to the pixels
3433% is returned if the pixels are transferred, otherwise a NULL is returned.
3434%
3435% The format of the GetVirtualPixelCache() method is:
3436%
3437% const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003438% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3439% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003440% ExceptionInfo *exception)
3441%
3442% A description of each parameter follows:
3443%
3444% o image: the image.
3445%
3446% o virtual_pixel_method: the virtual pixel method.
3447%
3448% o x,y,columns,rows: These values define the perimeter of a region of
3449% pixels.
3450%
3451% o exception: return any errors or warnings in this structure.
3452%
3453*/
3454static const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003455 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3456 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003457{
3458 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003459 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003460
cristy5c9e6f22010-09-17 17:31:01 +00003461 const int
3462 id = GetOpenMPThreadId();
3463
cristy3ed852e2009-09-05 21:47:34 +00003464 cache_info=(CacheInfo *) image->cache;
cristy6ebe97c2010-07-03 01:17:28 +00003465 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003466 return(GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3467 cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00003468}
3469
3470/*
3471%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3472% %
3473% %
3474% %
3475% G e t V i r t u a l P i x e l Q u e u e %
3476% %
3477% %
3478% %
3479%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3480%
3481% GetVirtualPixelQueue() returns the virtual pixels associated with the
3482% last call to QueueAuthenticPixels() or GetVirtualPixels().
3483%
3484% The format of the GetVirtualPixelQueue() method is:
3485%
3486% const PixelPacket *GetVirtualPixelQueue(const Image image)
3487%
3488% A description of each parameter follows:
3489%
3490% o image: the image.
3491%
3492*/
3493MagickExport const PixelPacket *GetVirtualPixelQueue(const Image *image)
3494{
3495 CacheInfo
3496 *cache_info;
3497
3498 assert(image != (const Image *) NULL);
3499 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003500 assert(image->cache != (Cache) NULL);
3501 cache_info=(CacheInfo *) image->cache;
3502 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003503 if (cache_info->methods.get_virtual_pixels_handler !=
3504 (GetVirtualPixelsHandler) NULL)
3505 return(cache_info->methods.get_virtual_pixels_handler(image));
3506 return(GetVirtualPixelsCache(image));
cristy3ed852e2009-09-05 21:47:34 +00003507}
3508
3509/*
3510%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3511% %
3512% %
3513% %
3514% G e t V i r t u a l P i x e l s %
3515% %
3516% %
3517% %
3518%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3519%
3520% GetVirtualPixels() returns an immutable pixel region. If the
3521% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003522% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003523% copy of the pixels or it may point to the original pixels in memory.
3524% Performance is maximized if the selected region is part of one row, or one
3525% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003526% (without a copy) if the image is in memory, or in a memory-mapped file. The
3527% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003528%
3529% Pixels accessed via the returned pointer represent a simple array of type
3530% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
3531% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to access
3532% the black color component or to obtain the colormap indexes (of type
3533% IndexPacket) corresponding to the region.
3534%
3535% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3536%
3537% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3538% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3539% GetCacheViewAuthenticPixels() instead.
3540%
3541% The format of the GetVirtualPixels() method is:
3542%
cristybb503372010-05-27 20:51:26 +00003543% const PixelPacket *GetVirtualPixels(const Image *image,const ssize_t x,
3544% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003545% ExceptionInfo *exception)
3546%
3547% A description of each parameter follows:
3548%
3549% o image: the image.
3550%
3551% o x,y,columns,rows: These values define the perimeter of a region of
3552% pixels.
3553%
3554% o exception: return any errors or warnings in this structure.
3555%
3556*/
3557MagickExport const PixelPacket *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003558 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3559 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003560{
3561 CacheInfo
3562 *cache_info;
3563
cristy3ed852e2009-09-05 21:47:34 +00003564 assert(image != (const Image *) NULL);
3565 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003566 assert(image->cache != (Cache) NULL);
3567 cache_info=(CacheInfo *) image->cache;
3568 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003569 if (cache_info->methods.get_virtual_pixel_handler !=
3570 (GetVirtualPixelHandler) NULL)
3571 return(cache_info->methods.get_virtual_pixel_handler(image,
3572 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3573 return(GetVirtualPixelCache(image,GetPixelCacheVirtualMethod(image),x,y,
3574 columns,rows,exception));
cristy3ed852e2009-09-05 21:47:34 +00003575}
3576
3577/*
3578%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3579% %
3580% %
3581% %
3582+ 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 %
3583% %
3584% %
3585% %
3586%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3587%
3588% GetVirtualPixelsCache() returns the pixels associated with the last call
3589% to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3590%
3591% The format of the GetVirtualPixelsCache() method is:
3592%
3593% PixelPacket *GetVirtualPixelsCache(const Image *image)
3594%
3595% A description of each parameter follows:
3596%
3597% o image: the image.
3598%
3599*/
3600static const PixelPacket *GetVirtualPixelsCache(const Image *image)
3601{
3602 CacheInfo
3603 *cache_info;
3604
cristy5c9e6f22010-09-17 17:31:01 +00003605 const int
3606 id = GetOpenMPThreadId();
3607
cristy3ed852e2009-09-05 21:47:34 +00003608 cache_info=(CacheInfo *) image->cache;
cristy6ebe97c2010-07-03 01:17:28 +00003609 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003610 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003611}
3612
3613/*
3614%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3615% %
3616% %
3617% %
3618+ G e t V i r t u a l P i x e l s N e x u s %
3619% %
3620% %
3621% %
3622%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3623%
3624% GetVirtualPixelsNexus() returns the pixels associated with the specified
3625% cache nexus.
3626%
3627% The format of the GetVirtualPixelsNexus() method is:
3628%
3629% const IndexPacket *GetVirtualPixelsNexus(const Cache cache,
3630% NexusInfo *nexus_info)
3631%
3632% A description of each parameter follows:
3633%
3634% o cache: the pixel cache.
3635%
3636% o nexus_info: the cache nexus to return the colormap pixels.
3637%
3638*/
3639MagickExport const PixelPacket *GetVirtualPixelsNexus(const Cache cache,
3640 NexusInfo *nexus_info)
3641{
3642 CacheInfo
3643 *cache_info;
3644
3645 if (cache == (Cache) NULL)
3646 return((PixelPacket *) NULL);
3647 cache_info=(CacheInfo *) cache;
3648 assert(cache_info->signature == MagickSignature);
3649 if (cache_info->storage_class == UndefinedClass)
3650 return((PixelPacket *) NULL);
3651 return((const PixelPacket *) nexus_info->pixels);
3652}
3653
3654/*
3655%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3656% %
3657% %
3658% %
3659+ M a s k P i x e l C a c h e N e x u s %
3660% %
3661% %
3662% %
3663%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3664%
3665% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3666% The method returns MagickTrue if the pixel region is masked, otherwise
3667% MagickFalse.
3668%
3669% The format of the MaskPixelCacheNexus() method is:
3670%
3671% MagickBooleanType MaskPixelCacheNexus(Image *image,
3672% NexusInfo *nexus_info,ExceptionInfo *exception)
3673%
3674% A description of each parameter follows:
3675%
3676% o image: the image.
3677%
3678% o nexus_info: the cache nexus to clip.
3679%
3680% o exception: return any errors or warnings in this structure.
3681%
3682*/
3683
3684static inline void MagickPixelCompositeMask(const MagickPixelPacket *p,
3685 const MagickRealType alpha,const MagickPixelPacket *q,
3686 const MagickRealType beta,MagickPixelPacket *composite)
3687{
3688 MagickRealType
3689 gamma;
3690
3691 if (alpha == TransparentOpacity)
3692 {
3693 *composite=(*q);
3694 return;
3695 }
3696 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3697 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3698 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3699 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3700 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3701 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3702 composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
3703}
3704
3705static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3706 ExceptionInfo *exception)
3707{
3708 CacheInfo
3709 *cache_info;
3710
3711 MagickPixelPacket
3712 alpha,
3713 beta;
3714
3715 MagickSizeType
3716 number_pixels;
3717
3718 NexusInfo
3719 **clip_nexus,
3720 **image_nexus;
3721
3722 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003723 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003724
3725 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003726 *restrict nexus_indexes,
3727 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003728
cristy3ed852e2009-09-05 21:47:34 +00003729 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003730 *restrict p,
3731 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003732
cristye076a6e2010-08-15 19:59:43 +00003733 register ssize_t
3734 i;
3735
cristy3ed852e2009-09-05 21:47:34 +00003736 /*
3737 Apply clip mask.
3738 */
3739 if (image->debug != MagickFalse)
3740 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3741 if (image->mask == (Image *) NULL)
3742 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +00003743 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00003744 if (cache_info == (Cache) NULL)
3745 return(MagickFalse);
3746 image_nexus=AcquirePixelCacheNexus(1);
3747 clip_nexus=AcquirePixelCacheNexus(1);
3748 if ((image_nexus == (NexusInfo **) NULL) ||
3749 (clip_nexus == (NexusInfo **) NULL))
3750 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy09449f72010-01-23 03:08:36 +00003751 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,
3752 nexus_info->region.y,nexus_info->region.width,nexus_info->region.height,
3753 image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003754 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
3755 q=nexus_info->pixels;
3756 nexus_indexes=nexus_info->indexes;
3757 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3758 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3759 nexus_info->region.height,clip_nexus[0],&image->exception);
3760 GetMagickPixelPacket(image,&alpha);
3761 GetMagickPixelPacket(image,&beta);
3762 number_pixels=(MagickSizeType) nexus_info->region.width*
3763 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +00003764 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +00003765 {
3766 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
3767 break;
3768 SetMagickPixelPacket(image,p,indexes+i,&alpha);
3769 SetMagickPixelPacket(image,q,nexus_indexes+i,&beta);
3770 MagickPixelCompositeMask(&beta,(MagickRealType) PixelIntensityToQuantum(r),
3771 &alpha,alpha.opacity,&beta);
cristyce70c172010-01-07 17:15:30 +00003772 q->red=ClampToQuantum(beta.red);
3773 q->green=ClampToQuantum(beta.green);
3774 q->blue=ClampToQuantum(beta.blue);
3775 q->opacity=ClampToQuantum(beta.opacity);
cristy3ed852e2009-09-05 21:47:34 +00003776 if (cache_info->active_index_channel != MagickFalse)
3777 nexus_indexes[i]=indexes[i];
3778 p++;
3779 q++;
3780 r++;
3781 }
3782 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3783 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +00003784 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003785 return(MagickFalse);
3786 return(MagickTrue);
3787}
3788
3789/*
3790%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3791% %
3792% %
3793% %
3794+ O p e n P i x e l C a c h e %
3795% %
3796% %
3797% %
3798%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3799%
3800% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3801% dimensions, allocating space for the image pixels and optionally the
3802% colormap indexes, and memory mapping the cache if it is disk based. The
3803% cache nexus array is initialized as well.
3804%
3805% The format of the OpenPixelCache() method is:
3806%
3807% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3808% ExceptionInfo *exception)
3809%
3810% A description of each parameter follows:
3811%
3812% o image: the image.
3813%
3814% o mode: ReadMode, WriteMode, or IOMode.
3815%
3816% o exception: return any errors or warnings in this structure.
3817%
3818*/
3819
cristyd43a46b2010-01-21 02:13:41 +00003820static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003821{
3822 cache_info->mapped=MagickFalse;
3823 cache_info->pixels=(PixelPacket *) AcquireMagickMemory((size_t)
3824 cache_info->length);
3825 if (cache_info->pixels == (PixelPacket *) NULL)
3826 {
3827 cache_info->mapped=MagickTrue;
3828 cache_info->pixels=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
3829 cache_info->length);
3830 }
3831}
3832
3833static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3834{
3835 CacheInfo
3836 *cache_info;
3837
3838 MagickOffsetType
3839 count,
3840 extent,
3841 offset;
3842
3843 cache_info=(CacheInfo *) image->cache;
3844 if (image->debug != MagickFalse)
3845 {
3846 char
3847 format[MaxTextExtent],
3848 message[MaxTextExtent];
3849
cristyb9080c92009-12-01 20:13:26 +00003850 (void) FormatMagickSize(length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00003851 (void) FormatMagickString(message,MaxTextExtent,
cristy2ce15c92010-03-12 14:03:41 +00003852 "extend %s (%s[%d], disk, %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003853 cache_info->cache_filename,cache_info->file,format);
3854 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3855 }
3856 if (length != (MagickSizeType) ((MagickOffsetType) length))
3857 return(MagickFalse);
3858 extent=(MagickOffsetType) MagickSeek(cache_info->file,0,SEEK_END);
3859 if (extent < 0)
3860 return(MagickFalse);
3861 if ((MagickSizeType) extent >= length)
3862 return(MagickTrue);
3863 offset=(MagickOffsetType) length-1;
3864 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3865 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3866}
3867
3868static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3869 ExceptionInfo *exception)
3870{
3871 char
3872 format[MaxTextExtent],
3873 message[MaxTextExtent];
3874
3875 CacheInfo
3876 *cache_info,
3877 source_info;
3878
3879 MagickSizeType
3880 length,
3881 number_pixels;
3882
3883 MagickStatusType
3884 status;
3885
3886 size_t
cristye076a6e2010-08-15 19:59:43 +00003887 columns,
cristy3ed852e2009-09-05 21:47:34 +00003888 packet_size;
3889
cristy3ed852e2009-09-05 21:47:34 +00003890 if (image->debug != MagickFalse)
3891 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3892 if ((image->columns == 0) || (image->rows == 0))
3893 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3894 cache_info=(CacheInfo *) image->cache;
3895 source_info=(*cache_info);
3896 source_info.file=(-1);
cristye8c25f92010-06-03 00:53:06 +00003897 (void) FormatMagickString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3898 image->filename,(double) GetImageIndexInList(image));
cristy87528ea2009-09-10 14:53:56 +00003899 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +00003900 cache_info->rows=image->rows;
3901 cache_info->columns=image->columns;
3902 cache_info->active_index_channel=((image->storage_class == PseudoClass) ||
3903 (image->colorspace == CMYKColorspace)) ? MagickTrue : MagickFalse;
cristy73724512010-04-12 14:43:14 +00003904 if (image->ping != MagickFalse)
3905 {
3906 cache_info->storage_class=image->storage_class;
3907 cache_info->colorspace=image->colorspace;
3908 cache_info->type=PingCache;
3909 cache_info->pixels=(PixelPacket *) NULL;
3910 cache_info->indexes=(IndexPacket *) NULL;
3911 cache_info->length=0;
3912 return(MagickTrue);
3913 }
cristy3ed852e2009-09-05 21:47:34 +00003914 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3915 packet_size=sizeof(PixelPacket);
3916 if (cache_info->active_index_channel != MagickFalse)
3917 packet_size+=sizeof(IndexPacket);
3918 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00003919 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00003920 if (cache_info->columns != columns)
3921 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3922 image->filename);
3923 cache_info->length=length;
3924 status=AcquireMagickResource(AreaResource,cache_info->length);
3925 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
3926 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3927 {
3928 status=AcquireMagickResource(MemoryResource,cache_info->length);
3929 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3930 (cache_info->type == MemoryCache))
3931 {
cristyd43a46b2010-01-21 02:13:41 +00003932 AllocatePixelCachePixels(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00003933 if (cache_info->pixels == (PixelPacket *) NULL)
3934 cache_info->pixels=source_info.pixels;
3935 else
3936 {
3937 /*
3938 Create memory pixel cache.
3939 */
3940 if (image->debug != MagickFalse)
3941 {
cristy97e7a572009-12-05 15:07:53 +00003942 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00003943 format);
cristy3ed852e2009-09-05 21:47:34 +00003944 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00003945 "open %s (%s memory, %.20gx%.20g %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003946 cache_info->mapped != MagickFalse ? "anonymous" : "heap",
cristye8c25f92010-06-03 00:53:06 +00003947 (double) cache_info->columns,(double) cache_info->rows,
3948 format);
cristy3ed852e2009-09-05 21:47:34 +00003949 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3950 message);
3951 }
3952 cache_info->storage_class=image->storage_class;
3953 cache_info->colorspace=image->colorspace;
3954 cache_info->type=MemoryCache;
3955 cache_info->indexes=(IndexPacket *) NULL;
3956 if (cache_info->active_index_channel != MagickFalse)
3957 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
3958 number_pixels);
3959 if (source_info.storage_class != UndefinedClass)
3960 {
3961 status|=ClonePixelCachePixels(cache_info,&source_info,
3962 exception);
3963 RelinquishPixelCachePixels(&source_info);
3964 }
3965 return(MagickTrue);
3966 }
3967 }
3968 RelinquishMagickResource(MemoryResource,cache_info->length);
3969 }
3970 /*
3971 Create pixel cache on disk.
3972 */
3973 status=AcquireMagickResource(DiskResource,cache_info->length);
3974 if (status == MagickFalse)
3975 {
3976 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3977 "CacheResourcesExhausted","`%s'",image->filename);
3978 return(MagickFalse);
3979 }
3980 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3981 {
3982 RelinquishMagickResource(DiskResource,cache_info->length);
3983 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3984 image->filename);
3985 return(MagickFalse);
3986 }
3987 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
3988 cache_info->length);
3989 if (status == MagickFalse)
3990 {
3991 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3992 image->filename);
3993 return(MagickFalse);
3994 }
3995 cache_info->storage_class=image->storage_class;
3996 cache_info->colorspace=image->colorspace;
3997 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
3998 status=AcquireMagickResource(AreaResource,cache_info->length);
3999 if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4000 cache_info->type=DiskCache;
4001 else
4002 {
4003 status=AcquireMagickResource(MapResource,cache_info->length);
4004 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4005 (cache_info->type != MemoryCache))
4006 cache_info->type=DiskCache;
4007 else
4008 {
4009 cache_info->pixels=(PixelPacket *) MapBlob(cache_info->file,mode,
4010 cache_info->offset,(size_t) cache_info->length);
4011 if (cache_info->pixels == (PixelPacket *) NULL)
4012 {
4013 cache_info->pixels=source_info.pixels;
4014 cache_info->type=DiskCache;
4015 }
4016 else
4017 {
4018 /*
4019 Create file-backed memory-mapped pixel cache.
4020 */
4021 (void) ClosePixelCacheOnDisk(cache_info);
4022 cache_info->type=MapCache;
4023 cache_info->mapped=MagickTrue;
4024 cache_info->indexes=(IndexPacket *) NULL;
4025 if (cache_info->active_index_channel != MagickFalse)
4026 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4027 number_pixels);
4028 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4029 {
4030 status=ClonePixelCachePixels(cache_info,&source_info,
4031 exception);
4032 RelinquishPixelCachePixels(&source_info);
4033 }
4034 if (image->debug != MagickFalse)
4035 {
cristy97e7a572009-12-05 15:07:53 +00004036 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004037 format);
cristy3ed852e2009-09-05 21:47:34 +00004038 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004039 "open %s (%s[%d], memory-mapped, %.20gx%.20g %sB)",
cristy3ed852e2009-09-05 21:47:34 +00004040 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004041 cache_info->file,(double) cache_info->columns,(double)
4042 cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004043 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4044 message);
4045 }
4046 return(MagickTrue);
4047 }
4048 }
4049 RelinquishMagickResource(MapResource,cache_info->length);
4050 }
4051 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4052 {
4053 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4054 RelinquishPixelCachePixels(&source_info);
4055 }
4056 if (image->debug != MagickFalse)
4057 {
cristyb9080c92009-12-01 20:13:26 +00004058 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00004059 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004060 "open %s (%s[%d], disk, %.20gx%.20g %sB)",cache_info->filename,
4061 cache_info->cache_filename,cache_info->file,(double)
4062 cache_info->columns,(double) cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004063 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4064 }
4065 return(MagickTrue);
4066}
4067
4068/*
4069%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4070% %
4071% %
4072% %
4073+ P e r s i s t P i x e l C a c h e %
4074% %
4075% %
4076% %
4077%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4078%
4079% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4080% persistent pixel cache is one that resides on disk and is not destroyed
4081% when the program exits.
4082%
4083% The format of the PersistPixelCache() method is:
4084%
4085% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4086% const MagickBooleanType attach,MagickOffsetType *offset,
4087% ExceptionInfo *exception)
4088%
4089% A description of each parameter follows:
4090%
4091% o image: the image.
4092%
4093% o filename: the persistent pixel cache filename.
4094%
cristy01b7eb02009-09-10 23:10:14 +00004095% o attach: A value other than zero initializes the persistent pixel
4096% cache.
4097%
cristy3ed852e2009-09-05 21:47:34 +00004098% o initialize: A value other than zero initializes the persistent pixel
4099% cache.
4100%
4101% o offset: the offset in the persistent cache to store pixels.
4102%
4103% o exception: return any errors or warnings in this structure.
4104%
4105*/
4106MagickExport MagickBooleanType PersistPixelCache(Image *image,
4107 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4108 ExceptionInfo *exception)
4109{
4110 CacheInfo
4111 *cache_info,
4112 *clone_info;
4113
4114 Image
4115 clone_image;
4116
cristy3ed852e2009-09-05 21:47:34 +00004117 MagickBooleanType
4118 status;
4119
cristye076a6e2010-08-15 19:59:43 +00004120 ssize_t
4121 page_size;
4122
cristy3ed852e2009-09-05 21:47:34 +00004123 assert(image != (Image *) NULL);
4124 assert(image->signature == MagickSignature);
4125 if (image->debug != MagickFalse)
4126 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4127 assert(image->cache != (void *) NULL);
4128 assert(filename != (const char *) NULL);
4129 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004130 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004131 cache_info=(CacheInfo *) image->cache;
4132 assert(cache_info->signature == MagickSignature);
4133 if (attach != MagickFalse)
4134 {
4135 /*
cristy01b7eb02009-09-10 23:10:14 +00004136 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004137 */
4138 if (image->debug != MagickFalse)
4139 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4140 "attach persistent cache");
4141 (void) CopyMagickString(cache_info->cache_filename,filename,
4142 MaxTextExtent);
4143 cache_info->type=DiskCache;
4144 cache_info->offset=(*offset);
4145 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4146 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004147 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004148 return(MagickTrue);
4149 }
cristy01b7eb02009-09-10 23:10:14 +00004150 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4151 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004152 {
cristyf84a1932010-01-03 18:00:18 +00004153 LockSemaphoreInfo(cache_info->semaphore);
cristy09449f72010-01-23 03:08:36 +00004154 if ((cache_info->mode != ReadMode) &&
4155 (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004156 (cache_info->reference_count == 1))
4157 {
4158 int
4159 status;
4160
4161 /*
cristy01b7eb02009-09-10 23:10:14 +00004162 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004163 */
4164 status=rename(cache_info->cache_filename,filename);
4165 if (status == 0)
4166 {
4167 (void) CopyMagickString(cache_info->cache_filename,filename,
4168 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004169 *offset+=cache_info->length+page_size-(cache_info->length %
4170 page_size);
cristyf84a1932010-01-03 18:00:18 +00004171 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004172 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004173 if (image->debug != MagickFalse)
4174 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4175 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004176 return(MagickTrue);
4177 }
4178 }
cristyf84a1932010-01-03 18:00:18 +00004179 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004180 }
4181 /*
cristy01b7eb02009-09-10 23:10:14 +00004182 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004183 */
4184 clone_image=(*image);
4185 clone_info=(CacheInfo *) clone_image.cache;
4186 image->cache=ClonePixelCache(cache_info);
4187 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4188 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4189 cache_info->type=DiskCache;
4190 cache_info->offset=(*offset);
4191 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004192 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004193 if (status != MagickFalse)
cristyabd6e372010-09-15 19:11:26 +00004194 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
cristy688f07b2009-09-27 15:19:13 +00004195 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004196 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4197 return(status);
4198}
4199
4200/*
4201%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4202% %
4203% %
4204% %
4205+ Q u e u e A u t h e n t i c N e x u s %
4206% %
4207% %
4208% %
4209%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4210%
4211% QueueAuthenticNexus() allocates an region to store image pixels as defined
4212% by the region rectangle and returns a pointer to the region. This region is
4213% subsequently transferred from the pixel cache with
4214% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4215% pixels are transferred, otherwise a NULL is returned.
4216%
4217% The format of the QueueAuthenticNexus() method is:
4218%
cristy5f959472010-05-27 22:19:46 +00004219% PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
4220% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004221% NexusInfo *nexus_info,ExceptionInfo *exception)
4222%
4223% A description of each parameter follows:
4224%
4225% o image: the image.
4226%
4227% o x,y,columns,rows: These values define the perimeter of a region of
4228% pixels.
4229%
4230% o nexus_info: the cache nexus to set.
4231%
4232% o exception: return any errors or warnings in this structure.
4233%
4234*/
cristybb503372010-05-27 20:51:26 +00004235MagickExport PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy30097232010-07-01 02:16:30 +00004236 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
4237 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004238{
4239 CacheInfo
4240 *cache_info;
4241
4242 MagickOffsetType
4243 offset;
4244
4245 MagickSizeType
4246 number_pixels;
4247
4248 RectangleInfo
4249 region;
4250
4251 /*
4252 Validate pixel cache geometry.
4253 */
cristy77ff0282010-09-13 00:51:10 +00004254 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
4255 if (cache_info == (Cache) NULL)
4256 return((PixelPacket *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004257 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4258 {
4259 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4260 "NoPixelsDefinedInCache","`%s'",image->filename);
4261 return((PixelPacket *) NULL);
4262 }
cristybb503372010-05-27 20:51:26 +00004263 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4264 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004265 {
4266 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4267 "PixelsAreNotAuthentic","`%s'",image->filename);
4268 return((PixelPacket *) NULL);
4269 }
4270 offset=(MagickOffsetType) y*cache_info->columns+x;
4271 if (offset < 0)
4272 return((PixelPacket *) NULL);
4273 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4274 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4275 if ((MagickSizeType) offset >= number_pixels)
4276 return((PixelPacket *) NULL);
4277 /*
4278 Return pixel cache.
4279 */
4280 region.x=x;
4281 region.y=y;
4282 region.width=columns;
4283 region.height=rows;
4284 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4285}
4286
4287/*
4288%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4289% %
4290% %
4291% %
4292+ 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 %
4293% %
4294% %
4295% %
4296%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4297%
4298% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4299% defined by the region rectangle and returns a pointer to the region. This
4300% region is subsequently transferred from the pixel cache with
4301% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4302% pixels are transferred, otherwise a NULL is returned.
4303%
4304% The format of the QueueAuthenticPixelsCache() method is:
4305%
cristybb503372010-05-27 20:51:26 +00004306% PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4307% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004308% ExceptionInfo *exception)
4309%
4310% A description of each parameter follows:
4311%
4312% o image: the image.
4313%
4314% o x,y,columns,rows: These values define the perimeter of a region of
4315% pixels.
4316%
4317% o exception: return any errors or warnings in this structure.
4318%
4319*/
cristybb503372010-05-27 20:51:26 +00004320static PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4321 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004322 ExceptionInfo *exception)
4323{
4324 CacheInfo
4325 *cache_info;
4326
cristy5c9e6f22010-09-17 17:31:01 +00004327 const int
4328 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004329
cristy77ff0282010-09-13 00:51:10 +00004330 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00004331 if (cache_info == (Cache) NULL)
4332 return((PixelPacket *) NULL);
cristy6ebe97c2010-07-03 01:17:28 +00004333 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00004334 return(QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4335 exception));
cristy3ed852e2009-09-05 21:47:34 +00004336}
4337
4338/*
4339%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4340% %
4341% %
4342% %
4343% Q u e u e A u t h e n t i c P i x e l s %
4344% %
4345% %
4346% %
4347%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4348%
4349% QueueAuthenticPixels() queues a mutable pixel region. If the region is
4350% successfully intialized a pointer to a PixelPacket array representing the
4351% region is returned, otherwise NULL is returned. The returned pointer may
4352% point to a temporary working buffer for the pixels or it may point to the
4353% final location of the pixels in memory.
4354%
4355% Write-only access means that any existing pixel values corresponding to
4356% the region are ignored. This is useful if the initial image is being
4357% created from scratch, or if the existing pixel values are to be
4358% completely replaced without need to refer to their pre-existing values.
4359% The application is free to read and write the pixel buffer returned by
4360% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4361% initialize the pixel array values. Initializing pixel array values is the
4362% application's responsibility.
4363%
4364% Performance is maximized if the selected region is part of one row, or
4365% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004366% pixels in-place (without a copy) if the image is in memory, or in a
4367% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004368% by the user.
4369%
4370% Pixels accessed via the returned pointer represent a simple array of type
4371% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
4372% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
4373% the black color component or the colormap indexes (of type IndexPacket)
4374% corresponding to the region. Once the PixelPacket (and/or IndexPacket)
4375% array has been updated, the changes must be saved back to the underlying
4376% image using SyncAuthenticPixels() or they may be lost.
4377%
4378% The format of the QueueAuthenticPixels() method is:
4379%
cristy5f959472010-05-27 22:19:46 +00004380% PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4381% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004382% ExceptionInfo *exception)
4383%
4384% A description of each parameter follows:
4385%
4386% o image: the image.
4387%
4388% o x,y,columns,rows: These values define the perimeter of a region of
4389% pixels.
4390%
4391% o exception: return any errors or warnings in this structure.
4392%
4393*/
cristybb503372010-05-27 20:51:26 +00004394MagickExport PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4395 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004396 ExceptionInfo *exception)
4397{
4398 CacheInfo
4399 *cache_info;
4400
cristy3ed852e2009-09-05 21:47:34 +00004401 assert(image != (Image *) NULL);
4402 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004403 assert(image->cache != (Cache) NULL);
4404 cache_info=(CacheInfo *) image->cache;
4405 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004406 if (cache_info->methods.queue_authentic_pixels_handler !=
4407 (QueueAuthenticPixelsHandler) NULL)
4408 return(cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4409 rows,exception));
4410 return(QueueAuthenticPixelsCache(image,x,y,columns,rows,exception));
cristy3ed852e2009-09-05 21:47:34 +00004411}
4412
4413/*
4414%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4415% %
4416% %
4417% %
4418+ R e a d P i x e l C a c h e I n d e x e s %
4419% %
4420% %
4421% %
4422%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4423%
4424% ReadPixelCacheIndexes() reads colormap indexes from the specified region of
4425% the pixel cache.
4426%
4427% The format of the ReadPixelCacheIndexes() method is:
4428%
4429% MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4430% NexusInfo *nexus_info,ExceptionInfo *exception)
4431%
4432% A description of each parameter follows:
4433%
4434% o cache_info: the pixel cache.
4435%
4436% o nexus_info: the cache nexus to read the colormap indexes.
4437%
4438% o exception: return any errors or warnings in this structure.
4439%
4440*/
4441static MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4442 NexusInfo *nexus_info,ExceptionInfo *exception)
4443{
4444 MagickOffsetType
4445 count,
4446 offset;
4447
4448 MagickSizeType
4449 length,
4450 number_pixels;
4451
4452 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004453 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004454
cristybb503372010-05-27 20:51:26 +00004455 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004456 y;
4457
cristybb503372010-05-27 20:51:26 +00004458 size_t
cristy3ed852e2009-09-05 21:47:34 +00004459 rows;
4460
cristy3ed852e2009-09-05 21:47:34 +00004461 if (cache_info->active_index_channel == MagickFalse)
4462 return(MagickFalse);
4463 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4464 return(MagickTrue);
4465 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4466 nexus_info->region.x;
4467 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
4468 rows=nexus_info->region.height;
4469 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004470 q=nexus_info->indexes;
4471 switch (cache_info->type)
4472 {
4473 case MemoryCache:
4474 case MapCache:
4475 {
4476 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004477 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004478
4479 /*
4480 Read indexes from memory.
4481 */
cristydd341db2010-03-04 19:06:38 +00004482 if ((cache_info->columns == nexus_info->region.width) &&
4483 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4484 {
4485 length=number_pixels;
4486 rows=1UL;
4487 }
cristy3ed852e2009-09-05 21:47:34 +00004488 p=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00004489 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004490 {
cristy8f036fe2010-09-18 02:02:00 +00004491 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00004492 p+=cache_info->columns;
4493 q+=nexus_info->region.width;
4494 }
4495 break;
4496 }
4497 case DiskCache:
4498 {
4499 /*
4500 Read indexes from disk.
4501 */
4502 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4503 {
4504 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4505 cache_info->cache_filename);
4506 return(MagickFalse);
4507 }
cristydd341db2010-03-04 19:06:38 +00004508 if ((cache_info->columns == nexus_info->region.width) &&
4509 (number_pixels < MagickMaxBufferExtent))
4510 {
4511 length=number_pixels;
4512 rows=1UL;
4513 }
cristy3ed852e2009-09-05 21:47:34 +00004514 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004515 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004516 {
4517 count=ReadPixelCacheRegion(cache_info,cache_info->offset+number_pixels*
4518 sizeof(PixelPacket)+offset*sizeof(*q),length,(unsigned char *) q);
4519 if ((MagickSizeType) count < length)
4520 break;
4521 offset+=cache_info->columns;
4522 q+=nexus_info->region.width;
4523 }
cristybb503372010-05-27 20:51:26 +00004524 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004525 {
4526 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4527 cache_info->cache_filename);
4528 return(MagickFalse);
4529 }
4530 break;
4531 }
4532 default:
4533 break;
4534 }
4535 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004536 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004537 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004538 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004539 nexus_info->region.width,(double) nexus_info->region.height,(double)
4540 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004541 return(MagickTrue);
4542}
4543
4544/*
4545%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4546% %
4547% %
4548% %
4549+ R e a d P i x e l C a c h e P i x e l s %
4550% %
4551% %
4552% %
4553%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4554%
4555% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4556% cache.
4557%
4558% The format of the ReadPixelCachePixels() method is:
4559%
4560% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4561% NexusInfo *nexus_info,ExceptionInfo *exception)
4562%
4563% A description of each parameter follows:
4564%
4565% o cache_info: the pixel cache.
4566%
4567% o nexus_info: the cache nexus to read the pixels.
4568%
4569% o exception: return any errors or warnings in this structure.
4570%
4571*/
4572static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4573 NexusInfo *nexus_info,ExceptionInfo *exception)
4574{
4575 MagickOffsetType
4576 count,
4577 offset;
4578
4579 MagickSizeType
4580 length,
4581 number_pixels;
4582
cristy3ed852e2009-09-05 21:47:34 +00004583 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004584 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004585
cristye076a6e2010-08-15 19:59:43 +00004586 register ssize_t
4587 y;
4588
cristybb503372010-05-27 20:51:26 +00004589 size_t
cristy3ed852e2009-09-05 21:47:34 +00004590 rows;
4591
cristy3ed852e2009-09-05 21:47:34 +00004592 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4593 return(MagickTrue);
4594 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4595 nexus_info->region.x;
4596 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
4597 rows=nexus_info->region.height;
4598 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004599 q=nexus_info->pixels;
4600 switch (cache_info->type)
4601 {
4602 case MemoryCache:
4603 case MapCache:
4604 {
4605 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004606 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004607
4608 /*
4609 Read pixels from memory.
4610 */
cristydd341db2010-03-04 19:06:38 +00004611 if ((cache_info->columns == nexus_info->region.width) &&
4612 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4613 {
4614 length=number_pixels;
4615 rows=1UL;
4616 }
cristy3ed852e2009-09-05 21:47:34 +00004617 p=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00004618 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004619 {
cristy8f036fe2010-09-18 02:02:00 +00004620 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00004621 p+=cache_info->columns;
4622 q+=nexus_info->region.width;
4623 }
4624 break;
4625 }
4626 case DiskCache:
4627 {
4628 /*
4629 Read pixels from disk.
4630 */
4631 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4632 {
4633 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4634 cache_info->cache_filename);
4635 return(MagickFalse);
4636 }
cristydd341db2010-03-04 19:06:38 +00004637 if ((cache_info->columns == nexus_info->region.width) &&
4638 (number_pixels < MagickMaxBufferExtent))
4639 {
4640 length=number_pixels;
4641 rows=1UL;
4642 }
cristybb503372010-05-27 20:51:26 +00004643 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004644 {
4645 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4646 sizeof(*q),length,(unsigned char *) q);
4647 if ((MagickSizeType) count < length)
4648 break;
4649 offset+=cache_info->columns;
4650 q+=nexus_info->region.width;
4651 }
cristybb503372010-05-27 20:51:26 +00004652 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004653 {
4654 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4655 cache_info->cache_filename);
4656 return(MagickFalse);
4657 }
4658 break;
4659 }
4660 default:
4661 break;
4662 }
4663 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004664 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004665 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004666 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004667 nexus_info->region.width,(double) nexus_info->region.height,(double)
4668 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004669 return(MagickTrue);
4670}
4671
4672/*
4673%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4674% %
4675% %
4676% %
4677+ R e f e r e n c e P i x e l C a c h e %
4678% %
4679% %
4680% %
4681%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4682%
4683% ReferencePixelCache() increments the reference count associated with the
4684% pixel cache returning a pointer to the cache.
4685%
4686% The format of the ReferencePixelCache method is:
4687%
4688% Cache ReferencePixelCache(Cache cache_info)
4689%
4690% A description of each parameter follows:
4691%
4692% o cache_info: the pixel cache.
4693%
4694*/
4695MagickExport Cache ReferencePixelCache(Cache cache)
4696{
4697 CacheInfo
4698 *cache_info;
4699
4700 assert(cache != (Cache *) NULL);
4701 cache_info=(CacheInfo *) cache;
4702 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004703 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004704 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004705 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004706 return(cache_info);
4707}
4708
4709/*
4710%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4711% %
4712% %
4713% %
4714+ S e t P i x e l C a c h e M e t h o d s %
4715% %
4716% %
4717% %
4718%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4719%
4720% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4721%
4722% The format of the SetPixelCacheMethods() method is:
4723%
4724% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4725%
4726% A description of each parameter follows:
4727%
4728% o cache: the pixel cache.
4729%
4730% o cache_methods: Specifies a pointer to a CacheMethods structure.
4731%
4732*/
4733MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4734{
4735 CacheInfo
4736 *cache_info;
4737
4738 GetOneAuthenticPixelFromHandler
4739 get_one_authentic_pixel_from_handler;
4740
4741 GetOneVirtualPixelFromHandler
4742 get_one_virtual_pixel_from_handler;
4743
4744 /*
4745 Set cache pixel methods.
4746 */
4747 assert(cache != (Cache) NULL);
4748 assert(cache_methods != (CacheMethods *) NULL);
4749 cache_info=(CacheInfo *) cache;
4750 assert(cache_info->signature == MagickSignature);
4751 if (cache_info->debug != MagickFalse)
4752 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4753 cache_info->filename);
4754 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4755 cache_info->methods.get_virtual_pixel_handler=
4756 cache_methods->get_virtual_pixel_handler;
4757 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4758 cache_info->methods.destroy_pixel_handler=
4759 cache_methods->destroy_pixel_handler;
4760 if (cache_methods->get_virtual_indexes_from_handler !=
4761 (GetVirtualIndexesFromHandler) NULL)
4762 cache_info->methods.get_virtual_indexes_from_handler=
4763 cache_methods->get_virtual_indexes_from_handler;
4764 if (cache_methods->get_authentic_pixels_handler !=
4765 (GetAuthenticPixelsHandler) NULL)
4766 cache_info->methods.get_authentic_pixels_handler=
4767 cache_methods->get_authentic_pixels_handler;
4768 if (cache_methods->queue_authentic_pixels_handler !=
4769 (QueueAuthenticPixelsHandler) NULL)
4770 cache_info->methods.queue_authentic_pixels_handler=
4771 cache_methods->queue_authentic_pixels_handler;
4772 if (cache_methods->sync_authentic_pixels_handler !=
4773 (SyncAuthenticPixelsHandler) NULL)
4774 cache_info->methods.sync_authentic_pixels_handler=
4775 cache_methods->sync_authentic_pixels_handler;
4776 if (cache_methods->get_authentic_pixels_from_handler !=
4777 (GetAuthenticPixelsFromHandler) NULL)
4778 cache_info->methods.get_authentic_pixels_from_handler=
4779 cache_methods->get_authentic_pixels_from_handler;
4780 if (cache_methods->get_authentic_indexes_from_handler !=
4781 (GetAuthenticIndexesFromHandler) NULL)
4782 cache_info->methods.get_authentic_indexes_from_handler=
4783 cache_methods->get_authentic_indexes_from_handler;
4784 get_one_virtual_pixel_from_handler=
4785 cache_info->methods.get_one_virtual_pixel_from_handler;
4786 if (get_one_virtual_pixel_from_handler !=
4787 (GetOneVirtualPixelFromHandler) NULL)
4788 cache_info->methods.get_one_virtual_pixel_from_handler=
4789 cache_methods->get_one_virtual_pixel_from_handler;
4790 get_one_authentic_pixel_from_handler=
4791 cache_methods->get_one_authentic_pixel_from_handler;
4792 if (get_one_authentic_pixel_from_handler !=
4793 (GetOneAuthenticPixelFromHandler) NULL)
4794 cache_info->methods.get_one_authentic_pixel_from_handler=
4795 cache_methods->get_one_authentic_pixel_from_handler;
4796}
4797
4798/*
4799%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4800% %
4801% %
4802% %
4803+ S e t P i x e l C a c h e N e x u s P i x e l s %
4804% %
4805% %
4806% %
4807%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4808%
4809% SetPixelCacheNexusPixels() defines the region of the cache for the
4810% specified cache nexus.
4811%
4812% The format of the SetPixelCacheNexusPixels() method is:
4813%
4814% PixelPacket SetPixelCacheNexusPixels(const Image *image,
4815% const RectangleInfo *region,NexusInfo *nexus_info,
4816% ExceptionInfo *exception)
4817%
4818% A description of each parameter follows:
4819%
4820% o image: the image.
4821%
4822% o region: A pointer to the RectangleInfo structure that defines the
4823% region of this particular cache nexus.
4824%
4825% o nexus_info: the cache nexus to set.
4826%
4827% o exception: return any errors or warnings in this structure.
4828%
4829*/
cristyabd6e372010-09-15 19:11:26 +00004830
4831static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4832 NexusInfo *nexus_info,ExceptionInfo *exception)
4833{
4834 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4835 return(MagickFalse);
4836 nexus_info->mapped=MagickFalse;
4837 nexus_info->cache=(PixelPacket *) AcquireMagickMemory((size_t)
4838 nexus_info->length);
4839 if (nexus_info->cache == (PixelPacket *) NULL)
4840 {
4841 nexus_info->mapped=MagickTrue;
4842 nexus_info->cache=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
4843 nexus_info->length);
4844 }
4845 if (nexus_info->cache == (PixelPacket *) NULL)
4846 {
4847 (void) ThrowMagickException(exception,GetMagickModule(),
4848 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4849 cache_info->filename);
4850 return(MagickFalse);
4851 }
4852 return(MagickTrue);
4853}
4854
cristy3ed852e2009-09-05 21:47:34 +00004855static PixelPacket *SetPixelCacheNexusPixels(const Image *image,
4856 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4857{
4858 CacheInfo
4859 *cache_info;
4860
4861 MagickBooleanType
4862 status;
4863
cristy3ed852e2009-09-05 21:47:34 +00004864 MagickSizeType
4865 length,
4866 number_pixels;
4867
cristy3ed852e2009-09-05 21:47:34 +00004868 cache_info=(CacheInfo *) image->cache;
4869 assert(cache_info->signature == MagickSignature);
4870 if (cache_info->type == UndefinedCache)
4871 return((PixelPacket *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00004872 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00004873 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
4874 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00004875 {
cristybb503372010-05-27 20:51:26 +00004876 ssize_t
cristybad067a2010-02-15 17:20:55 +00004877 x,
4878 y;
cristy3ed852e2009-09-05 21:47:34 +00004879
cristyeaedf062010-05-29 22:36:02 +00004880 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4881 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00004882 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4883 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00004884 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00004885 ((nexus_info->region.width == cache_info->columns) ||
4886 ((nexus_info->region.width % cache_info->columns) == 0)))))
4887 {
4888 MagickOffsetType
4889 offset;
4890
4891 /*
4892 Pixels are accessed directly from memory.
4893 */
4894 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4895 nexus_info->region.x;
4896 nexus_info->pixels=cache_info->pixels+offset;
4897 nexus_info->indexes=(IndexPacket *) NULL;
4898 if (cache_info->active_index_channel != MagickFalse)
4899 nexus_info->indexes=cache_info->indexes+offset;
4900 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00004901 }
4902 }
4903 /*
4904 Pixels are stored in a cache region until they are synced to the cache.
4905 */
4906 number_pixels=(MagickSizeType) nexus_info->region.width*
4907 nexus_info->region.height;
4908 length=number_pixels*sizeof(PixelPacket);
4909 if (cache_info->active_index_channel != MagickFalse)
4910 length+=number_pixels*sizeof(IndexPacket);
4911 if (nexus_info->cache == (PixelPacket *) NULL)
4912 {
4913 nexus_info->length=length;
4914 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4915 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004916 {
4917 nexus_info->length=0;
4918 return((PixelPacket *) NULL);
4919 }
cristy3ed852e2009-09-05 21:47:34 +00004920 }
4921 else
4922 if (nexus_info->length != length)
4923 {
4924 RelinquishCacheNexusPixels(nexus_info);
4925 nexus_info->length=length;
4926 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4927 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004928 {
4929 nexus_info->length=0;
4930 return((PixelPacket *) NULL);
4931 }
cristy3ed852e2009-09-05 21:47:34 +00004932 }
4933 nexus_info->pixels=nexus_info->cache;
4934 nexus_info->indexes=(IndexPacket *) NULL;
4935 if (cache_info->active_index_channel != MagickFalse)
4936 nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
4937 return(nexus_info->pixels);
4938}
4939
4940/*
4941%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4942% %
4943% %
4944% %
4945% 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 %
4946% %
4947% %
4948% %
4949%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4950%
4951% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4952% pixel cache and returns the previous setting. A virtual pixel is any pixel
4953% access that is outside the boundaries of the image cache.
4954%
4955% The format of the SetPixelCacheVirtualMethod() method is:
4956%
4957% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
4958% const VirtualPixelMethod virtual_pixel_method)
4959%
4960% A description of each parameter follows:
4961%
4962% o image: the image.
4963%
4964% o virtual_pixel_method: choose the type of virtual pixel.
4965%
4966*/
4967MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
4968 const VirtualPixelMethod virtual_pixel_method)
4969{
4970 CacheInfo
4971 *cache_info;
4972
4973 VirtualPixelMethod
4974 method;
4975
4976 assert(image != (Image *) NULL);
4977 assert(image->signature == MagickSignature);
4978 if (image->debug != MagickFalse)
4979 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4980 assert(image->cache != (Cache) NULL);
4981 cache_info=(CacheInfo *) image->cache;
4982 assert(cache_info->signature == MagickSignature);
4983 method=cache_info->virtual_pixel_method;
4984 cache_info->virtual_pixel_method=virtual_pixel_method;
4985 return(method);
4986}
4987
4988/*
4989%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4990% %
4991% %
4992% %
4993+ 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 %
4994% %
4995% %
4996% %
4997%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4998%
4999% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5000% in-memory or disk cache. The method returns MagickTrue if the pixel region
5001% is synced, otherwise MagickFalse.
5002%
5003% The format of the SyncAuthenticPixelCacheNexus() method is:
5004%
5005% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5006% NexusInfo *nexus_info,ExceptionInfo *exception)
5007%
5008% A description of each parameter follows:
5009%
5010% o image: the image.
5011%
5012% o nexus_info: the cache nexus to sync.
5013%
5014% o exception: return any errors or warnings in this structure.
5015%
5016*/
5017MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5018 NexusInfo *nexus_info,ExceptionInfo *exception)
5019{
5020 CacheInfo
5021 *cache_info;
5022
5023 MagickBooleanType
5024 status;
5025
5026 /*
5027 Transfer pixels to the cache.
5028 */
5029 assert(image != (Image *) NULL);
5030 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005031 if (image->cache == (Cache) NULL)
5032 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5033 cache_info=(CacheInfo *) image->cache;
5034 if (cache_info->type == UndefinedCache)
5035 return(MagickFalse);
5036 if ((image->clip_mask != (Image *) NULL) &&
5037 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5038 return(MagickFalse);
5039 if ((image->mask != (Image *) NULL) &&
5040 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5041 return(MagickFalse);
5042 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5043 return(MagickTrue);
5044 assert(cache_info->signature == MagickSignature);
5045 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5046 if ((cache_info->active_index_channel != MagickFalse) &&
5047 (WritePixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse))
5048 return(MagickFalse);
5049 return(status);
5050}
5051
5052/*
5053%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5054% %
5055% %
5056% %
5057+ S y n c A u t h e n t i c P i x e l C a c h e %
5058% %
5059% %
5060% %
5061%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5062%
5063% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5064% or disk cache. The method returns MagickTrue if the pixel region is synced,
5065% otherwise MagickFalse.
5066%
5067% The format of the SyncAuthenticPixelsCache() method is:
5068%
5069% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5070% ExceptionInfo *exception)
5071%
5072% A description of each parameter follows:
5073%
5074% o image: the image.
5075%
5076% o exception: return any errors or warnings in this structure.
5077%
5078*/
5079static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5080 ExceptionInfo *exception)
5081{
5082 CacheInfo
5083 *cache_info;
5084
cristy5c9e6f22010-09-17 17:31:01 +00005085 const int
5086 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005087
cristy3ed852e2009-09-05 21:47:34 +00005088 cache_info=(CacheInfo *) image->cache;
cristy6ebe97c2010-07-03 01:17:28 +00005089 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00005090 return(SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5091 exception));
cristy3ed852e2009-09-05 21:47:34 +00005092}
5093
5094/*
5095%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5096% %
5097% %
5098% %
5099% S y n c A u t h e n t i c P i x e l s %
5100% %
5101% %
5102% %
5103%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5104%
5105% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5106% The method returns MagickTrue if the pixel region is flushed, otherwise
5107% MagickFalse.
5108%
5109% The format of the SyncAuthenticPixels() method is:
5110%
5111% MagickBooleanType SyncAuthenticPixels(Image *image,
5112% ExceptionInfo *exception)
5113%
5114% A description of each parameter follows:
5115%
5116% o image: the image.
5117%
5118% o exception: return any errors or warnings in this structure.
5119%
5120*/
5121MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5122 ExceptionInfo *exception)
5123{
5124 CacheInfo
5125 *cache_info;
5126
5127 assert(image != (Image *) NULL);
5128 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005129 assert(image->cache != (Cache) NULL);
5130 cache_info=(CacheInfo *) image->cache;
5131 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005132 if (cache_info->methods.sync_authentic_pixels_handler !=
5133 (SyncAuthenticPixelsHandler) NULL)
5134 return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
5135 return(SyncAuthenticPixelsCache(image,exception));
cristy3ed852e2009-09-05 21:47:34 +00005136}
5137
5138/*
5139%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5140% %
5141% %
5142% %
5143+ W r i t e P i x e l C a c h e I n d e x e s %
5144% %
5145% %
5146% %
5147%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5148%
5149% WritePixelCacheIndexes() writes the colormap indexes to the specified
5150% region of the pixel cache.
5151%
5152% The format of the WritePixelCacheIndexes() method is:
5153%
5154% MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5155% NexusInfo *nexus_info,ExceptionInfo *exception)
5156%
5157% A description of each parameter follows:
5158%
5159% o cache_info: the pixel cache.
5160%
5161% o nexus_info: the cache nexus to write the colormap indexes.
5162%
5163% o exception: return any errors or warnings in this structure.
5164%
5165*/
5166static MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5167 NexusInfo *nexus_info,ExceptionInfo *exception)
5168{
5169 MagickOffsetType
5170 count,
5171 offset;
5172
5173 MagickSizeType
5174 length,
5175 number_pixels;
5176
5177 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005178 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005179
cristybb503372010-05-27 20:51:26 +00005180 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005181 y;
5182
cristybb503372010-05-27 20:51:26 +00005183 size_t
cristy3ed852e2009-09-05 21:47:34 +00005184 rows;
5185
cristy3ed852e2009-09-05 21:47:34 +00005186 if (cache_info->active_index_channel == MagickFalse)
5187 return(MagickFalse);
5188 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5189 return(MagickTrue);
5190 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5191 nexus_info->region.x;
5192 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
5193 rows=nexus_info->region.height;
5194 number_pixels=(MagickSizeType) length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005195 p=nexus_info->indexes;
5196 switch (cache_info->type)
5197 {
5198 case MemoryCache:
5199 case MapCache:
5200 {
5201 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005202 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005203
5204 /*
5205 Write indexes to memory.
5206 */
cristydd341db2010-03-04 19:06:38 +00005207 if ((cache_info->columns == nexus_info->region.width) &&
5208 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5209 {
5210 length=number_pixels;
5211 rows=1UL;
5212 }
cristy3ed852e2009-09-05 21:47:34 +00005213 q=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00005214 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005215 {
cristy8f036fe2010-09-18 02:02:00 +00005216 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00005217 p+=nexus_info->region.width;
5218 q+=cache_info->columns;
5219 }
5220 break;
5221 }
5222 case DiskCache:
5223 {
5224 /*
5225 Write indexes to disk.
5226 */
5227 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5228 {
5229 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5230 cache_info->cache_filename);
5231 return(MagickFalse);
5232 }
cristydd341db2010-03-04 19:06:38 +00005233 if ((cache_info->columns == nexus_info->region.width) &&
5234 (number_pixels < MagickMaxBufferExtent))
5235 {
5236 length=number_pixels;
5237 rows=1UL;
5238 }
cristy3ed852e2009-09-05 21:47:34 +00005239 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005240 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005241 {
5242 count=WritePixelCacheRegion(cache_info,cache_info->offset+number_pixels*
5243 sizeof(PixelPacket)+offset*sizeof(*p),length,
5244 (const unsigned char *) p);
5245 if ((MagickSizeType) count < length)
5246 break;
5247 p+=nexus_info->region.width;
5248 offset+=cache_info->columns;
5249 }
cristybb503372010-05-27 20:51:26 +00005250 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005251 {
5252 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5253 cache_info->cache_filename);
5254 return(MagickFalse);
5255 }
5256 break;
5257 }
5258 default:
5259 break;
5260 }
5261 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005262 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005263 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005264 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005265 nexus_info->region.width,(double) nexus_info->region.height,(double)
5266 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005267 return(MagickTrue);
5268}
5269
5270/*
5271%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5272% %
5273% %
5274% %
5275+ W r i t e C a c h e P i x e l s %
5276% %
5277% %
5278% %
5279%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5280%
5281% WritePixelCachePixels() writes image pixels to the specified region of the
5282% pixel cache.
5283%
5284% The format of the WritePixelCachePixels() method is:
5285%
5286% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5287% NexusInfo *nexus_info,ExceptionInfo *exception)
5288%
5289% A description of each parameter follows:
5290%
5291% o cache_info: the pixel cache.
5292%
5293% o nexus_info: the cache nexus to write the pixels.
5294%
5295% o exception: return any errors or warnings in this structure.
5296%
5297*/
5298static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5299 NexusInfo *nexus_info,ExceptionInfo *exception)
5300{
5301 MagickOffsetType
5302 count,
5303 offset;
5304
5305 MagickSizeType
5306 length,
5307 number_pixels;
5308
cristy3ed852e2009-09-05 21:47:34 +00005309 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005310 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005311
cristybb503372010-05-27 20:51:26 +00005312 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005313 y;
5314
cristybb503372010-05-27 20:51:26 +00005315 size_t
cristy3ed852e2009-09-05 21:47:34 +00005316 rows;
5317
cristy3ed852e2009-09-05 21:47:34 +00005318 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5319 return(MagickTrue);
5320 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5321 nexus_info->region.x;
5322 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
5323 rows=nexus_info->region.height;
5324 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005325 p=nexus_info->pixels;
5326 switch (cache_info->type)
5327 {
5328 case MemoryCache:
5329 case MapCache:
5330 {
5331 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005332 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005333
5334 /*
5335 Write pixels to memory.
5336 */
cristydd341db2010-03-04 19:06:38 +00005337 if ((cache_info->columns == nexus_info->region.width) &&
5338 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5339 {
5340 length=number_pixels;
5341 rows=1UL;
5342 }
cristy3ed852e2009-09-05 21:47:34 +00005343 q=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00005344 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005345 {
cristy8f036fe2010-09-18 02:02:00 +00005346 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00005347 p+=nexus_info->region.width;
5348 q+=cache_info->columns;
5349 }
5350 break;
5351 }
5352 case DiskCache:
5353 {
5354 /*
5355 Write pixels to disk.
5356 */
5357 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5358 {
5359 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5360 cache_info->cache_filename);
5361 return(MagickFalse);
5362 }
cristydd341db2010-03-04 19:06:38 +00005363 if ((cache_info->columns == nexus_info->region.width) &&
5364 (number_pixels < MagickMaxBufferExtent))
5365 {
5366 length=number_pixels;
5367 rows=1UL;
5368 }
cristybb503372010-05-27 20:51:26 +00005369 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005370 {
5371 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5372 sizeof(*p),length,(const unsigned char *) p);
5373 if ((MagickSizeType) count < length)
5374 break;
5375 p+=nexus_info->region.width;
5376 offset+=cache_info->columns;
5377 }
cristybb503372010-05-27 20:51:26 +00005378 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005379 {
5380 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5381 cache_info->cache_filename);
5382 return(MagickFalse);
5383 }
5384 break;
5385 }
5386 default:
5387 break;
5388 }
5389 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005390 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005391 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005392 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005393 nexus_info->region.width,(double) nexus_info->region.height,(double)
5394 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005395 return(MagickTrue);
5396}