blob: b28064d7feaf968bd5c353c633e272c20156c715 [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"
59#include "magick/quantum.h"
60#include "magick/random_.h"
61#include "magick/resource_.h"
62#include "magick/semaphore.h"
63#include "magick/splay-tree.h"
64#include "magick/string_.h"
65#include "magick/thread-private.h"
66#include "magick/utility.h"
67#if defined(MAGICKCORE_ZLIB_DELEGATE)
68#include "zlib.h"
69#endif
70
71/*
72 Typedef declarations.
73*/
74typedef struct _MagickModulo
75{
76 long
77 quotient,
78 remainder;
79} MagickModulo;
80
81struct _NexusInfo
82{
83 MagickBooleanType
84 mapped;
85
86 RectangleInfo
87 region;
88
89 MagickSizeType
90 length;
91
92 PixelPacket
93 *cache,
94 *pixels;
95
96 IndexPacket
97 *indexes;
98
99 unsigned long
100 signature;
101};
102
103/*
104 Forward declarations.
105*/
106#if defined(__cplusplus) || defined(c_plusplus)
107extern "C" {
108#endif
109
110static const IndexPacket
111 *GetVirtualIndexesFromCache(const Image *);
112
113static const PixelPacket
114 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const long,
115 const long,const unsigned long,const unsigned long,ExceptionInfo *),
116 *GetVirtualPixelsCache(const Image *);
117
118static MagickBooleanType
119 GetOneAuthenticPixelFromCache(Image *,const long,const long,PixelPacket *,
120 ExceptionInfo *),
121 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
122 const long,const long,PixelPacket *,ExceptionInfo *),
123 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
124 ReadPixelCacheIndexes(CacheInfo *,NexusInfo *,ExceptionInfo *),
125 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
126 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
127 WritePixelCacheIndexes(CacheInfo *,NexusInfo *,ExceptionInfo *),
128 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
129
130static PixelPacket
131 *GetAuthenticPixelsCache(Image *,const long,const long,const unsigned long,
132 const unsigned long,ExceptionInfo *),
133 *QueueAuthenticPixelsCache(Image *,const long,const long,const unsigned long,
134 const unsigned long,ExceptionInfo *),
135 *SetPixelCacheNexusPixels(const Image *,const RectangleInfo *,NexusInfo *,
136 ExceptionInfo *);
137
138#if defined(__cplusplus) || defined(c_plusplus)
139}
140#endif
141
142/*
143 Global declarations.
144*/
145static volatile MagickBooleanType
146 instantiate_cache = MagickFalse;
147
148static SemaphoreInfo
149 *cache_semaphore = (SemaphoreInfo *) NULL;
150
151static SplayTreeInfo
152 *cache_resources = (SplayTreeInfo *) NULL;
153
154static time_t
155 cache_timer = 0;
156
157/*
158%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
159% %
160% %
161% %
162+ A c q u i r e P i x e l C a c h e %
163% %
164% %
165% %
166%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
167%
168% AcquirePixelCache() acquires a pixel cache.
169%
170% The format of the AcquirePixelCache() method is:
171%
172% Cache AcquirePixelCache(const unsigned long number_threads)
173%
174% A description of each parameter follows:
175%
176% o number_threads: the number of nexus threads.
177%
178*/
179MagickExport Cache AcquirePixelCache(const unsigned long number_threads)
180{
181 CacheInfo
182 *cache_info;
183
184 cache_info=(CacheInfo *) AcquireAlignedMemory(1,sizeof(*cache_info));
185 if (cache_info == (CacheInfo *) NULL)
186 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
187 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
188 cache_info->type=UndefinedCache;
cristy87528ea2009-09-10 14:53:56 +0000189 cache_info->mode=IOMode;
cristy3ed852e2009-09-05 21:47:34 +0000190 cache_info->colorspace=RGBColorspace;
191 cache_info->file=(-1);
192 cache_info->id=GetMagickThreadId();
193 cache_info->number_threads=number_threads;
194 if (number_threads == 0)
195 cache_info->number_threads=GetOpenMPMaximumThreads();
196 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
197 if (cache_info->nexus_info == (NexusInfo **) NULL)
198 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
199 GetPixelCacheMethods(&cache_info->methods);
200 cache_info->reference_count=1;
201 cache_info->semaphore=AllocateSemaphoreInfo();
202 cache_info->disk_semaphore=AllocateSemaphoreInfo();
203 cache_info->debug=IsEventLogging();
204 cache_info->signature=MagickSignature;
205 if ((cache_resources == (SplayTreeInfo *) NULL) &&
206 (instantiate_cache == MagickFalse))
207 {
cristy4e1dff62009-10-25 20:36:03 +0000208 if (cache_semaphore == (SemaphoreInfo *) NULL)
209 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000210 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000211 if ((cache_resources == (SplayTreeInfo *) NULL) &&
212 (instantiate_cache == MagickFalse))
213 {
214 cache_resources=NewSplayTree((int (*)(const void *,const void *))
215 NULL,(void *(*)(void *)) NULL,(void *(*)(void *)) NULL);
216 instantiate_cache=MagickTrue;
217 }
cristyf84a1932010-01-03 18:00:18 +0000218 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000219 }
220 (void) AddValueToSplayTree(cache_resources,cache_info,cache_info);
221 return((Cache ) cache_info);
222}
223
224/*
225%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
226% %
227% %
228% %
229% A c q u i r e P i x e l C a c h e N e x u s %
230% %
231% %
232% %
233%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
234%
235% AcquirePixelCacheNexus() allocates the NexusInfo structure.
236%
237% The format of the AcquirePixelCacheNexus method is:
238%
239% NexusInfo **AcquirePixelCacheNexus(const unsigned long number_threads)
240%
241% A description of each parameter follows:
242%
243% o number_threads: the number of nexus threads.
244%
245*/
246MagickExport NexusInfo **AcquirePixelCacheNexus(
247 const unsigned long number_threads)
248{
249 register long
250 i;
251
252 NexusInfo
253 **nexus_info;
254
255 nexus_info=(NexusInfo **) AcquireAlignedMemory(number_threads,
256 sizeof(*nexus_info));
257 if (nexus_info == (NexusInfo **) NULL)
258 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
259 for (i=0; i < (long) number_threads; i++)
260 {
261 nexus_info[i]=(NexusInfo *) AcquireAlignedMemory(1,sizeof(**nexus_info));
262 if (nexus_info[i] == (NexusInfo *) NULL)
263 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
264 (void) ResetMagickMemory(nexus_info[i],0,sizeof(*nexus_info[i]));
265 nexus_info[i]->signature=MagickSignature;
266 }
267 return(nexus_info);
268}
269
270/*
271%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
272% %
273% %
274% %
cristyd43a46b2010-01-21 02:13:41 +0000275+ A c q u i r e P i x e l C a c h e P i x e l s %
276% %
277% %
278% %
279%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
280%
281% AcquirePixelCachePixels() returns the pixels associated with the specified
282% image.
283%
284% The format of the AcquirePixelCachePixels() method is:
285%
286% const void *AcquirePixelCachePixels(const Image *image,
287% MagickSizeType *length,ExceptionInfo *exception)
288%
289% A description of each parameter follows:
290%
291% o image: the image.
292%
293% o length: the pixel cache length.
294%
295% o exception: return any errors or warnings in this structure.
296%
297*/
298MagickExport const void *AcquirePixelCachePixels(const Image *image,
299 MagickSizeType *length,ExceptionInfo *exception)
300{
301 CacheInfo
302 *cache_info;
303
304 assert(image != (const Image *) NULL);
305 assert(image->signature == MagickSignature);
306 if (image->debug != MagickFalse)
307 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
308 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
423 register long
424 i;
425
426 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000427 *restrict p,
428 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000429
430 /*
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);
437 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
438 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;
456 for (i=0; i < (long) number_pixels; i++)
457 {
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);
475 if (i < (long) number_pixels)
476 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% %
528+ C l o n e P i x e l C a c h e N e x u s %
529% %
530% %
531% %
532%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
533%
534% ClonePixelCacheNexus() clones the source cache nexus to the destination
535% nexus.
536%
537% The format of the ClonePixelCacheNexus() method is:
538%
539% MagickBooleanType ClonePixelCacheNexus(CacheInfo *destination,
540% CacheInfo *source,ExceptionInfo *exception)
541%
542% A description of each parameter follows:
543%
544% o destination: the destination cache nexus.
545%
546% o source: the source cache nexus.
547%
548% o exception: return any errors or warnings in this structure.
549%
550*/
551
552static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
553 NexusInfo *nexus_info,ExceptionInfo *exception)
554{
555 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
556 return(MagickFalse);
557 nexus_info->mapped=MagickFalse;
558 nexus_info->cache=(PixelPacket *) AcquireMagickMemory((size_t)
559 nexus_info->length);
560 if (nexus_info->cache == (PixelPacket *) NULL)
561 {
562 nexus_info->mapped=MagickTrue;
563 nexus_info->cache=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
564 nexus_info->length);
565 }
566 if (nexus_info->cache == (PixelPacket *) NULL)
567 {
568 (void) ThrowMagickException(exception,GetMagickModule(),
569 ResourceLimitError,"MemoryAllocationFailed","`%s'",
570 cache_info->filename);
571 return(MagickFalse);
572 }
573 return(MagickTrue);
574}
575
576static MagickBooleanType ClonePixelCacheNexus(CacheInfo *destination,
577 CacheInfo *source,ExceptionInfo *exception)
578{
579 MagickBooleanType
580 status;
581
582 MagickSizeType
583 number_pixels;
584
585 register long
586 i;
587
588 register const NexusInfo
589 *p;
590
591 register NexusInfo
592 *q;
593
594 status=MagickTrue;
595 for (i=0; i < (long) source->number_threads; i++)
596 {
597 p=source->nexus_info[i];
598 q=destination->nexus_info[i];
599 q->mapped=p->mapped;
600 q->region=p->region;
601 q->length=p->length;
602 q->cache=p->cache;
603 q->pixels=p->pixels;
604 q->indexes=p->indexes;
605 if (p->cache != (PixelPacket *) NULL)
606 {
607 status=AcquireCacheNexusPixels(source,q,exception);
608 if (status != MagickFalse)
609 {
610 (void) CopyMagickMemory(q->cache,p->cache,(size_t) p->length);
611 q->pixels=q->cache;
612 q->indexes=(IndexPacket *) NULL;
613 number_pixels=(MagickSizeType) q->region.width*q->region.height;
614 if (p->indexes != (IndexPacket *) NULL)
615 q->indexes=(IndexPacket *) (q->pixels+number_pixels);
616 }
617 }
618 }
619 return(status);
620}
621
622/*
623%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
624% %
625% %
626% %
cristy60c44a82009-10-07 00:58:49 +0000627+ 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 +0000628% %
629% %
630% %
631%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
632% ClonePixelCachePixels() clones the source pixel cache to the destination
633% cache.
634%
635% The format of the ClonePixelCachePixels() method is:
636%
637% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
638% CacheInfo *source_info,ExceptionInfo *exception)
639%
640% A description of each parameter follows:
641%
642% o cache_info: the pixel cache.
643%
644% o source_info: the source pixel cache.
645%
646% o exception: return any errors or warnings in this structure.
647%
648*/
649
650static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
651{
652 int
653 status;
654
cristy5ee247a2010-02-12 15:42:34 +0000655 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000656 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000657 if (cache_info->file != -1)
658 status=close(cache_info->file);
cristy3ed852e2009-09-05 21:47:34 +0000659 cache_info->file=(-1);
660 RelinquishMagickResource(FileResource,1);
cristyf84a1932010-01-03 18:00:18 +0000661 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000662 return(status == -1 ? MagickFalse : MagickTrue);
663}
664
665static void LimitPixelCacheDescriptors(void)
666{
667 register CacheInfo
668 *p,
669 *q;
670
671 /*
672 Limit # of open file descriptors.
673 */
674 if (GetMagickResource(FileResource) < GetMagickResourceLimit(FileResource))
675 return;
cristyf84a1932010-01-03 18:00:18 +0000676 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000677 if (cache_resources == (SplayTreeInfo *) NULL)
678 {
cristyf84a1932010-01-03 18:00:18 +0000679 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000680 return;
681 }
682 ResetSplayTreeIterator(cache_resources);
683 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
684 while (p != (CacheInfo *) NULL)
685 {
686 if ((p->type == DiskCache) && (p->file != -1))
cristy508d9312010-02-10 21:10:30 +0000687 break;
cristy3ed852e2009-09-05 21:47:34 +0000688 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
689 }
690 for (q=p; p != (CacheInfo *) NULL; )
691 {
692 if ((p->type == DiskCache) && (p->file != -1) &&
693 (p->timestamp < q->timestamp))
cristy508d9312010-02-10 21:10:30 +0000694 q=p;
cristy3ed852e2009-09-05 21:47:34 +0000695 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
696 }
697 if (q != (CacheInfo *) NULL)
cristy9e116922010-02-12 20:58:13 +0000698 {
699 /*
700 Close least recently used cache.
701 */
702 (void) close(q->file);
703 q->file=(-1);
704 }
cristyf84a1932010-01-03 18:00:18 +0000705 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000706}
707
708static inline MagickSizeType MagickMax(const MagickSizeType x,
709 const MagickSizeType y)
710{
711 if (x > y)
712 return(x);
713 return(y);
714}
715
716static inline MagickSizeType MagickMin(const MagickSizeType x,
717 const MagickSizeType y)
718{
719 if (x < y)
720 return(x);
721 return(y);
722}
723
724static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
725 const MapMode mode)
726{
727 int
728 file;
729
730 /*
731 Open pixel cache on disk.
732 */
cristyf84a1932010-01-03 18:00:18 +0000733 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000734 if (cache_info->file != -1)
735 {
cristyf84a1932010-01-03 18:00:18 +0000736 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000737 return(MagickTrue); /* cache already open */
738 }
739 LimitPixelCacheDescriptors();
740 if (*cache_info->cache_filename == '\0')
741 file=AcquireUniqueFileResource(cache_info->cache_filename);
742 else
743 switch (mode)
744 {
745 case ReadMode:
746 {
747 file=open(cache_info->cache_filename,O_RDONLY | O_BINARY);
748 break;
749 }
750 case WriteMode:
751 {
752 file=open(cache_info->cache_filename,O_WRONLY | O_CREAT | O_BINARY |
753 O_EXCL,S_MODE);
754 if (file == -1)
755 file=open(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
756 break;
757 }
758 case IOMode:
759 default:
760 {
761 file=open(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
762 O_EXCL,S_MODE);
763 if (file == -1)
764 file=open(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
765 break;
766 }
767 }
768 if (file == -1)
769 {
cristyf84a1932010-01-03 18:00:18 +0000770 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000771 return(MagickFalse);
772 }
773 (void) AcquireMagickResource(FileResource,1);
774 cache_info->file=file;
775 cache_info->timestamp=time(0);
cristyf84a1932010-01-03 18:00:18 +0000776 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000777 return(MagickTrue);
778}
779
780static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
781 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000782 unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000783{
784 register MagickOffsetType
785 i;
786
787 ssize_t
788 count;
789
790#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000791 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000792 cache_info->timestamp=time(0);
793 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
794 {
cristyf84a1932010-01-03 18:00:18 +0000795 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000796 return((MagickOffsetType) -1);
797 }
798#endif
799 count=0;
800 for (i=0; i < (MagickOffsetType) length; i+=count)
801 {
802#if !defined(MAGICKCORE_HAVE_PREAD)
803 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
804 (MagickSizeType) SSIZE_MAX));
805#else
806 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
807 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
808#endif
809 if (count > 0)
810 continue;
811 count=0;
812 if (errno != EINTR)
813 {
814 i=(-1);
815 break;
816 }
817 }
818#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000819 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000820#endif
821 return(i);
822}
823
824static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
825 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000826 const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000827{
828 register MagickOffsetType
829 i;
830
831 ssize_t
832 count;
833
834#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000835 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000836 cache_info->timestamp=time(0);
837 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
838 {
cristyf84a1932010-01-03 18:00:18 +0000839 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000840 return((MagickOffsetType) -1);
841 }
842#endif
843 count=0;
844 for (i=0; i < (MagickOffsetType) length; i+=count)
845 {
846#if !defined(MAGICKCORE_HAVE_PWRITE)
847 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
848 (MagickSizeType) SSIZE_MAX));
849#else
850 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
851 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
852#endif
853 if (count > 0)
854 continue;
855 count=0;
856 if (errno != EINTR)
857 {
858 i=(-1);
859 break;
860 }
861 }
862#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000863 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000864#endif
865 return(i);
866}
867
868static MagickBooleanType CloneDiskToDiskPixelCache(CacheInfo *clone_info,
869 CacheInfo *cache_info,ExceptionInfo *exception)
870{
871 MagickOffsetType
872 count,
873 offset,
874 source_offset;
875
876 MagickSizeType
877 length;
878
879 register long
880 y;
881
882 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000883 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +0000884
885 unsigned long
886 columns,
887 rows;
888
889 if (cache_info->debug != MagickFalse)
890 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
891 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
892 {
893 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
894 clone_info->cache_filename);
895 return(MagickFalse);
896 }
897 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
898 {
899 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
900 cache_info->cache_filename);
901 return(MagickFalse);
902 }
903 columns=(unsigned long) MagickMin(clone_info->columns,cache_info->columns);
904 rows=(unsigned long) MagickMin(clone_info->rows,cache_info->rows);
905 if ((clone_info->active_index_channel != MagickFalse) &&
906 (cache_info->active_index_channel != MagickFalse))
907 {
908 register IndexPacket
909 *indexes;
910
911 /*
912 Clone cache indexes.
913 */
914 length=MagickMax(clone_info->columns,cache_info->columns)*
915 sizeof(*indexes);
916 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
917 if (indexes == (IndexPacket *) NULL)
918 {
919 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
920 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
921 return(MagickFalse);
922 }
923 (void) ResetMagickMemory(indexes,0,(size_t) length);
924 length=columns*sizeof(*indexes);
925 source_offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
926 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
927 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
928 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
929 for (y=0; y < (long) rows; y++)
930 {
931 source_offset-=cache_info->columns*sizeof(*indexes);
932 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
933 length,(unsigned char *) indexes);
934 if ((MagickSizeType) count != length)
935 break;
936 offset-=clone_info->columns*sizeof(*indexes);
937 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
938 (unsigned char *) indexes);
939 if ((MagickSizeType) count != length)
940 break;
941 }
942 if (y < (long) rows)
943 {
944 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
945 ThrowFileException(exception,CacheError,"UnableToCloneCache",
946 cache_info->cache_filename);
947 return(MagickFalse);
948 }
949 if (clone_info->columns > cache_info->columns)
950 {
951 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
952 (void) ResetMagickMemory(indexes,0,(size_t) length);
953 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
954 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
955 for (y=0; y < (long) rows; y++)
956 {
957 offset-=clone_info->columns*sizeof(*indexes);
958 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
959 length,(unsigned char *) indexes);
960 if ((MagickSizeType) count != length)
961 break;
962 }
963 if (y < (long) rows)
964 {
965 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
966 ThrowFileException(exception,CacheError,"UnableToCloneCache",
967 cache_info->cache_filename);
968 return(MagickFalse);
969 }
970 }
971 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
972 }
973 /*
974 Clone cache pixels.
975 */
976 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
977 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
978 if (pixels == (PixelPacket *) NULL)
979 {
980 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
981 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
982 return(MagickFalse);
983 }
984 (void) ResetMagickMemory(pixels,0,(size_t) length);
985 length=columns*sizeof(*pixels);
986 source_offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
987 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
988 for (y=0; y < (long) rows; y++)
989 {
990 source_offset-=cache_info->columns*sizeof(*pixels);
991 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
992 length,(unsigned char *) pixels);
993 if ((MagickSizeType) count != length)
994 break;
995 offset-=clone_info->columns*sizeof(*pixels);
996 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
997 (unsigned char *) pixels);
998 if ((MagickSizeType) count != length)
999 break;
1000 }
1001 if (y < (long) rows)
1002 {
1003 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1004 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1005 cache_info->cache_filename);
1006 return(MagickFalse);
1007 }
1008 if (clone_info->columns > cache_info->columns)
1009 {
1010 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
1011 sizeof(*pixels);
1012 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1013 (void) ResetMagickMemory(pixels,0,(size_t) length);
1014 for (y=0; y < (long) rows; y++)
1015 {
1016 offset-=clone_info->columns*sizeof(*pixels);
1017 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1018 (unsigned char *) pixels);
1019 if ((MagickSizeType) count != length)
1020 break;
1021 }
1022 if (y < (long) rows)
1023 {
1024 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1025 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1026 cache_info->cache_filename);
1027 return(MagickFalse);
1028 }
1029 }
1030 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1031 return(MagickTrue);
1032}
1033
1034static MagickBooleanType CloneDiskToMemoryPixelCache(CacheInfo *clone_info,
1035 CacheInfo *cache_info,ExceptionInfo *exception)
1036{
1037 MagickOffsetType
1038 count,
1039 offset;
1040
1041 MagickSizeType
1042 length;
1043
1044 register long
1045 y;
1046
1047 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001048 *restrict pixels,
1049 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00001050
1051 unsigned long
1052 columns,
1053 rows;
1054
1055 if (cache_info->debug != MagickFalse)
1056 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
1057 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
1058 {
1059 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1060 cache_info->cache_filename);
1061 return(MagickFalse);
1062 }
1063 columns=(unsigned long) MagickMin(clone_info->columns,cache_info->columns);
1064 rows=(unsigned long) MagickMin(clone_info->rows,cache_info->rows);
1065 if ((clone_info->active_index_channel != MagickFalse) &&
1066 (cache_info->active_index_channel != MagickFalse))
1067 {
1068 register IndexPacket
1069 *indexes,
1070 *q;
1071
1072 /*
1073 Clone cache indexes.
1074 */
1075 length=MagickMax(clone_info->columns,cache_info->columns)*
1076 sizeof(*indexes);
1077 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
1078 if (indexes == (IndexPacket *) NULL)
1079 {
1080 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1081 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1082 return(MagickFalse);
1083 }
1084 (void) ResetMagickMemory(indexes,0,(size_t) length);
1085 length=columns*sizeof(IndexPacket);
1086 offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
1087 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
1088 q=clone_info->indexes+clone_info->columns*rows;
1089 for (y=0; y < (long) rows; y++)
1090 {
1091 offset-=cache_info->columns*sizeof(IndexPacket);
1092 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,
1093 length,(unsigned char *) indexes);
1094 if ((MagickSizeType) count != length)
1095 break;
1096 q-=clone_info->columns;
1097 (void) CopyMagickMemory(q,indexes,(size_t) length);
1098 if ((MagickSizeType) count != length)
1099 break;
1100 }
1101 if (y < (long) rows)
1102 {
1103 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1104 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1105 cache_info->cache_filename);
1106 return(MagickFalse);
1107 }
1108 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1109 }
1110 /*
1111 Clone cache pixels.
1112 */
1113 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1114 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1115 if (pixels == (PixelPacket *) NULL)
1116 {
1117 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1118 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1119 return(MagickFalse);
1120 }
1121 (void) ResetMagickMemory(pixels,0,(size_t) length);
1122 length=columns*sizeof(*pixels);
1123 offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
1124 q=clone_info->pixels+clone_info->columns*rows;
1125 for (y=0; y < (long) rows; y++)
1126 {
1127 offset-=cache_info->columns*sizeof(*pixels);
1128 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,length,
1129 (unsigned char *) pixels);
1130 if ((MagickSizeType) count != length)
1131 break;
1132 q-=clone_info->columns;
1133 (void) CopyMagickMemory(q,pixels,(size_t) length);
1134 }
1135 if (y < (long) rows)
1136 {
1137 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1138 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1139 cache_info->cache_filename);
1140 return(MagickFalse);
1141 }
1142 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1143 return(MagickTrue);
1144}
1145
1146static MagickBooleanType CloneMemoryToDiskPixelCache(CacheInfo *clone_info,
1147 CacheInfo *cache_info,ExceptionInfo *exception)
1148{
1149 MagickOffsetType
1150 count,
1151 offset;
1152
1153 MagickSizeType
1154 length;
1155
1156 register long
1157 y;
1158
1159 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001160 *restrict p,
1161 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +00001162
1163 unsigned long
1164 columns,
1165 rows;
1166
1167 if (cache_info->debug != MagickFalse)
1168 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
1169 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
1170 {
1171 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1172 clone_info->cache_filename);
1173 return(MagickFalse);
1174 }
1175 columns=(unsigned long) MagickMin(clone_info->columns,cache_info->columns);
1176 rows=(unsigned long) MagickMin(clone_info->rows,cache_info->rows);
1177 if ((clone_info->active_index_channel != MagickFalse) &&
1178 (cache_info->active_index_channel != MagickFalse))
1179 {
1180 register IndexPacket
1181 *p,
1182 *indexes;
1183
1184 /*
1185 Clone cache indexes.
1186 */
1187 length=MagickMax(clone_info->columns,cache_info->columns)*
1188 sizeof(*indexes);
1189 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
1190 if (indexes == (IndexPacket *) NULL)
1191 {
1192 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1193 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1194 return(MagickFalse);
1195 }
1196 (void) ResetMagickMemory(indexes,0,(size_t) length);
1197 length=columns*sizeof(*indexes);
1198 p=cache_info->indexes+cache_info->columns*rows;
1199 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1200 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
1201 for (y=0; y < (long) rows; y++)
1202 {
1203 p-=cache_info->columns;
1204 (void) CopyMagickMemory(indexes,p,(size_t) length);
1205 offset-=clone_info->columns*sizeof(*indexes);
1206 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1207 (unsigned char *) indexes);
1208 if ((MagickSizeType) count != length)
1209 break;
1210 }
1211 if (y < (long) rows)
1212 {
1213 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1214 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1215 cache_info->cache_filename);
1216 return(MagickFalse);
1217 }
1218 if (clone_info->columns > cache_info->columns)
1219 {
1220 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
1221 (void) ResetMagickMemory(indexes,0,(size_t) length);
1222 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1223 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
1224 for (y=0; y < (long) rows; y++)
1225 {
1226 offset-=clone_info->columns*sizeof(*indexes);
1227 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
1228 length,(unsigned char *) indexes);
1229 if ((MagickSizeType) count != length)
1230 break;
1231 }
1232 if (y < (long) rows)
1233 {
1234 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1235 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1236 cache_info->cache_filename);
1237 return(MagickFalse);
1238 }
1239 }
1240 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1241 }
1242 /*
1243 Clone cache pixels.
1244 */
1245 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1246 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1247 if (pixels == (PixelPacket *) NULL)
1248 {
1249 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1250 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1251 return(MagickFalse);
1252 }
1253 (void) ResetMagickMemory(pixels,0,(size_t) length);
1254 length=columns*sizeof(*pixels);
1255 p=cache_info->pixels+cache_info->columns*rows;
1256 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
1257 for (y=0; y < (long) rows; y++)
1258 {
1259 p-=cache_info->columns;
1260 (void) CopyMagickMemory(pixels,p,(size_t) length);
1261 offset-=clone_info->columns*sizeof(*pixels);
1262 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1263 (unsigned char *) pixels);
1264 if ((MagickSizeType) count != length)
1265 break;
1266 }
1267 if (y < (long) rows)
1268 {
1269 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1270 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1271 cache_info->cache_filename);
1272 return(MagickFalse);
1273 }
1274 if (clone_info->columns > cache_info->columns)
1275 {
1276 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
1277 sizeof(*pixels);
1278 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1279 (void) ResetMagickMemory(pixels,0,(size_t) length);
1280 for (y=0; y < (long) rows; y++)
1281 {
1282 offset-=clone_info->columns*sizeof(*pixels);
1283 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1284 (unsigned char *) pixels);
1285 if ((MagickSizeType) count != length)
1286 break;
1287 }
1288 if (y < (long) rows)
1289 {
1290 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1291 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1292 cache_info->cache_filename);
1293 return(MagickFalse);
1294 }
1295 }
1296 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1297 return(MagickTrue);
1298}
1299
1300static MagickBooleanType CloneMemoryToMemoryPixelCache(CacheInfo *clone_info,
1301 CacheInfo *cache_info,ExceptionInfo *magick_unused(exception))
1302{
1303 register long
1304 y;
1305
1306 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001307 *restrict pixels,
1308 *restrict source_pixels;
cristy3ed852e2009-09-05 21:47:34 +00001309
1310 size_t
1311 length;
1312
1313 unsigned long
1314 columns,
1315 rows;
1316
1317 if (cache_info->debug != MagickFalse)
1318 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
1319 columns=(unsigned long) MagickMin(clone_info->columns,cache_info->columns);
1320 rows=(unsigned long) MagickMin(clone_info->rows,cache_info->rows);
1321 if ((clone_info->active_index_channel != MagickFalse) &&
1322 (cache_info->active_index_channel != MagickFalse))
1323 {
1324 register IndexPacket
1325 *indexes,
1326 *source_indexes;
1327
1328 /*
1329 Clone cache indexes.
1330 */
1331 length=columns*sizeof(*indexes);
1332 if (clone_info->columns == cache_info->columns)
1333 (void) CopyMagickMemory(clone_info->indexes,cache_info->indexes,
1334 length*rows);
1335 else
1336 {
1337 source_indexes=cache_info->indexes+cache_info->columns*rows;
1338 indexes=clone_info->indexes+clone_info->columns*rows;
1339 for (y=0; y < (long) rows; y++)
1340 {
1341 source_indexes-=cache_info->columns;
1342 indexes-=clone_info->columns;
1343 (void) CopyMagickMemory(indexes,source_indexes,length);
1344 }
1345 if (clone_info->columns > cache_info->columns)
1346 {
1347 length=(clone_info->columns-cache_info->columns)*
1348 sizeof(*indexes);
1349 indexes=clone_info->indexes+clone_info->columns*rows+
1350 cache_info->columns;
1351 for (y=0; y < (long) rows; y++)
1352 {
1353 indexes-=clone_info->columns;
1354 (void) ResetMagickMemory(indexes,0,length);
1355 }
1356 }
1357 }
1358 }
1359 /*
1360 Clone cache pixels.
1361 */
1362 length=columns*sizeof(*pixels);
1363 if (clone_info->columns == cache_info->columns)
1364 (void) CopyMagickMemory(clone_info->pixels,cache_info->pixels,length*rows);
1365 else
1366 {
1367 source_pixels=cache_info->pixels+cache_info->columns*rows;
1368 pixels=clone_info->pixels+clone_info->columns*rows;
1369 for (y=0; y < (long) rows; y++)
1370 {
1371 source_pixels-=cache_info->columns;
1372 pixels-=clone_info->columns;
1373 (void) CopyMagickMemory(pixels,source_pixels,length);
1374 }
1375 if (clone_info->columns > cache_info->columns)
1376 {
1377 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1378 pixels=clone_info->pixels+clone_info->columns*rows+
1379 cache_info->columns;
1380 for (y=0; y < (long) rows; y++)
1381 {
1382 pixels-=clone_info->columns;
1383 (void) ResetMagickMemory(pixels,0,length);
1384 }
1385 }
1386 }
1387 return(MagickTrue);
1388}
1389
1390static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1391 CacheInfo *cache_info,ExceptionInfo *exception)
1392{
1393 if ((clone_info->type != DiskCache) && (cache_info->type != DiskCache))
1394 return(CloneMemoryToMemoryPixelCache(clone_info,cache_info,exception));
1395 if ((clone_info->type == DiskCache) && (cache_info->type == DiskCache))
1396 return(CloneDiskToDiskPixelCache(clone_info,cache_info,exception));
1397 if (cache_info->type == DiskCache)
1398 return(CloneDiskToMemoryPixelCache(clone_info,cache_info,exception));
1399 return(CloneMemoryToDiskPixelCache(clone_info,cache_info,exception));
1400}
1401
1402/*
1403%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1404% %
1405% %
1406% %
1407+ C l o n e P i x e l C a c h e M e t h o d s %
1408% %
1409% %
1410% %
1411%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1412%
1413% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1414% another.
1415%
1416% The format of the ClonePixelCacheMethods() method is:
1417%
1418% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1419%
1420% A description of each parameter follows:
1421%
1422% o clone: Specifies a pointer to a Cache structure.
1423%
1424% o cache: the pixel cache.
1425%
1426*/
1427MagickExport void ClonePixelCacheMethods(Cache clone,const Cache cache)
1428{
1429 CacheInfo
1430 *cache_info,
1431 *source_info;
1432
1433 assert(clone != (Cache) NULL);
1434 source_info=(CacheInfo *) clone;
1435 assert(source_info->signature == MagickSignature);
1436 if (source_info->debug != MagickFalse)
1437 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1438 source_info->filename);
1439 assert(cache != (Cache) NULL);
1440 cache_info=(CacheInfo *) cache;
1441 assert(cache_info->signature == MagickSignature);
1442 source_info->methods=cache_info->methods;
1443}
1444
1445/*
1446%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1447% %
1448% %
1449% %
1450+ D e s t r o y I m a g e P i x e l C a c h e %
1451% %
1452% %
1453% %
1454%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1455%
1456% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1457%
1458% The format of the DestroyImagePixelCache() method is:
1459%
1460% void DestroyImagePixelCache(Image *image)
1461%
1462% A description of each parameter follows:
1463%
1464% o image: the image.
1465%
1466*/
1467static void DestroyImagePixelCache(Image *image)
1468{
1469 assert(image != (Image *) NULL);
1470 assert(image->signature == MagickSignature);
1471 if (image->debug != MagickFalse)
1472 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1473 if (image->cache == (void *) NULL)
1474 return;
1475 image->cache=DestroyPixelCache(image->cache);
1476}
1477
1478/*
1479%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1480% %
1481% %
1482% %
1483+ D e s t r o y I m a g e P i x e l s %
1484% %
1485% %
1486% %
1487%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1488%
1489% DestroyImagePixels() deallocates memory associated with the pixel cache.
1490%
1491% The format of the DestroyImagePixels() method is:
1492%
1493% void DestroyImagePixels(Image *image)
1494%
1495% A description of each parameter follows:
1496%
1497% o image: the image.
1498%
1499*/
1500MagickExport void DestroyImagePixels(Image *image)
1501{
1502 CacheInfo
1503 *cache_info;
1504
1505 assert(image != (const Image *) NULL);
1506 assert(image->signature == MagickSignature);
1507 if (image->debug != MagickFalse)
1508 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1509 assert(image->cache != (Cache) NULL);
1510 cache_info=(CacheInfo *) image->cache;
1511 assert(cache_info->signature == MagickSignature);
1512 if (cache_info->methods.destroy_pixel_handler == (DestroyPixelHandler) NULL)
1513 return;
1514 cache_info->methods.destroy_pixel_handler(image);
1515}
1516
1517/*
1518%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1519% %
1520% %
1521% %
1522+ D e s t r o y P i x e l C a c h e %
1523% %
1524% %
1525% %
1526%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1527%
1528% DestroyPixelCache() deallocates memory associated with the pixel cache.
1529%
1530% The format of the DestroyPixelCache() method is:
1531%
1532% Cache DestroyPixelCache(Cache cache)
1533%
1534% A description of each parameter follows:
1535%
1536% o cache: the pixel cache.
1537%
1538*/
1539
1540static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1541{
1542 switch (cache_info->type)
1543 {
1544 case MemoryCache:
1545 {
1546 if (cache_info->mapped == MagickFalse)
1547 cache_info->pixels=(PixelPacket *) RelinquishMagickMemory(
1548 cache_info->pixels);
1549 else
1550 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,
1551 (size_t) cache_info->length);
1552 RelinquishMagickResource(MemoryResource,cache_info->length);
1553 break;
1554 }
1555 case MapCache:
1556 {
1557 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,(size_t)
1558 cache_info->length);
1559 RelinquishMagickResource(MapResource,cache_info->length);
1560 }
1561 case DiskCache:
1562 {
1563 if (cache_info->file != -1)
1564 (void) ClosePixelCacheOnDisk(cache_info);
1565 RelinquishMagickResource(DiskResource,cache_info->length);
1566 break;
1567 }
1568 default:
1569 break;
1570 }
1571 cache_info->type=UndefinedCache;
1572 cache_info->mapped=MagickFalse;
1573 cache_info->indexes=(IndexPacket *) NULL;
1574}
1575
1576MagickExport Cache DestroyPixelCache(Cache cache)
1577{
1578 CacheInfo
1579 *cache_info;
1580
cristy3ed852e2009-09-05 21:47:34 +00001581 assert(cache != (Cache) NULL);
1582 cache_info=(CacheInfo *) cache;
1583 assert(cache_info->signature == MagickSignature);
1584 if (cache_info->debug != MagickFalse)
1585 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1586 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001587 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001588 cache_info->reference_count--;
1589 if (cache_info->reference_count != 0)
1590 {
cristyf84a1932010-01-03 18:00:18 +00001591 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001592 return((Cache) NULL);
1593 }
cristyf84a1932010-01-03 18:00:18 +00001594 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001595 if (cache_resources != (SplayTreeInfo *) NULL)
1596 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
cristy5b8de732009-09-10 23:50:40 +00001597 if (cache_info->debug != MagickFalse)
1598 {
1599 char
1600 message[MaxTextExtent];
1601
1602 (void) FormatMagickString(message,MaxTextExtent,"destroy %s",
1603 cache_info->filename);
1604 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1605 }
cristyc2e1bdd2009-09-10 23:43:34 +00001606 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1607 (cache_info->type != DiskCache)))
1608 RelinquishPixelCachePixels(cache_info);
1609 else
1610 {
1611 RelinquishPixelCachePixels(cache_info);
1612 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1613 }
cristy3ed852e2009-09-05 21:47:34 +00001614 *cache_info->cache_filename='\0';
1615 if (cache_info->nexus_info != (NexusInfo **) NULL)
1616 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1617 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001618 if (cache_info->random_info != (RandomInfo *) NULL)
1619 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001620 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1621 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1622 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1623 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001624 cache_info->signature=(~MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001625 cache_info=(CacheInfo *) RelinquishAlignedMemory(cache_info);
1626 cache=(Cache) NULL;
1627 return(cache);
1628}
1629
1630/*
1631%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1632% %
1633% %
1634% %
1635+ D e s t r o y P i x e l C a c h e N e x u s %
1636% %
1637% %
1638% %
1639%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1640%
1641% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1642%
1643% The format of the DestroyPixelCacheNexus() method is:
1644%
1645% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
1646% const unsigned long number_threads)
1647%
1648% A description of each parameter follows:
1649%
1650% o nexus_info: the nexus to destroy.
1651%
1652% o number_threads: the number of nexus threads.
1653%
1654*/
1655
1656static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1657{
1658 if (nexus_info->mapped == MagickFalse)
1659 (void) RelinquishMagickMemory(nexus_info->cache);
1660 else
1661 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1662 nexus_info->cache=(PixelPacket *) NULL;
1663 nexus_info->pixels=(PixelPacket *) NULL;
1664 nexus_info->indexes=(IndexPacket *) NULL;
1665 nexus_info->length=0;
1666 nexus_info->mapped=MagickFalse;
1667}
1668
1669MagickExport NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
1670 const unsigned long number_threads)
1671{
1672 register long
1673 i;
1674
1675 assert(nexus_info != (NexusInfo **) NULL);
1676 for (i=0; i < (long) number_threads; i++)
1677 {
1678 if (nexus_info[i]->cache != (PixelPacket *) NULL)
1679 RelinquishCacheNexusPixels(nexus_info[i]);
1680 nexus_info[i]->signature=(~MagickSignature);
1681 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
1682 }
1683 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
1684 return(nexus_info);
1685}
1686
1687/*
1688%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1689% %
1690% %
1691% %
cristy3ed852e2009-09-05 21:47:34 +00001692+ 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 %
1693% %
1694% %
1695% %
1696%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1697%
1698% GetAuthenticIndexesFromCache() returns the indexes associated with the last
1699% call to QueueAuthenticPixelsCache() or GetAuthenticPixelsCache().
1700%
1701% The format of the GetAuthenticIndexesFromCache() method is:
1702%
1703% IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1704%
1705% A description of each parameter follows:
1706%
1707% o image: the image.
1708%
1709*/
1710static IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1711{
1712 CacheInfo
1713 *cache_info;
1714
1715 IndexPacket
1716 *indexes;
1717
1718 long
1719 id;
1720
1721 if (image->debug != MagickFalse)
1722 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1723 cache_info=(CacheInfo *) image->cache;
1724 id=GetOpenMPThreadId();
1725 assert(id < (long) cache_info->number_threads);
1726 indexes=GetPixelCacheNexusIndexes(image->cache,cache_info->nexus_info[id]);
1727 return(indexes);
1728}
1729
1730/*
1731%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1732% %
1733% %
1734% %
1735% G e t A u t h e n t i c I n d e x Q u e u e %
1736% %
1737% %
1738% %
1739%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1740%
1741% GetAuthenticIndexQueue() returns the authentic black channel or the colormap
1742% indexes associated with the last call to QueueAuthenticPixels() or
1743% GetVirtualPixels(). NULL is returned if the black channel or colormap
1744% indexes are not available.
1745%
1746% The format of the GetAuthenticIndexQueue() method is:
1747%
1748% IndexPacket *GetAuthenticIndexQueue(const Image *image)
1749%
1750% A description of each parameter follows:
1751%
1752% o image: the image.
1753%
1754*/
1755MagickExport IndexPacket *GetAuthenticIndexQueue(const Image *image)
1756{
1757 CacheInfo
1758 *cache_info;
1759
1760 assert(image != (const Image *) NULL);
1761 assert(image->signature == MagickSignature);
1762 if (image->debug != MagickFalse)
1763 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1764 assert(image->cache != (Cache) NULL);
1765 cache_info=(CacheInfo *) image->cache;
1766 assert(cache_info->signature == MagickSignature);
1767 if (cache_info->methods.get_authentic_indexes_from_handler ==
1768 (GetAuthenticIndexesFromHandler) NULL)
1769 return((IndexPacket *) NULL);
1770 return(cache_info->methods.get_authentic_indexes_from_handler(image));
1771}
1772
1773/*
1774%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1775% %
1776% %
1777% %
1778+ 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 %
1779% %
1780% %
1781% %
1782%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1783%
1784% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1785% disk pixel cache as defined by the geometry parameters. A pointer to the
1786% pixels is returned if the pixels are transferred, otherwise a NULL is
1787% returned.
1788%
1789% The format of the GetAuthenticPixelCacheNexus() method is:
1790%
1791% PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const long x,
1792% const long y,const unsigned long columns,const unsigned long rows,
1793% NexusInfo *nexus_info,ExceptionInfo *exception)
1794%
1795% A description of each parameter follows:
1796%
1797% o image: the image.
1798%
1799% o x,y,columns,rows: These values define the perimeter of a region of
1800% pixels.
1801%
1802% o nexus_info: the cache nexus to return.
1803%
1804% o exception: return any errors or warnings in this structure.
1805%
1806*/
1807
1808static inline MagickBooleanType IsNexusInCore(const CacheInfo *cache_info,
1809 NexusInfo *nexus_info)
1810{
1811 MagickOffsetType
1812 offset;
1813
1814 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1815 nexus_info->region.x;
1816 if (nexus_info->pixels != (cache_info->pixels+offset))
1817 return(MagickFalse);
1818 return(MagickTrue);
1819}
1820
1821MagickExport PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const long x,
1822 const long y,const unsigned long columns,const unsigned long rows,
1823 NexusInfo *nexus_info,ExceptionInfo *exception)
1824{
1825 CacheInfo
1826 *cache_info;
1827
1828 PixelPacket
1829 *pixels;
1830
1831 /*
1832 Transfer pixels from the cache.
1833 */
1834 assert(image != (Image *) NULL);
1835 assert(image->signature == MagickSignature);
1836 if (image->debug != MagickFalse)
1837 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1838 pixels=QueueAuthenticNexus(image,x,y,columns,rows,nexus_info,exception);
1839 if (pixels == (PixelPacket *) NULL)
1840 return((PixelPacket *) NULL);
1841 cache_info=(CacheInfo *) image->cache;
1842 assert(cache_info->signature == MagickSignature);
1843 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
1844 return(pixels);
1845 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1846 return((PixelPacket *) NULL);
1847 if (cache_info->active_index_channel != MagickFalse)
1848 if (ReadPixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse)
1849 return((PixelPacket *) NULL);
1850 return(pixels);
1851}
1852
1853/*
1854%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1855% %
1856% %
1857% %
1858+ 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 %
1859% %
1860% %
1861% %
1862%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1863%
1864% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1865% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1866%
1867% The format of the GetAuthenticPixelsFromCache() method is:
1868%
1869% PixelPacket *GetAuthenticPixelsFromCache(const Image image)
1870%
1871% A description of each parameter follows:
1872%
1873% o image: the image.
1874%
1875*/
1876static PixelPacket *GetAuthenticPixelsFromCache(const Image *image)
1877{
1878 CacheInfo
1879 *cache_info;
1880
1881 long
1882 id;
1883
1884 PixelPacket
1885 *pixels;
1886
1887 if (image->debug != MagickFalse)
1888 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1889 cache_info=(CacheInfo *) image->cache;
1890 id=GetOpenMPThreadId();
1891 assert(id < (long) cache_info->number_threads);
1892 pixels=GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]);
1893 return(pixels);
1894}
1895
1896/*
1897%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1898% %
1899% %
1900% %
1901% G e t A u t h e n t i c P i x e l Q u e u e %
1902% %
1903% %
1904% %
1905%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1906%
1907% GetAuthenticPixelQueue() returns the authentic pixels associated with the
1908% last call to QueueAuthenticPixels() or GetAuthenticPixels().
1909%
1910% The format of the GetAuthenticPixelQueue() method is:
1911%
1912% PixelPacket *GetAuthenticPixelQueue(const Image image)
1913%
1914% A description of each parameter follows:
1915%
1916% o image: the image.
1917%
1918*/
1919MagickExport PixelPacket *GetAuthenticPixelQueue(const Image *image)
1920{
1921 CacheInfo
1922 *cache_info;
1923
1924 assert(image != (const Image *) NULL);
1925 assert(image->signature == MagickSignature);
1926 if (image->debug != MagickFalse)
1927 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1928 assert(image->cache != (Cache) NULL);
1929 cache_info=(CacheInfo *) image->cache;
1930 assert(cache_info->signature == MagickSignature);
1931 if (cache_info->methods.get_authentic_pixels_from_handler ==
1932 (GetAuthenticPixelsFromHandler) NULL)
1933 return((PixelPacket *) NULL);
1934 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1935}
1936
1937/*
1938%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1939% %
1940% %
1941% %
1942% G e t A u t h e n t i c P i x e l s %
1943% %
1944% %
1945% %
1946%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1947%
1948% GetAuthenticPixels() obtains a pixel region for read/write access. If the
1949% region is successfully accessed, a pointer to a PixelPacket array
1950% representing the region is returned, otherwise NULL is returned.
1951%
1952% The returned pointer may point to a temporary working copy of the pixels
1953% or it may point to the original pixels in memory. Performance is maximized
1954% if the selected region is part of one row, or one or more full rows, since
1955% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001956% if the image is in memory, or in a memory-mapped file. The returned pointer
1957% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001958%
1959% Pixels accessed via the returned pointer represent a simple array of type
1960% PixelPacket. If the image type is CMYK or if the storage class is
1961% PseduoClass, call GetAuthenticIndexQueue() after invoking
1962% GetAuthenticPixels() to obtain the black color component or colormap indexes
1963% (of type IndexPacket) corresponding to the region. Once the PixelPacket
1964% (and/or IndexPacket) array has been updated, the changes must be saved back
1965% to the underlying image using SyncAuthenticPixels() or they may be lost.
1966%
1967% The format of the GetAuthenticPixels() method is:
1968%
1969% PixelPacket *GetAuthenticPixels(Image *image,const long x,const long y,
1970% const unsigned long columns,const unsigned long rows,
1971% ExceptionInfo *exception)
1972%
1973% A description of each parameter follows:
1974%
1975% o image: the image.
1976%
1977% o x,y,columns,rows: These values define the perimeter of a region of
1978% pixels.
1979%
1980% o exception: return any errors or warnings in this structure.
1981%
1982*/
1983MagickExport PixelPacket *GetAuthenticPixels(Image *image,const long x,
1984 const long y,const unsigned long columns,const unsigned long rows,
1985 ExceptionInfo *exception)
1986{
1987 CacheInfo
1988 *cache_info;
1989
1990 PixelPacket
1991 *pixels;
1992
1993 assert(image != (Image *) NULL);
1994 assert(image->signature == MagickSignature);
1995 if (image->debug != MagickFalse)
1996 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1997 assert(image->cache != (Cache) NULL);
1998 cache_info=(CacheInfo *) image->cache;
1999 assert(cache_info->signature == MagickSignature);
2000 if (cache_info->methods.get_authentic_pixels_handler ==
2001 (GetAuthenticPixelsHandler) NULL)
2002 return((PixelPacket *) NULL);
2003 pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
2004 rows,exception);
2005 return(pixels);
2006}
2007
2008/*
2009%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2010% %
2011% %
2012% %
2013+ G e t A u t h e n t i c P i x e l s C a c h e %
2014% %
2015% %
2016% %
2017%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2018%
2019% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
2020% as defined by the geometry parameters. A pointer to the pixels is returned
2021% if the pixels are transferred, otherwise a NULL is returned.
2022%
2023% The format of the GetAuthenticPixelsCache() method is:
2024%
2025% PixelPacket *GetAuthenticPixelsCache(Image *image,const long x,
2026% const long y,const unsigned long columns,const unsigned long rows,
2027% ExceptionInfo *exception)
2028%
2029% A description of each parameter follows:
2030%
2031% o image: the image.
2032%
2033% o x,y,columns,rows: These values define the perimeter of a region of
2034% pixels.
2035%
2036% o exception: return any errors or warnings in this structure.
2037%
2038*/
2039static PixelPacket *GetAuthenticPixelsCache(Image *image,const long x,
2040 const long y,const unsigned long columns,const unsigned long rows,
2041 ExceptionInfo *exception)
2042{
2043 CacheInfo
2044 *cache_info;
2045
2046 long
2047 id;
2048
2049 PixelPacket
2050 *pixels;
2051
2052 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
2053 if (cache_info == (Cache) NULL)
2054 return((PixelPacket *) NULL);
2055 id=GetOpenMPThreadId();
2056 assert(id < (long) cache_info->number_threads);
2057 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
2058 cache_info->nexus_info[id],exception);
2059 return(pixels);
2060}
2061
2062/*
2063%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2064% %
2065% %
2066% %
2067+ G e t I m a g e E x t e n t %
2068% %
2069% %
2070% %
2071%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2072%
2073% GetImageExtent() returns the extent of the pixels associated with the
2074% last call to QueueAuthenticPixels() or GetAuthenticPixels().
2075%
2076% The format of the GetImageExtent() method is:
2077%
2078% MagickSizeType GetImageExtent(const Image *image)
2079%
2080% A description of each parameter follows:
2081%
2082% o image: the image.
2083%
2084*/
2085MagickExport MagickSizeType GetImageExtent(const Image *image)
2086{
2087 CacheInfo
2088 *cache_info;
2089
2090 long
2091 id;
2092
2093 MagickSizeType
2094 extent;
2095
2096 assert(image != (Image *) NULL);
2097 assert(image->signature == MagickSignature);
2098 if (image->debug != MagickFalse)
2099 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2100 assert(image->cache != (Cache) NULL);
2101 cache_info=(CacheInfo *) image->cache;
2102 assert(cache_info->signature == MagickSignature);
2103 id=GetOpenMPThreadId();
2104 assert(id < (long) cache_info->number_threads);
2105 extent=GetPixelCacheNexusExtent(image->cache,cache_info->nexus_info[id]);
2106 return(extent);
2107}
2108
2109/*
2110%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2111% %
2112% %
2113% %
2114+ G e t I m a g e P i x e l C a c h e %
2115% %
2116% %
2117% %
2118%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2119%
2120% GetImagePixelCache() ensures that there is only a single reference to the
2121% pixel cache to be modified, updating the provided cache pointer to point to
2122% a clone of the original pixel cache if necessary.
2123%
2124% The format of the GetImagePixelCache method is:
2125%
2126% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2127% ExceptionInfo *exception)
2128%
2129% A description of each parameter follows:
2130%
2131% o image: the image.
2132%
2133% o clone: any value other than MagickFalse clones the cache pixels.
2134%
2135% o exception: return any errors or warnings in this structure.
2136%
2137*/
2138
2139static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
2140{
2141 CacheInfo
2142 *cache_info;
2143
2144 /*
2145 Does the image match the pixel cache morphology?
2146 */
2147 cache_info=(CacheInfo *) image->cache;
2148 if ((image->storage_class != cache_info->storage_class) ||
2149 (image->colorspace != cache_info->colorspace) ||
2150 (image->columns != cache_info->columns) ||
2151 (image->rows != cache_info->rows) ||
2152 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2153 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2154 return(MagickFalse);
2155 return(MagickTrue);
2156}
2157
2158MagickExport Cache GetImagePixelCache(Image *image,
2159 const MagickBooleanType clone,ExceptionInfo *exception)
2160{
2161 CacheInfo
2162 *cache_info;
2163
2164 MagickSizeType
2165 time_limit;
2166
2167 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00002168 destroy,
cristy3ed852e2009-09-05 21:47:34 +00002169 status;
2170
2171 if (image->debug != MagickFalse)
2172 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2173 status=MagickTrue;
cristyf84a1932010-01-03 18:00:18 +00002174 LockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002175 time_limit=GetMagickResourceLimit(TimeResource);
2176 if (cache_timer == 0)
2177 cache_timer=time((time_t *) NULL);
2178 if ((time_limit != MagickResourceInfinity) &&
2179 ((MagickSizeType) (time((time_t *) NULL)-cache_timer) >= time_limit))
2180 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
2181 assert(image->cache != (Cache) NULL);
2182 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002183 destroy=MagickFalse;
cristy01b7eb02009-09-10 23:10:14 +00002184 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002185 {
cristyaaa0cb62010-02-15 17:47:27 +00002186 LockSemaphoreInfo(cache_info->semaphore);
2187 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002188 {
cristyaaa0cb62010-02-15 17:47:27 +00002189 Image
2190 clone_image;
2191
2192 CacheInfo
2193 *clone_info;
2194
2195 /*
2196 Clone pixel cache.
2197 */
2198 clone_image=(*image);
2199 clone_image.cache=ClonePixelCache(cache_info);
2200 clone_info=(CacheInfo *) clone_image.cache;
2201 status=ClonePixelCacheNexus(cache_info,clone_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00002202 if (status != MagickFalse)
2203 {
cristyaaa0cb62010-02-15 17:47:27 +00002204 status=OpenPixelCache(&clone_image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00002205 if (status != MagickFalse)
2206 {
cristyaaa0cb62010-02-15 17:47:27 +00002207 if (clone != MagickFalse)
2208 status=ClonePixelCachePixels(clone_info,cache_info,
2209 exception);
2210 if (status != MagickFalse)
2211 {
2212 destroy=MagickTrue;
2213 image->cache=clone_image.cache;
2214 }
cristy3ed852e2009-09-05 21:47:34 +00002215 }
2216 }
2217 }
cristyaaa0cb62010-02-15 17:47:27 +00002218 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002219 }
cristy4320e0e2009-09-10 15:00:08 +00002220 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002221 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002222 if (status != MagickFalse)
2223 {
2224 /*
2225 Ensure the image matches the pixel cache morphology.
2226 */
2227 image->taint=MagickTrue;
2228 image->type=UndefinedType;
2229 if (image->colorspace == GRAYColorspace)
2230 image->colorspace=RGBColorspace;
2231 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2232 status=OpenPixelCache(image,IOMode,exception);
2233 }
cristyf84a1932010-01-03 18:00:18 +00002234 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002235 if (status == MagickFalse)
2236 return((Cache) NULL);
2237 return(image->cache);
2238}
2239
2240/*
2241%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2242% %
2243% %
2244% %
2245% G e t O n e A u t h e n t i c P i x e l %
2246% %
2247% %
2248% %
2249%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2250%
2251% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2252% location. The image background color is returned if an error occurs.
2253%
2254% The format of the GetOneAuthenticPixel() method is:
2255%
2256% MagickBooleanType GetOneAuthenticPixel(const Image image,const long x,
2257% const long y,PixelPacket *pixel,ExceptionInfo *exception)
2258%
2259% A description of each parameter follows:
2260%
2261% o image: the image.
2262%
2263% o x,y: These values define the location of the pixel to return.
2264%
2265% o pixel: return a pixel at the specified (x,y) location.
2266%
2267% o exception: return any errors or warnings in this structure.
2268%
2269*/
2270MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,const long x,
2271 const long y,PixelPacket *pixel,ExceptionInfo *exception)
2272{
2273 CacheInfo
2274 *cache_info;
2275
2276 GetOneAuthenticPixelFromHandler
2277 get_one_authentic_pixel_from_handler;
2278
2279 MagickBooleanType
2280 status;
2281
2282 assert(image != (Image *) NULL);
2283 assert(image->signature == MagickSignature);
2284 if (image->debug != MagickFalse)
2285 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2286 assert(image->cache != (Cache) NULL);
2287 cache_info=(CacheInfo *) image->cache;
2288 assert(cache_info->signature == MagickSignature);
2289 *pixel=image->background_color;
2290 get_one_authentic_pixel_from_handler=
2291 cache_info->methods.get_one_authentic_pixel_from_handler;
2292 if (get_one_authentic_pixel_from_handler ==
2293 (GetOneAuthenticPixelFromHandler) NULL)
2294 return(MagickFalse);
2295 status=cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2296 pixel,exception);
2297 return(status);
2298}
2299
2300/*
2301%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2302% %
2303% %
2304% %
2305+ 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 %
2306% %
2307% %
2308% %
2309%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2310%
2311% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2312% location. The image background color is returned if an error occurs.
2313%
2314% The format of the GetOneAuthenticPixelFromCache() method is:
2315%
2316% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
2317% const long x,const long y,PixelPacket *pixel,ExceptionInfo *exception)
2318%
2319% A description of each parameter follows:
2320%
2321% o image: the image.
2322%
2323% o x,y: These values define the location of the pixel to return.
2324%
2325% o pixel: return a pixel at the specified (x,y) location.
2326%
2327% o exception: return any errors or warnings in this structure.
2328%
2329*/
2330static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
2331 const long x,const long y,PixelPacket *pixel,ExceptionInfo *exception)
2332{
2333 PixelPacket
2334 *pixels;
2335
2336 if (image->debug != MagickFalse)
2337 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2338 *pixel=image->background_color;
2339 pixels=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2340 if (pixels == (PixelPacket *) NULL)
2341 return(MagickFalse);
2342 *pixel=(*pixels);
2343 return(MagickTrue);
2344}
2345
2346/*
2347%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2348% %
2349% %
2350% %
2351% G e t O n e V i r t u a l M a g i c k P i x e l %
2352% %
2353% %
2354% %
2355%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2356%
2357% GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2358% location. The image background color is returned if an error occurs. If
2359% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2360%
2361% The format of the GetOneVirtualMagickPixel() method is:
2362%
2363% MagickBooleanType GetOneVirtualMagickPixel(const Image image,
2364% const long x,const long y,MagickPixelPacket *pixel,
2365% ExceptionInfo exception)
2366%
2367% A description of each parameter follows:
2368%
2369% o image: the image.
2370%
2371% o x,y: these values define the location of the pixel to return.
2372%
2373% o pixel: return a pixel at the specified (x,y) location.
2374%
2375% o exception: return any errors or warnings in this structure.
2376%
2377*/
2378MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
2379 const long x,const long y,MagickPixelPacket *pixel,ExceptionInfo *exception)
2380{
2381 CacheInfo
2382 *cache_info;
2383
2384 register const IndexPacket
2385 *indexes;
2386
2387 register const PixelPacket
2388 *p;
2389
2390 assert(image != (const Image *) NULL);
2391 assert(image->signature == MagickSignature);
2392 assert(image->cache != (Cache) NULL);
2393 cache_info=(CacheInfo *) image->cache;
2394 assert(cache_info->signature == MagickSignature);
2395 GetMagickPixelPacket(image,pixel);
2396 p=GetVirtualPixelCache(image,GetPixelCacheVirtualMethod(image),x,y,1,1,
2397 exception);
2398 if (p == (const PixelPacket *) NULL)
2399 return(MagickFalse);
2400 indexes=GetVirtualIndexQueue(image);
2401 SetMagickPixelPacket(image,p,indexes,pixel);
2402 return(MagickTrue);
2403}
2404
2405/*
2406%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2407% %
2408% %
2409% %
2410% G e t O n e V i r t u a l M e t h o d P i x e l %
2411% %
2412% %
2413% %
2414%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2415%
2416% GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2417% location as defined by specified pixel method. The image background color
2418% is returned if an error occurs. If you plan to modify the pixel, use
2419% GetOneAuthenticPixel() instead.
2420%
2421% The format of the GetOneVirtualMethodPixel() method is:
2422%
2423% MagickBooleanType GetOneVirtualMethodPixel(const Image image,
2424% const VirtualPixelMethod virtual_pixel_method,const long x,
2425% const long y,Pixelpacket *pixel,ExceptionInfo exception)
2426%
2427% A description of each parameter follows:
2428%
2429% o image: the image.
2430%
2431% o virtual_pixel_method: the virtual pixel method.
2432%
2433% o x,y: These values define the location of the pixel to return.
2434%
2435% o pixel: return a pixel at the specified (x,y) location.
2436%
2437% o exception: return any errors or warnings in this structure.
2438%
2439*/
2440MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
2441 const VirtualPixelMethod virtual_pixel_method,const long x,const long y,
2442 PixelPacket *pixel,ExceptionInfo *exception)
2443{
2444 GetOneVirtualPixelFromHandler
2445 get_one_virtual_pixel_from_handler;
2446
2447 CacheInfo
2448 *cache_info;
2449
2450 MagickBooleanType
2451 status;
2452
2453 assert(image != (const Image *) NULL);
2454 assert(image->signature == MagickSignature);
2455 assert(image->cache != (Cache) NULL);
2456 cache_info=(CacheInfo *) image->cache;
2457 assert(cache_info->signature == MagickSignature);
2458 *pixel=image->background_color;
2459 get_one_virtual_pixel_from_handler=
2460 cache_info->methods.get_one_virtual_pixel_from_handler;
2461 if (get_one_virtual_pixel_from_handler ==
2462 (GetOneVirtualPixelFromHandler) NULL)
2463 return(MagickFalse);
2464 status=get_one_virtual_pixel_from_handler(image,virtual_pixel_method,x,y,
2465 pixel,exception);
2466 return(status);
2467}
2468
2469/*
2470%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2471% %
2472% %
2473% %
2474% G e t O n e V i r t u a l P i x e l %
2475% %
2476% %
2477% %
2478%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2479%
2480% GetOneVirtualPixel() returns a single virtual pixel at the specified
2481% (x,y) location. The image background color is returned if an error occurs.
2482% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2483%
2484% The format of the GetOneVirtualPixel() method is:
2485%
2486% MagickBooleanType GetOneVirtualPixel(const Image image,const long x,
2487% const long y,PixelPacket *pixel,ExceptionInfo exception)
2488%
2489% A description of each parameter follows:
2490%
2491% o image: the image.
2492%
2493% o x,y: These values define the location of the pixel to return.
2494%
2495% o pixel: return a pixel at the specified (x,y) location.
2496%
2497% o exception: return any errors or warnings in this structure.
2498%
2499*/
2500MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
2501 const long x,const long y,PixelPacket *pixel,ExceptionInfo *exception)
2502{
2503 GetOneVirtualPixelFromHandler
2504 get_one_virtual_pixel_from_handler;
2505
2506 CacheInfo
2507 *cache_info;
2508
2509 MagickBooleanType
2510 status;
2511
2512 assert(image != (const Image *) NULL);
2513 assert(image->signature == MagickSignature);
2514 assert(image->cache != (Cache) NULL);
2515 cache_info=(CacheInfo *) image->cache;
2516 assert(cache_info->signature == MagickSignature);
2517 *pixel=image->background_color;
2518 get_one_virtual_pixel_from_handler=
2519 cache_info->methods.get_one_virtual_pixel_from_handler;
2520 if (get_one_virtual_pixel_from_handler ==
2521 (GetOneVirtualPixelFromHandler) NULL)
2522 return(MagickFalse);
2523 status=get_one_virtual_pixel_from_handler(image,GetPixelCacheVirtualMethod(
2524 image),x,y,pixel,exception);
2525 return(status);
2526}
2527
2528/*
2529%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2530% %
2531% %
2532% %
2533+ 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 %
2534% %
2535% %
2536% %
2537%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2538%
2539% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2540% specified (x,y) location. The image background color is returned if an
2541% error occurs.
2542%
2543% The format of the GetOneVirtualPixelFromCache() method is:
2544%
2545% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
2546% const VirtualPixelPacket method,const long x,const long y,
2547% PixelPacket *pixel,ExceptionInfo *exception)
2548%
2549% A description of each parameter follows:
2550%
2551% o image: the image.
2552%
2553% o virtual_pixel_method: the virtual pixel method.
2554%
2555% o x,y: These values define the location of the pixel to return.
2556%
2557% o pixel: return a pixel at the specified (x,y) location.
2558%
2559% o exception: return any errors or warnings in this structure.
2560%
2561*/
2562static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
2563 const VirtualPixelMethod virtual_pixel_method,const long x,const long y,
2564 PixelPacket *pixel,ExceptionInfo *exception)
2565{
2566 const PixelPacket
2567 *pixels;
2568
2569 *pixel=image->background_color;
2570 pixels=GetVirtualPixelCache(image,virtual_pixel_method,x,y,1UL,1UL,exception);
2571 if (pixels == (const PixelPacket *) NULL)
2572 return(MagickFalse);
2573 *pixel=(*pixels);
2574 return(MagickTrue);
2575}
2576
2577/*
2578%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2579% %
2580% %
2581% %
2582+ G e t P i x e l C a c h e C o l o r s p a c e %
2583% %
2584% %
2585% %
2586%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2587%
2588% GetPixelCacheColorspace() returns the class type of the pixel cache.
2589%
2590% The format of the GetPixelCacheColorspace() method is:
2591%
2592% Colorspace GetPixelCacheColorspace(Cache cache)
2593%
2594% A description of each parameter follows:
2595%
2596% o cache: the pixel cache.
2597%
2598*/
2599MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
2600{
2601 CacheInfo
2602 *cache_info;
2603
2604 assert(cache != (Cache) NULL);
2605 cache_info=(CacheInfo *) cache;
2606 assert(cache_info->signature == MagickSignature);
2607 if (cache_info->debug != MagickFalse)
2608 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2609 cache_info->filename);
2610 return(cache_info->colorspace);
2611}
2612
2613/*
2614%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2615% %
2616% %
2617% %
2618+ G e t P i x e l C a c h e M e t h o d s %
2619% %
2620% %
2621% %
2622%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2623%
2624% GetPixelCacheMethods() initializes the CacheMethods structure.
2625%
2626% The format of the GetPixelCacheMethods() method is:
2627%
2628% void GetPixelCacheMethods(CacheMethods *cache_methods)
2629%
2630% A description of each parameter follows:
2631%
2632% o cache_methods: Specifies a pointer to a CacheMethods structure.
2633%
2634*/
2635MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
2636{
2637 assert(cache_methods != (CacheMethods *) NULL);
2638 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2639 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2640 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2641 cache_methods->get_virtual_indexes_from_handler=GetVirtualIndexesFromCache;
2642 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2643 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2644 cache_methods->get_authentic_indexes_from_handler=
2645 GetAuthenticIndexesFromCache;
2646 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2647 cache_methods->get_one_authentic_pixel_from_handler=
2648 GetOneAuthenticPixelFromCache;
2649 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2650 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2651 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2652}
2653
2654/*
2655%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2656% %
2657% %
2658% %
2659+ G e t P i x e l C a c h e N e x u s E x t e n t %
2660% %
2661% %
2662% %
2663%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2664%
2665% GetPixelCacheNexusExtent() returns the extent of the pixels associated with
2666% the last call to SetPixelCacheNexusPixels() or GetPixelCacheNexusPixels().
2667%
2668% The format of the GetPixelCacheNexusExtent() method is:
2669%
2670% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2671% NexusInfo *nexus_info)
2672%
2673% A description of each parameter follows:
2674%
2675% o nexus_info: the nexus info.
2676%
2677*/
2678MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2679 NexusInfo *nexus_info)
2680{
2681 CacheInfo
2682 *cache_info;
2683
2684 MagickSizeType
2685 extent;
2686
2687 if (cache == (Cache) NULL)
2688 return(0);
2689 cache_info=(CacheInfo *) cache;
2690 assert(cache_info->signature == MagickSignature);
2691 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2692 if (extent == 0)
2693 return((MagickSizeType) cache_info->columns*cache_info->rows);
2694 return(extent);
2695}
2696
2697/*
2698%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2699% %
2700% %
2701% %
2702+ 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 %
2703% %
2704% %
2705% %
2706%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2707%
2708% GetPixelCacheNexusIndexes() returns the indexes associated with the
2709% specified cache nexus.
2710%
2711% The format of the GetPixelCacheNexusIndexes() method is:
2712%
2713% IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2714% NexusInfo *nexus_info)
2715%
2716% A description of each parameter follows:
2717%
2718% o cache: the pixel cache.
2719%
2720% o nexus_info: the cache nexus to return the colormap indexes.
2721%
2722*/
2723MagickExport IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2724 NexusInfo *nexus_info)
2725{
2726 CacheInfo
2727 *cache_info;
2728
2729 if (cache == (Cache) NULL)
2730 return((IndexPacket *) NULL);
2731 cache_info=(CacheInfo *) cache;
2732 assert(cache_info->signature == MagickSignature);
2733 if (cache_info->storage_class == UndefinedClass)
2734 return((IndexPacket *) NULL);
2735 return(nexus_info->indexes);
2736}
2737
2738/*
2739%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2740% %
2741% %
2742% %
2743+ G e t P i x e l C a c h e N e x u s P i x e l s %
2744% %
2745% %
2746% %
2747%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2748%
2749% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2750% cache nexus.
2751%
2752% The format of the GetPixelCacheNexusPixels() method is:
2753%
2754% PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2755% NexusInfo *nexus_info)
2756%
2757% A description of each parameter follows:
2758%
2759% o cache: the pixel cache.
2760%
2761% o nexus_info: the cache nexus to return the pixels.
2762%
2763*/
2764MagickExport PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2765 NexusInfo *nexus_info)
2766{
2767 CacheInfo
2768 *cache_info;
2769
2770 if (cache == (Cache) NULL)
2771 return((PixelPacket *) NULL);
2772 cache_info=(CacheInfo *) cache;
2773 assert(cache_info->signature == MagickSignature);
2774 if (cache_info->debug != MagickFalse)
2775 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2776 cache_info->filename);
2777 if (cache_info->storage_class == UndefinedClass)
2778 return((PixelPacket *) NULL);
2779 return(nexus_info->pixels);
2780}
2781
2782/*
2783%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2784% %
2785% %
2786% %
cristy056ba772010-01-02 23:33:54 +00002787+ G e t P i x e l C a c h e P i x e l s %
2788% %
2789% %
2790% %
2791%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2792%
2793% GetPixelCachePixels() returns the pixels associated with the specified image.
2794%
2795% The format of the GetPixelCachePixels() method is:
2796%
cristyf84a1932010-01-03 18:00:18 +00002797% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2798% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002799%
2800% A description of each parameter follows:
2801%
2802% o image: the image.
2803%
2804% o length: the pixel cache length.
2805%
cristyf84a1932010-01-03 18:00:18 +00002806% o exception: return any errors or warnings in this structure.
2807%
cristy056ba772010-01-02 23:33:54 +00002808*/
cristyf84a1932010-01-03 18:00:18 +00002809MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2810 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002811{
2812 CacheInfo
2813 *cache_info;
2814
2815 assert(image != (const Image *) NULL);
2816 assert(image->signature == MagickSignature);
2817 if (image->debug != MagickFalse)
2818 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2819 assert(image->cache != (Cache) NULL);
cristyc4c8d132010-01-07 01:58:38 +00002820 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
cristy056ba772010-01-02 23:33:54 +00002821 assert(cache_info->signature == MagickSignature);
2822 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002823 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002824 return((void *) NULL);
2825 *length=cache_info->length;
2826 return((void *) cache_info->pixels);
2827}
2828
2829/*
2830%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2831% %
2832% %
2833% %
cristyb32b90a2009-09-07 21:45:48 +00002834+ 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 +00002835% %
2836% %
2837% %
2838%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2839%
2840% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2841%
2842% The format of the GetPixelCacheStorageClass() method is:
2843%
2844% ClassType GetPixelCacheStorageClass(Cache cache)
2845%
2846% A description of each parameter follows:
2847%
2848% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2849%
2850% o cache: the pixel cache.
2851%
2852*/
2853MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
2854{
2855 CacheInfo
2856 *cache_info;
2857
2858 assert(cache != (Cache) NULL);
2859 cache_info=(CacheInfo *) cache;
2860 assert(cache_info->signature == MagickSignature);
2861 if (cache_info->debug != MagickFalse)
2862 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2863 cache_info->filename);
2864 return(cache_info->storage_class);
2865}
2866
2867/*
2868%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2869% %
2870% %
2871% %
cristyb32b90a2009-09-07 21:45:48 +00002872+ G e t P i x e l C a c h e T i l e S i z e %
2873% %
2874% %
2875% %
2876%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2877%
2878% GetPixelCacheTileSize() returns the pixel cache tile size.
2879%
2880% The format of the GetPixelCacheTileSize() method is:
2881%
2882% void GetPixelCacheTileSize(const Image *image,unsigned long *width,
2883% unsigned long *height)
2884%
2885% A description of each parameter follows:
2886%
2887% o image: the image.
2888%
2889% o width: the optimize cache tile width in pixels.
2890%
2891% o height: the optimize cache tile height in pixels.
2892%
2893*/
2894MagickExport void GetPixelCacheTileSize(const Image *image,unsigned long *width,
2895 unsigned long *height)
2896{
2897 CacheInfo
2898 *cache_info;
2899
2900 assert(image != (Image *) NULL);
2901 assert(image->signature == MagickSignature);
2902 if (image->debug != MagickFalse)
2903 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2904 assert(image->cache != (Cache) NULL);
2905 cache_info=(CacheInfo *) image->cache;
2906 assert(cache_info->signature == MagickSignature);
2907 *width=2048UL/sizeof(PixelPacket);
2908 if (GetPixelCacheType(image) == DiskCache)
cristydaa97692009-09-13 02:10:35 +00002909 *width=8192UL/sizeof(PixelPacket);
cristyb32b90a2009-09-07 21:45:48 +00002910 *height=(*width);
2911}
2912
2913/*
2914%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2915% %
2916% %
2917% %
2918+ G e t P i x e l C a c h e T y p e %
2919% %
2920% %
2921% %
2922%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2923%
2924% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2925%
2926% The format of the GetPixelCacheType() method is:
2927%
2928% CacheType GetPixelCacheType(const Image *image)
2929%
2930% A description of each parameter follows:
2931%
2932% o image: the image.
2933%
2934*/
2935MagickExport CacheType GetPixelCacheType(const Image *image)
2936{
2937 CacheInfo
2938 *cache_info;
2939
2940 assert(image != (Image *) NULL);
2941 assert(image->signature == MagickSignature);
2942 if (image->debug != MagickFalse)
2943 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2944 assert(image->cache != (Cache) NULL);
2945 cache_info=(CacheInfo *) image->cache;
2946 assert(cache_info->signature == MagickSignature);
2947 return(cache_info->type);
2948}
2949
2950/*
2951%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2952% %
2953% %
2954% %
cristy3ed852e2009-09-05 21:47:34 +00002955+ 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 %
2956% %
2957% %
2958% %
2959%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2960%
2961% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2962% pixel cache. A virtual pixel is any pixel access that is outside the
2963% boundaries of the image cache.
2964%
2965% The format of the GetPixelCacheVirtualMethod() method is:
2966%
2967% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2968%
2969% A description of each parameter follows:
2970%
2971% o image: the image.
2972%
2973*/
2974MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2975{
2976 CacheInfo
2977 *cache_info;
2978
2979 assert(image != (Image *) NULL);
2980 assert(image->signature == MagickSignature);
2981 if (image->debug != MagickFalse)
2982 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2983 assert(image->cache != (Cache) NULL);
2984 cache_info=(CacheInfo *) image->cache;
2985 assert(cache_info->signature == MagickSignature);
2986 return(cache_info->virtual_pixel_method);
2987}
2988
2989/*
2990%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2991% %
2992% %
2993% %
2994+ 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 %
2995% %
2996% %
2997% %
2998%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2999%
3000% GetVirtualIndexesFromCache() returns the indexes associated with the last
3001% call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3002%
3003% The format of the GetVirtualIndexesFromCache() method is:
3004%
3005% IndexPacket *GetVirtualIndexesFromCache(const Image *image)
3006%
3007% A description of each parameter follows:
3008%
3009% o image: the image.
3010%
3011*/
3012static const IndexPacket *GetVirtualIndexesFromCache(const Image *image)
3013{
3014 CacheInfo
3015 *cache_info;
3016
3017 const IndexPacket
3018 *indexes;
3019
3020 long
3021 id;
3022
3023 if (image->debug != MagickFalse)
3024 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3025 cache_info=(CacheInfo *) image->cache;
3026 id=GetOpenMPThreadId();
3027 assert(id < (long) cache_info->number_threads);
3028 indexes=GetVirtualIndexesFromNexus(image->cache,cache_info->nexus_info[id]);
3029 return(indexes);
3030}
3031
3032/*
3033%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3034% %
3035% %
3036% %
3037+ 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 %
3038% %
3039% %
3040% %
3041%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3042%
3043% GetVirtualIndexesFromNexus() returns the indexes associated with the
3044% specified cache nexus.
3045%
3046% The format of the GetVirtualIndexesFromNexus() method is:
3047%
3048% const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
3049% NexusInfo *nexus_info)
3050%
3051% A description of each parameter follows:
3052%
3053% o cache: the pixel cache.
3054%
3055% o nexus_info: the cache nexus to return the colormap indexes.
3056%
3057*/
3058MagickExport const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
3059 NexusInfo *nexus_info)
3060{
3061 CacheInfo
3062 *cache_info;
3063
3064 if (cache == (Cache) NULL)
3065 return((IndexPacket *) NULL);
3066 cache_info=(CacheInfo *) cache;
3067 assert(cache_info->signature == MagickSignature);
3068 if (cache_info->storage_class == UndefinedClass)
3069 return((IndexPacket *) NULL);
3070 return(nexus_info->indexes);
3071}
3072
3073/*
3074%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3075% %
3076% %
3077% %
3078% G e t V i r t u a l I n d e x Q u e u e %
3079% %
3080% %
3081% %
3082%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3083%
3084% GetVirtualIndexQueue() returns the virtual black channel or the
3085% colormap indexes associated with the last call to QueueAuthenticPixels() or
3086% GetVirtualPixels(). NULL is returned if the black channel or colormap
3087% indexes are not available.
3088%
3089% The format of the GetVirtualIndexQueue() method is:
3090%
3091% const IndexPacket *GetVirtualIndexQueue(const Image *image)
3092%
3093% A description of each parameter follows:
3094%
3095% o image: the image.
3096%
3097*/
3098MagickExport const IndexPacket *GetVirtualIndexQueue(const Image *image)
3099{
3100 CacheInfo
3101 *cache_info;
3102
3103 assert(image != (const Image *) NULL);
3104 assert(image->signature == MagickSignature);
3105 if (image->debug != MagickFalse)
3106 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3107 assert(image->cache != (Cache) NULL);
3108 cache_info=(CacheInfo *) image->cache;
3109 assert(cache_info->signature == MagickSignature);
3110 if (cache_info->methods.get_virtual_indexes_from_handler ==
3111 (GetVirtualIndexesFromHandler) NULL)
3112 return((IndexPacket *) NULL);
3113 return(cache_info->methods.get_virtual_indexes_from_handler(image));
3114}
3115
3116/*
3117%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3118% %
3119% %
3120% %
3121+ 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 %
3122% %
3123% %
3124% %
3125%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3126%
3127% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3128% pixel cache as defined by the geometry parameters. A pointer to the pixels
3129% is returned if the pixels are transferred, otherwise a NULL is returned.
3130%
3131% The format of the GetVirtualPixelsFromNexus() method is:
3132%
3133% PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
3134% const VirtualPixelMethod method,const long x,const long y,
3135% const unsigned long columns,const unsigned long rows,
3136% NexusInfo *nexus_info,ExceptionInfo *exception)
3137%
3138% A description of each parameter follows:
3139%
3140% o image: the image.
3141%
3142% o virtual_pixel_method: the virtual pixel method.
3143%
3144% o x,y,columns,rows: These values define the perimeter of a region of
3145% pixels.
3146%
3147% o nexus_info: the cache nexus to acquire.
3148%
3149% o exception: return any errors or warnings in this structure.
3150%
3151*/
3152
3153static long
3154 DitherMatrix[64] =
3155 {
3156 0, 48, 12, 60, 3, 51, 15, 63,
3157 32, 16, 44, 28, 35, 19, 47, 31,
3158 8, 56, 4, 52, 11, 59, 7, 55,
3159 40, 24, 36, 20, 43, 27, 39, 23,
3160 2, 50, 14, 62, 1, 49, 13, 61,
3161 34, 18, 46, 30, 33, 17, 45, 29,
3162 10, 58, 6, 54, 9, 57, 5, 53,
3163 42, 26, 38, 22, 41, 25, 37, 21
3164 };
3165
cristy222528c2010-01-09 23:36:34 +00003166static inline long DitherX(const long x,const unsigned long columns)
cristy3ed852e2009-09-05 21:47:34 +00003167{
3168 long
3169 index;
3170
3171 index=x+DitherMatrix[x & 0x07]-32L;
3172 if (index < 0L)
3173 return(0L);
3174 if (index >= (long) columns)
3175 return((long) columns-1L);
3176 return(index);
3177}
3178
cristy222528c2010-01-09 23:36:34 +00003179static inline long DitherY(const long y,const unsigned long rows)
cristy3ed852e2009-09-05 21:47:34 +00003180{
3181 long
3182 index;
3183
3184 index=y+DitherMatrix[y & 0x07]-32L;
3185 if (index < 0L)
3186 return(0L);
3187 if (index >= (long) rows)
3188 return((long) rows-1L);
3189 return(index);
3190}
3191
cristy222528c2010-01-09 23:36:34 +00003192static inline long EdgeX(const long x,const unsigned long columns)
cristy3ed852e2009-09-05 21:47:34 +00003193{
3194 if (x < 0L)
3195 return(0L);
3196 if (x >= (long) columns)
cristy97be2b92010-01-09 23:37:55 +00003197 return((long) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003198 return(x);
3199}
3200
cristy222528c2010-01-09 23:36:34 +00003201static inline long EdgeY(const long y,const unsigned long rows)
cristy3ed852e2009-09-05 21:47:34 +00003202{
3203 if (y < 0L)
3204 return(0L);
3205 if (y >= (long) rows)
cristy97be2b92010-01-09 23:37:55 +00003206 return((long) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003207 return(y);
3208}
3209
cristy222528c2010-01-09 23:36:34 +00003210static inline long RandomX(RandomInfo *random_info,const unsigned long columns)
cristy3ed852e2009-09-05 21:47:34 +00003211{
3212 return((long) (columns*GetPseudoRandomValue(random_info)));
3213}
3214
cristy222528c2010-01-09 23:36:34 +00003215static inline long RandomY(RandomInfo *random_info,const unsigned long rows)
cristy3ed852e2009-09-05 21:47:34 +00003216{
3217 return((long) (rows*GetPseudoRandomValue(random_info)));
3218}
3219
3220/*
3221 VirtualPixelModulo() computes the remainder of dividing offset by extent. It
3222 returns not only the quotient (tile the offset falls in) but also the positive
3223 remainer within that tile such that 0 <= remainder < extent. This method is
3224 essentially a ldiv() using a floored modulo division rather than the normal
3225 default truncated modulo division.
3226*/
3227static inline MagickModulo VirtualPixelModulo(const long offset,
3228 const unsigned long extent)
3229{
3230 MagickModulo
3231 modulo;
3232
3233 modulo.quotient=offset/(long) extent;
3234 if (offset < 0L)
3235 modulo.quotient--;
3236 modulo.remainder=offset-modulo.quotient*(long) extent;
3237 return(modulo);
3238}
3239
3240MagickExport const PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
3241 const VirtualPixelMethod virtual_pixel_method,const long x,const long y,
3242 const unsigned long columns,const unsigned long rows,NexusInfo *nexus_info,
3243 ExceptionInfo *exception)
3244{
3245 CacheInfo
3246 *cache_info;
3247
3248 MagickOffsetType
3249 offset;
3250
3251 MagickSizeType
3252 length,
3253 number_pixels;
3254
3255 NexusInfo
3256 **virtual_nexus;
3257
3258 PixelPacket
3259 *pixels,
3260 virtual_pixel;
3261
3262 RectangleInfo
3263 region;
3264
3265 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003266 *restrict nexus_indexes;
cristy3ed852e2009-09-05 21:47:34 +00003267
3268 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003269 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003270
3271 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003272 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003273
3274 register long
3275 u,
3276 v;
3277
3278 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003279 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003280
3281 /*
3282 Acquire pixels.
3283 */
3284 if (image->debug != MagickFalse)
3285 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3286 cache_info=(CacheInfo *) image->cache;
3287 if (cache_info->type == UndefinedCache)
3288 return((const PixelPacket *) NULL);
3289 region.x=x;
3290 region.y=y;
3291 region.width=columns;
3292 region.height=rows;
3293 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
3294 if (pixels == (PixelPacket *) NULL)
3295 return((const PixelPacket *) NULL);
3296 offset=(MagickOffsetType) region.y*cache_info->columns+region.x;
cristy4789f0d2010-01-10 00:01:06 +00003297 length=(MagickSizeType) (region.height-1L)*cache_info->columns+
3298 region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003299 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3300 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
3301 if ((x >= 0) && ((long) (x+columns) <= (long) cache_info->columns) &&
3302 (y >= 0) && ((long) (y+rows) <= (long) cache_info->rows))
3303 {
3304 MagickBooleanType
3305 status;
3306
3307 /*
3308 Pixel request is inside cache extents.
3309 */
3310 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
3311 return(pixels);
3312 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3313 if (status == MagickFalse)
3314 return((const PixelPacket *) NULL);
3315 if ((cache_info->storage_class == PseudoClass) ||
3316 (cache_info->colorspace == CMYKColorspace))
3317 {
3318 status=ReadPixelCacheIndexes(cache_info,nexus_info,exception);
3319 if (status == MagickFalse)
3320 return((const PixelPacket *) NULL);
3321 }
3322 return(pixels);
3323 }
3324 /*
3325 Pixel request is outside cache extents.
3326 */
3327 q=pixels;
3328 indexes=GetPixelCacheNexusIndexes(cache_info,nexus_info);
3329 virtual_nexus=AcquirePixelCacheNexus(1);
3330 if (virtual_nexus == (NexusInfo **) NULL)
3331 {
3332 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3333 "UnableToGetCacheNexus","`%s'",image->filename);
3334 return((const PixelPacket *) NULL);
3335 }
3336 switch (virtual_pixel_method)
3337 {
3338 case BlackVirtualPixelMethod:
3339 {
cristy4789f0d2010-01-10 00:01:06 +00003340 SetRedPixelComponent(&virtual_pixel,0);
3341 SetGreenPixelComponent(&virtual_pixel,0);
3342 SetBluePixelComponent(&virtual_pixel,0);
3343 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003344 break;
3345 }
3346 case GrayVirtualPixelMethod:
3347 {
cristy4789f0d2010-01-10 00:01:06 +00003348 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3349 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3350 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3351 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003352 break;
3353 }
3354 case TransparentVirtualPixelMethod:
3355 {
cristy4789f0d2010-01-10 00:01:06 +00003356 SetRedPixelComponent(&virtual_pixel,0);
3357 SetGreenPixelComponent(&virtual_pixel,0);
3358 SetBluePixelComponent(&virtual_pixel,0);
3359 SetOpacityPixelComponent(&virtual_pixel,TransparentOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003360 break;
3361 }
3362 case MaskVirtualPixelMethod:
3363 case WhiteVirtualPixelMethod:
3364 {
cristy4789f0d2010-01-10 00:01:06 +00003365 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3366 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3367 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3368 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003369 break;
3370 }
3371 default:
3372 {
3373 virtual_pixel=image->background_color;
3374 break;
3375 }
3376 }
3377 for (v=0; v < (long) rows; v++)
3378 {
3379 for (u=0; u < (long) columns; u+=length)
3380 {
3381 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
3382 if ((((x+u) < 0) || ((x+u) >= (long) cache_info->columns)) ||
3383 (((y+v) < 0) || ((y+v) >= (long) cache_info->rows)) || (length == 0))
3384 {
3385 MagickModulo
3386 x_modulo,
3387 y_modulo;
3388
3389 /*
3390 Transfer a single pixel.
3391 */
3392 length=(MagickSizeType) 1;
3393 switch (virtual_pixel_method)
3394 {
3395 case BackgroundVirtualPixelMethod:
3396 case ConstantVirtualPixelMethod:
3397 case BlackVirtualPixelMethod:
3398 case GrayVirtualPixelMethod:
3399 case TransparentVirtualPixelMethod:
3400 case MaskVirtualPixelMethod:
3401 case WhiteVirtualPixelMethod:
3402 {
3403 p=(&virtual_pixel);
3404 break;
3405 }
3406 case EdgeVirtualPixelMethod:
3407 default:
3408 {
3409 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003410 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003411 1UL,1UL,virtual_nexus[0],exception);
3412 break;
3413 }
3414 case RandomVirtualPixelMethod:
3415 {
3416 if (cache_info->random_info == (RandomInfo *) NULL)
3417 cache_info->random_info=AcquireRandomInfo();
3418 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003419 RandomX(cache_info->random_info,cache_info->columns),
3420 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003421 virtual_nexus[0],exception);
3422 break;
3423 }
3424 case DitherVirtualPixelMethod:
3425 {
3426 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003427 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003428 1UL,1UL,virtual_nexus[0],exception);
3429 break;
3430 }
3431 case TileVirtualPixelMethod:
3432 {
3433 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3434 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3435 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3436 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3437 exception);
3438 break;
3439 }
3440 case MirrorVirtualPixelMethod:
3441 {
3442 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3443 if ((x_modulo.quotient & 0x01) == 1L)
3444 x_modulo.remainder=(long) cache_info->columns-
3445 x_modulo.remainder-1L;
3446 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3447 if ((y_modulo.quotient & 0x01) == 1L)
3448 y_modulo.remainder=(long) cache_info->rows-
3449 y_modulo.remainder-1L;
3450 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3451 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3452 exception);
3453 break;
3454 }
3455 case CheckerTileVirtualPixelMethod:
3456 {
3457 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3458 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3459 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3460 {
3461 p=(&virtual_pixel);
3462 break;
3463 }
3464 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3465 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3466 exception);
3467 break;
3468 }
3469 case HorizontalTileVirtualPixelMethod:
3470 {
3471 if (((y+v) < 0) || ((y+v) >= (long) cache_info->rows))
3472 {
3473 p=(&virtual_pixel);
3474 break;
3475 }
3476 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3477 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3478 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3479 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3480 exception);
3481 break;
3482 }
3483 case VerticalTileVirtualPixelMethod:
3484 {
3485 if (((x+u) < 0) || ((x+u) >= (long) cache_info->columns))
3486 {
3487 p=(&virtual_pixel);
3488 break;
3489 }
3490 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3491 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3492 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3493 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3494 exception);
3495 break;
3496 }
3497 case HorizontalTileEdgeVirtualPixelMethod:
3498 {
3499 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3500 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003501 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003502 virtual_nexus[0],exception);
3503 break;
3504 }
3505 case VerticalTileEdgeVirtualPixelMethod:
3506 {
3507 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3508 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003509 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003510 virtual_nexus[0],exception);
3511 break;
3512 }
3513 }
3514 if (p == (const PixelPacket *) NULL)
3515 break;
3516 *q++=(*p);
3517 if (indexes != (IndexPacket *) NULL)
3518 {
3519 nexus_indexes=GetVirtualIndexesFromNexus(cache_info,
3520 virtual_nexus[0]);
3521 if (nexus_indexes != (const IndexPacket *) NULL)
3522 *indexes++=(*nexus_indexes);
3523 }
3524 continue;
3525 }
3526 /*
3527 Transfer a run of pixels.
3528 */
3529 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,
3530 (unsigned long) length,1UL,virtual_nexus[0],exception);
3531 if (p == (const PixelPacket *) NULL)
3532 break;
3533 (void) CopyMagickMemory(q,p,(size_t) length*sizeof(*p));
3534 q+=length;
3535 if (indexes != (IndexPacket *) NULL)
3536 {
3537 nexus_indexes=GetVirtualIndexesFromNexus(cache_info,virtual_nexus[0]);
3538 if (nexus_indexes != (const IndexPacket *) NULL)
3539 {
3540 (void) CopyMagickMemory(indexes,nexus_indexes,(size_t) length*
3541 sizeof(*nexus_indexes));
3542 indexes+=length;
3543 }
3544 }
3545 }
3546 }
3547 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3548 return(pixels);
3549}
3550
3551/*
3552%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3553% %
3554% %
3555% %
3556+ G e t V i r t u a l P i x e l C a c h e %
3557% %
3558% %
3559% %
3560%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3561%
3562% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3563% cache as defined by the geometry parameters. A pointer to the pixels
3564% is returned if the pixels are transferred, otherwise a NULL is returned.
3565%
3566% The format of the GetVirtualPixelCache() method is:
3567%
3568% const PixelPacket *GetVirtualPixelCache(const Image *image,
3569% const VirtualPixelMethod virtual_pixel_method,const long x,
3570% const long y,const unsigned long columns,const unsigned long rows,
3571% ExceptionInfo *exception)
3572%
3573% A description of each parameter follows:
3574%
3575% o image: the image.
3576%
3577% o virtual_pixel_method: the virtual pixel method.
3578%
3579% o x,y,columns,rows: These values define the perimeter of a region of
3580% pixels.
3581%
3582% o exception: return any errors or warnings in this structure.
3583%
3584*/
3585static const PixelPacket *GetVirtualPixelCache(const Image *image,
3586 const VirtualPixelMethod virtual_pixel_method,const long x,const long y,
3587 const unsigned long columns,const unsigned long rows,ExceptionInfo *exception)
3588{
3589 CacheInfo
3590 *cache_info;
3591
3592 const PixelPacket
3593 *pixels;
3594
3595 long
3596 id;
3597
3598 if (image->debug != MagickFalse)
3599 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3600 cache_info=(CacheInfo *) image->cache;
3601 id=GetOpenMPThreadId();
3602 assert(id < (long) cache_info->number_threads);
3603 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3604 cache_info->nexus_info[id],exception);
3605 return(pixels);
3606}
3607
3608/*
3609%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3610% %
3611% %
3612% %
3613% G e t V i r t u a l P i x e l Q u e u e %
3614% %
3615% %
3616% %
3617%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3618%
3619% GetVirtualPixelQueue() returns the virtual pixels associated with the
3620% last call to QueueAuthenticPixels() or GetVirtualPixels().
3621%
3622% The format of the GetVirtualPixelQueue() method is:
3623%
3624% const PixelPacket *GetVirtualPixelQueue(const Image image)
3625%
3626% A description of each parameter follows:
3627%
3628% o image: the image.
3629%
3630*/
3631MagickExport const PixelPacket *GetVirtualPixelQueue(const Image *image)
3632{
3633 CacheInfo
3634 *cache_info;
3635
3636 assert(image != (const Image *) NULL);
3637 assert(image->signature == MagickSignature);
3638 if (image->debug != MagickFalse)
3639 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3640 assert(image->cache != (Cache) NULL);
3641 cache_info=(CacheInfo *) image->cache;
3642 assert(cache_info->signature == MagickSignature);
3643 if (cache_info->methods.get_virtual_pixels_handler ==
3644 (GetVirtualPixelsHandler) NULL)
3645 return((PixelPacket *) NULL);
3646 return(cache_info->methods.get_virtual_pixels_handler(image));
3647}
3648
3649/*
3650%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3651% %
3652% %
3653% %
3654% G e t V i r t u a l P i x e l s %
3655% %
3656% %
3657% %
3658%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3659%
3660% GetVirtualPixels() returns an immutable pixel region. If the
3661% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003662% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003663% copy of the pixels or it may point to the original pixels in memory.
3664% Performance is maximized if the selected region is part of one row, or one
3665% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003666% (without a copy) if the image is in memory, or in a memory-mapped file. The
3667% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003668%
3669% Pixels accessed via the returned pointer represent a simple array of type
3670% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
3671% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to access
3672% the black color component or to obtain the colormap indexes (of type
3673% IndexPacket) corresponding to the region.
3674%
3675% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3676%
3677% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3678% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3679% GetCacheViewAuthenticPixels() instead.
3680%
3681% The format of the GetVirtualPixels() method is:
3682%
3683% const PixelPacket *GetVirtualPixels(const Image *image,const long x,
3684% const long y,const unsigned long columns,const unsigned long rows,
3685% ExceptionInfo *exception)
3686%
3687% A description of each parameter follows:
3688%
3689% o image: the image.
3690%
3691% o x,y,columns,rows: These values define the perimeter of a region of
3692% pixels.
3693%
3694% o exception: return any errors or warnings in this structure.
3695%
3696*/
3697MagickExport const PixelPacket *GetVirtualPixels(const Image *image,
3698 const long x,const long y,const unsigned long columns,
3699 const unsigned long rows,ExceptionInfo *exception)
3700{
3701 CacheInfo
3702 *cache_info;
3703
3704 const PixelPacket
3705 *pixels;
3706
3707 assert(image != (const Image *) NULL);
3708 assert(image->signature == MagickSignature);
3709 if (image->debug != MagickFalse)
3710 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3711 assert(image->cache != (Cache) NULL);
3712 cache_info=(CacheInfo *) image->cache;
3713 assert(cache_info->signature == MagickSignature);
3714 if (cache_info->methods.get_virtual_pixel_handler ==
3715 (GetVirtualPixelHandler) NULL)
3716 return((const PixelPacket *) NULL);
3717 pixels=cache_info->methods.get_virtual_pixel_handler(image,
3718 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception);
3719 return(pixels);
3720}
3721
3722/*
3723%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3724% %
3725% %
3726% %
3727+ 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 %
3728% %
3729% %
3730% %
3731%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3732%
3733% GetVirtualPixelsCache() returns the pixels associated with the last call
3734% to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3735%
3736% The format of the GetVirtualPixelsCache() method is:
3737%
3738% PixelPacket *GetVirtualPixelsCache(const Image *image)
3739%
3740% A description of each parameter follows:
3741%
3742% o image: the image.
3743%
3744*/
3745static const PixelPacket *GetVirtualPixelsCache(const Image *image)
3746{
3747 CacheInfo
3748 *cache_info;
3749
3750 const PixelPacket
3751 *pixels;
3752
3753 long
3754 id;
3755
3756 if (image->debug != MagickFalse)
3757 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3758 cache_info=(CacheInfo *) image->cache;
3759 id=GetOpenMPThreadId();
3760 assert(id < (long) cache_info->number_threads);
3761 pixels=GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]);
3762 return(pixels);
3763}
3764
3765/*
3766%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3767% %
3768% %
3769% %
3770+ G e t V i r t u a l P i x e l s N e x u s %
3771% %
3772% %
3773% %
3774%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3775%
3776% GetVirtualPixelsNexus() returns the pixels associated with the specified
3777% cache nexus.
3778%
3779% The format of the GetVirtualPixelsNexus() method is:
3780%
3781% const IndexPacket *GetVirtualPixelsNexus(const Cache cache,
3782% NexusInfo *nexus_info)
3783%
3784% A description of each parameter follows:
3785%
3786% o cache: the pixel cache.
3787%
3788% o nexus_info: the cache nexus to return the colormap pixels.
3789%
3790*/
3791MagickExport const PixelPacket *GetVirtualPixelsNexus(const Cache cache,
3792 NexusInfo *nexus_info)
3793{
3794 CacheInfo
3795 *cache_info;
3796
3797 if (cache == (Cache) NULL)
3798 return((PixelPacket *) NULL);
3799 cache_info=(CacheInfo *) cache;
3800 assert(cache_info->signature == MagickSignature);
3801 if (cache_info->storage_class == UndefinedClass)
3802 return((PixelPacket *) NULL);
3803 return((const PixelPacket *) nexus_info->pixels);
3804}
3805
3806/*
3807%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3808% %
3809% %
3810% %
3811+ M a s k P i x e l C a c h e N e x u s %
3812% %
3813% %
3814% %
3815%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3816%
3817% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3818% The method returns MagickTrue if the pixel region is masked, otherwise
3819% MagickFalse.
3820%
3821% The format of the MaskPixelCacheNexus() method is:
3822%
3823% MagickBooleanType MaskPixelCacheNexus(Image *image,
3824% NexusInfo *nexus_info,ExceptionInfo *exception)
3825%
3826% A description of each parameter follows:
3827%
3828% o image: the image.
3829%
3830% o nexus_info: the cache nexus to clip.
3831%
3832% o exception: return any errors or warnings in this structure.
3833%
3834*/
3835
3836static inline void MagickPixelCompositeMask(const MagickPixelPacket *p,
3837 const MagickRealType alpha,const MagickPixelPacket *q,
3838 const MagickRealType beta,MagickPixelPacket *composite)
3839{
3840 MagickRealType
3841 gamma;
3842
3843 if (alpha == TransparentOpacity)
3844 {
3845 *composite=(*q);
3846 return;
3847 }
3848 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3849 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3850 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3851 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3852 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3853 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3854 composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
3855}
3856
3857static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3858 ExceptionInfo *exception)
3859{
3860 CacheInfo
3861 *cache_info;
3862
3863 MagickPixelPacket
3864 alpha,
3865 beta;
3866
3867 MagickSizeType
3868 number_pixels;
3869
3870 NexusInfo
3871 **clip_nexus,
3872 **image_nexus;
3873
3874 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003875 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003876
3877 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003878 *restrict nexus_indexes,
3879 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003880
3881 register long
3882 i;
3883
3884 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003885 *restrict p,
3886 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003887
3888 /*
3889 Apply clip mask.
3890 */
3891 if (image->debug != MagickFalse)
3892 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3893 if (image->mask == (Image *) NULL)
3894 return(MagickFalse);
3895 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
3896 if (cache_info == (Cache) NULL)
3897 return(MagickFalse);
3898 image_nexus=AcquirePixelCacheNexus(1);
3899 clip_nexus=AcquirePixelCacheNexus(1);
3900 if ((image_nexus == (NexusInfo **) NULL) ||
3901 (clip_nexus == (NexusInfo **) NULL))
3902 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy09449f72010-01-23 03:08:36 +00003903 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,
3904 nexus_info->region.y,nexus_info->region.width,nexus_info->region.height,
3905 image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003906 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
3907 q=nexus_info->pixels;
3908 nexus_indexes=nexus_info->indexes;
3909 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3910 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3911 nexus_info->region.height,clip_nexus[0],&image->exception);
3912 GetMagickPixelPacket(image,&alpha);
3913 GetMagickPixelPacket(image,&beta);
3914 number_pixels=(MagickSizeType) nexus_info->region.width*
3915 nexus_info->region.height;
3916 for (i=0; i < (long) number_pixels; i++)
3917 {
3918 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
3919 break;
3920 SetMagickPixelPacket(image,p,indexes+i,&alpha);
3921 SetMagickPixelPacket(image,q,nexus_indexes+i,&beta);
3922 MagickPixelCompositeMask(&beta,(MagickRealType) PixelIntensityToQuantum(r),
3923 &alpha,alpha.opacity,&beta);
cristyce70c172010-01-07 17:15:30 +00003924 q->red=ClampToQuantum(beta.red);
3925 q->green=ClampToQuantum(beta.green);
3926 q->blue=ClampToQuantum(beta.blue);
3927 q->opacity=ClampToQuantum(beta.opacity);
cristy3ed852e2009-09-05 21:47:34 +00003928 if (cache_info->active_index_channel != MagickFalse)
3929 nexus_indexes[i]=indexes[i];
3930 p++;
3931 q++;
3932 r++;
3933 }
3934 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3935 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
3936 if (i < (long) number_pixels)
3937 return(MagickFalse);
3938 return(MagickTrue);
3939}
3940
3941/*
3942%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3943% %
3944% %
3945% %
3946+ O p e n P i x e l C a c h e %
3947% %
3948% %
3949% %
3950%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3951%
3952% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3953% dimensions, allocating space for the image pixels and optionally the
3954% colormap indexes, and memory mapping the cache if it is disk based. The
3955% cache nexus array is initialized as well.
3956%
3957% The format of the OpenPixelCache() method is:
3958%
3959% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3960% ExceptionInfo *exception)
3961%
3962% A description of each parameter follows:
3963%
3964% o image: the image.
3965%
3966% o mode: ReadMode, WriteMode, or IOMode.
3967%
3968% o exception: return any errors or warnings in this structure.
3969%
3970*/
3971
cristyd43a46b2010-01-21 02:13:41 +00003972static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003973{
3974 cache_info->mapped=MagickFalse;
3975 cache_info->pixels=(PixelPacket *) AcquireMagickMemory((size_t)
3976 cache_info->length);
3977 if (cache_info->pixels == (PixelPacket *) NULL)
3978 {
3979 cache_info->mapped=MagickTrue;
3980 cache_info->pixels=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
3981 cache_info->length);
3982 }
3983}
3984
3985static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3986{
3987 CacheInfo
3988 *cache_info;
3989
3990 MagickOffsetType
3991 count,
3992 extent,
3993 offset;
3994
3995 cache_info=(CacheInfo *) image->cache;
3996 if (image->debug != MagickFalse)
3997 {
3998 char
3999 format[MaxTextExtent],
4000 message[MaxTextExtent];
4001
cristyb9080c92009-12-01 20:13:26 +00004002 (void) FormatMagickSize(length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00004003 (void) FormatMagickString(message,MaxTextExtent,
4004 "extend %s (%s[%d], disk, %s)",cache_info->filename,
4005 cache_info->cache_filename,cache_info->file,format);
4006 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4007 }
4008 if (length != (MagickSizeType) ((MagickOffsetType) length))
4009 return(MagickFalse);
4010 extent=(MagickOffsetType) MagickSeek(cache_info->file,0,SEEK_END);
4011 if (extent < 0)
4012 return(MagickFalse);
4013 if ((MagickSizeType) extent >= length)
4014 return(MagickTrue);
4015 offset=(MagickOffsetType) length-1;
4016 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
4017 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
4018}
4019
4020static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
4021 ExceptionInfo *exception)
4022{
4023 char
4024 format[MaxTextExtent],
4025 message[MaxTextExtent];
4026
4027 CacheInfo
4028 *cache_info,
4029 source_info;
4030
4031 MagickSizeType
4032 length,
4033 number_pixels;
4034
4035 MagickStatusType
4036 status;
4037
4038 size_t
4039 packet_size;
4040
4041 unsigned long
4042 columns;
4043
4044 if (image->debug != MagickFalse)
4045 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4046 if ((image->columns == 0) || (image->rows == 0))
4047 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
4048 cache_info=(CacheInfo *) image->cache;
4049 source_info=(*cache_info);
4050 source_info.file=(-1);
4051 (void) FormatMagickString(cache_info->filename,MaxTextExtent,"%s[%ld]",
4052 image->filename,GetImageIndexInList(image));
cristy87528ea2009-09-10 14:53:56 +00004053 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +00004054 cache_info->rows=image->rows;
4055 cache_info->columns=image->columns;
4056 cache_info->active_index_channel=((image->storage_class == PseudoClass) ||
4057 (image->colorspace == CMYKColorspace)) ? MagickTrue : MagickFalse;
4058 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4059 packet_size=sizeof(PixelPacket);
4060 if (cache_info->active_index_channel != MagickFalse)
4061 packet_size+=sizeof(IndexPacket);
4062 length=number_pixels*packet_size;
4063 columns=(unsigned long) (length/cache_info->rows/packet_size);
4064 if (cache_info->columns != columns)
4065 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4066 image->filename);
4067 cache_info->length=length;
4068 status=AcquireMagickResource(AreaResource,cache_info->length);
4069 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4070 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4071 {
4072 status=AcquireMagickResource(MemoryResource,cache_info->length);
4073 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4074 (cache_info->type == MemoryCache))
4075 {
cristyd43a46b2010-01-21 02:13:41 +00004076 AllocatePixelCachePixels(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004077 if (cache_info->pixels == (PixelPacket *) NULL)
4078 cache_info->pixels=source_info.pixels;
4079 else
4080 {
4081 /*
4082 Create memory pixel cache.
4083 */
4084 if (image->debug != MagickFalse)
4085 {
cristy97e7a572009-12-05 15:07:53 +00004086 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004087 format);
cristy3ed852e2009-09-05 21:47:34 +00004088 (void) FormatMagickString(message,MaxTextExtent,
4089 "open %s (%s memory, %lux%lu %s)",cache_info->filename,
4090 cache_info->mapped != MagickFalse ? "anonymous" : "heap",
4091 cache_info->columns,cache_info->rows,format);
4092 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4093 message);
4094 }
4095 cache_info->storage_class=image->storage_class;
4096 cache_info->colorspace=image->colorspace;
4097 cache_info->type=MemoryCache;
4098 cache_info->indexes=(IndexPacket *) NULL;
4099 if (cache_info->active_index_channel != MagickFalse)
4100 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4101 number_pixels);
4102 if (source_info.storage_class != UndefinedClass)
4103 {
4104 status|=ClonePixelCachePixels(cache_info,&source_info,
4105 exception);
4106 RelinquishPixelCachePixels(&source_info);
4107 }
4108 return(MagickTrue);
4109 }
4110 }
4111 RelinquishMagickResource(MemoryResource,cache_info->length);
4112 }
4113 /*
4114 Create pixel cache on disk.
4115 */
4116 status=AcquireMagickResource(DiskResource,cache_info->length);
4117 if (status == MagickFalse)
4118 {
4119 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4120 "CacheResourcesExhausted","`%s'",image->filename);
4121 return(MagickFalse);
4122 }
4123 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4124 {
4125 RelinquishMagickResource(DiskResource,cache_info->length);
4126 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4127 image->filename);
4128 return(MagickFalse);
4129 }
4130 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4131 cache_info->length);
4132 if (status == MagickFalse)
4133 {
4134 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4135 image->filename);
4136 return(MagickFalse);
4137 }
4138 cache_info->storage_class=image->storage_class;
4139 cache_info->colorspace=image->colorspace;
4140 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4141 status=AcquireMagickResource(AreaResource,cache_info->length);
4142 if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4143 cache_info->type=DiskCache;
4144 else
4145 {
4146 status=AcquireMagickResource(MapResource,cache_info->length);
4147 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4148 (cache_info->type != MemoryCache))
4149 cache_info->type=DiskCache;
4150 else
4151 {
4152 cache_info->pixels=(PixelPacket *) MapBlob(cache_info->file,mode,
4153 cache_info->offset,(size_t) cache_info->length);
4154 if (cache_info->pixels == (PixelPacket *) NULL)
4155 {
4156 cache_info->pixels=source_info.pixels;
4157 cache_info->type=DiskCache;
4158 }
4159 else
4160 {
4161 /*
4162 Create file-backed memory-mapped pixel cache.
4163 */
4164 (void) ClosePixelCacheOnDisk(cache_info);
4165 cache_info->type=MapCache;
4166 cache_info->mapped=MagickTrue;
4167 cache_info->indexes=(IndexPacket *) NULL;
4168 if (cache_info->active_index_channel != MagickFalse)
4169 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4170 number_pixels);
4171 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4172 {
4173 status=ClonePixelCachePixels(cache_info,&source_info,
4174 exception);
4175 RelinquishPixelCachePixels(&source_info);
4176 }
4177 if (image->debug != MagickFalse)
4178 {
cristy97e7a572009-12-05 15:07:53 +00004179 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004180 format);
cristy3ed852e2009-09-05 21:47:34 +00004181 (void) FormatMagickString(message,MaxTextExtent,
4182 "open %s (%s[%d], memory-mapped, %lux%lu %s)",
4183 cache_info->filename,cache_info->cache_filename,
4184 cache_info->file,cache_info->columns,cache_info->rows,
4185 format);
4186 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4187 message);
4188 }
4189 return(MagickTrue);
4190 }
4191 }
4192 RelinquishMagickResource(MapResource,cache_info->length);
4193 }
4194 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4195 {
4196 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4197 RelinquishPixelCachePixels(&source_info);
4198 }
4199 if (image->debug != MagickFalse)
4200 {
cristyb9080c92009-12-01 20:13:26 +00004201 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00004202 (void) FormatMagickString(message,MaxTextExtent,
4203 "open %s (%s[%d], disk, %lux%lu %s)",cache_info->filename,
4204 cache_info->cache_filename,cache_info->file,cache_info->columns,
4205 cache_info->rows,format);
4206 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4207 }
4208 return(MagickTrue);
4209}
4210
4211/*
4212%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4213% %
4214% %
4215% %
4216+ P e r s i s t P i x e l C a c h e %
4217% %
4218% %
4219% %
4220%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4221%
4222% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4223% persistent pixel cache is one that resides on disk and is not destroyed
4224% when the program exits.
4225%
4226% The format of the PersistPixelCache() method is:
4227%
4228% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4229% const MagickBooleanType attach,MagickOffsetType *offset,
4230% ExceptionInfo *exception)
4231%
4232% A description of each parameter follows:
4233%
4234% o image: the image.
4235%
4236% o filename: the persistent pixel cache filename.
4237%
cristy01b7eb02009-09-10 23:10:14 +00004238% o attach: A value other than zero initializes the persistent pixel
4239% cache.
4240%
cristy3ed852e2009-09-05 21:47:34 +00004241% o initialize: A value other than zero initializes the persistent pixel
4242% cache.
4243%
4244% o offset: the offset in the persistent cache to store pixels.
4245%
4246% o exception: return any errors or warnings in this structure.
4247%
4248*/
4249MagickExport MagickBooleanType PersistPixelCache(Image *image,
4250 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4251 ExceptionInfo *exception)
4252{
4253 CacheInfo
4254 *cache_info,
4255 *clone_info;
4256
4257 Image
4258 clone_image;
4259
4260 long
cristy688f07b2009-09-27 15:19:13 +00004261 page_size;
cristy3ed852e2009-09-05 21:47:34 +00004262
4263 MagickBooleanType
4264 status;
4265
4266 assert(image != (Image *) NULL);
4267 assert(image->signature == MagickSignature);
4268 if (image->debug != MagickFalse)
4269 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4270 assert(image->cache != (void *) NULL);
4271 assert(filename != (const char *) NULL);
4272 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004273 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004274 cache_info=(CacheInfo *) image->cache;
4275 assert(cache_info->signature == MagickSignature);
4276 if (attach != MagickFalse)
4277 {
4278 /*
cristy01b7eb02009-09-10 23:10:14 +00004279 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004280 */
4281 if (image->debug != MagickFalse)
4282 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4283 "attach persistent cache");
4284 (void) CopyMagickString(cache_info->cache_filename,filename,
4285 MaxTextExtent);
4286 cache_info->type=DiskCache;
4287 cache_info->offset=(*offset);
4288 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4289 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004290 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004291 return(MagickTrue);
4292 }
cristy01b7eb02009-09-10 23:10:14 +00004293 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4294 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004295 {
cristyf84a1932010-01-03 18:00:18 +00004296 LockSemaphoreInfo(cache_info->semaphore);
cristy09449f72010-01-23 03:08:36 +00004297 if ((cache_info->mode != ReadMode) &&
4298 (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004299 (cache_info->reference_count == 1))
4300 {
4301 int
4302 status;
4303
4304 /*
cristy01b7eb02009-09-10 23:10:14 +00004305 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004306 */
4307 status=rename(cache_info->cache_filename,filename);
4308 if (status == 0)
4309 {
4310 (void) CopyMagickString(cache_info->cache_filename,filename,
4311 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004312 *offset+=cache_info->length+page_size-(cache_info->length %
4313 page_size);
cristyf84a1932010-01-03 18:00:18 +00004314 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004315 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004316 if (image->debug != MagickFalse)
4317 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4318 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004319 return(MagickTrue);
4320 }
4321 }
cristyf84a1932010-01-03 18:00:18 +00004322 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004323 }
4324 /*
cristy01b7eb02009-09-10 23:10:14 +00004325 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004326 */
4327 clone_image=(*image);
4328 clone_info=(CacheInfo *) clone_image.cache;
4329 image->cache=ClonePixelCache(cache_info);
4330 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4331 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4332 cache_info->type=DiskCache;
4333 cache_info->offset=(*offset);
4334 cache_info=(CacheInfo *) image->cache;
4335 status=ClonePixelCacheNexus(cache_info,clone_info,exception);
4336 if (status != MagickFalse)
4337 {
4338 status=OpenPixelCache(image,IOMode,exception);
4339 if (status != MagickFalse)
4340 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
4341 }
cristy688f07b2009-09-27 15:19:13 +00004342 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004343 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4344 return(status);
4345}
4346
4347/*
4348%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4349% %
4350% %
4351% %
4352+ Q u e u e A u t h e n t i c N e x u s %
4353% %
4354% %
4355% %
4356%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4357%
4358% QueueAuthenticNexus() allocates an region to store image pixels as defined
4359% by the region rectangle and returns a pointer to the region. This region is
4360% subsequently transferred from the pixel cache with
4361% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4362% pixels are transferred, otherwise a NULL is returned.
4363%
4364% The format of the QueueAuthenticNexus() method is:
4365%
4366% PixelPacket *QueueAuthenticNexus(Image *image,const long x,const long y,
4367% const unsigned long columns,const unsigned long rows,
4368% NexusInfo *nexus_info,ExceptionInfo *exception)
4369%
4370% A description of each parameter follows:
4371%
4372% o image: the image.
4373%
4374% o x,y,columns,rows: These values define the perimeter of a region of
4375% pixels.
4376%
4377% o nexus_info: the cache nexus to set.
4378%
4379% o exception: return any errors or warnings in this structure.
4380%
4381*/
4382MagickExport PixelPacket *QueueAuthenticNexus(Image *image,const long x,
4383 const long y,const unsigned long columns,const unsigned long rows,
4384 NexusInfo *nexus_info,ExceptionInfo *exception)
4385{
4386 CacheInfo
4387 *cache_info;
4388
4389 MagickOffsetType
4390 offset;
4391
4392 MagickSizeType
4393 number_pixels;
4394
4395 RectangleInfo
4396 region;
4397
4398 /*
4399 Validate pixel cache geometry.
4400 */
4401 cache_info=(CacheInfo *) image->cache;
4402 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4403 {
4404 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4405 "NoPixelsDefinedInCache","`%s'",image->filename);
4406 return((PixelPacket *) NULL);
4407 }
4408 if ((x < 0) || (y < 0) || (x >= (long) cache_info->columns) ||
4409 (y >= (long) cache_info->rows))
4410 {
4411 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4412 "PixelsAreNotAuthentic","`%s'",image->filename);
4413 return((PixelPacket *) NULL);
4414 }
4415 offset=(MagickOffsetType) y*cache_info->columns+x;
4416 if (offset < 0)
4417 return((PixelPacket *) NULL);
4418 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4419 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4420 if ((MagickSizeType) offset >= number_pixels)
4421 return((PixelPacket *) NULL);
4422 /*
4423 Return pixel cache.
4424 */
4425 region.x=x;
4426 region.y=y;
4427 region.width=columns;
4428 region.height=rows;
4429 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4430}
4431
4432/*
4433%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4434% %
4435% %
4436% %
4437+ 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 %
4438% %
4439% %
4440% %
4441%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4442%
4443% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4444% defined by the region rectangle and returns a pointer to the region. This
4445% region is subsequently transferred from the pixel cache with
4446% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4447% pixels are transferred, otherwise a NULL is returned.
4448%
4449% The format of the QueueAuthenticPixelsCache() method is:
4450%
4451% PixelPacket *QueueAuthenticPixelsCache(Image *image,const long x,
4452% const long y,const unsigned long columns,const unsigned long rows,
4453% ExceptionInfo *exception)
4454%
4455% A description of each parameter follows:
4456%
4457% o image: the image.
4458%
4459% o x,y,columns,rows: These values define the perimeter of a region of
4460% pixels.
4461%
4462% o exception: return any errors or warnings in this structure.
4463%
4464*/
4465static PixelPacket *QueueAuthenticPixelsCache(Image *image,const long x,
4466 const long y,const unsigned long columns,const unsigned long rows,
4467 ExceptionInfo *exception)
4468{
4469 CacheInfo
4470 *cache_info;
4471
4472 long
4473 id;
4474
4475 PixelPacket
4476 *pixels;
4477
4478 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickFalse,exception);
4479 if (cache_info == (Cache) NULL)
4480 return((PixelPacket *) NULL);
4481 id=GetOpenMPThreadId();
4482 assert(id < (long) cache_info->number_threads);
4483 pixels=QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4484 exception);
4485 return(pixels);
4486}
4487
4488/*
4489%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4490% %
4491% %
4492% %
4493% Q u e u e A u t h e n t i c P i x e l s %
4494% %
4495% %
4496% %
4497%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4498%
4499% QueueAuthenticPixels() queues a mutable pixel region. If the region is
4500% successfully intialized a pointer to a PixelPacket array representing the
4501% region is returned, otherwise NULL is returned. The returned pointer may
4502% point to a temporary working buffer for the pixels or it may point to the
4503% final location of the pixels in memory.
4504%
4505% Write-only access means that any existing pixel values corresponding to
4506% the region are ignored. This is useful if the initial image is being
4507% created from scratch, or if the existing pixel values are to be
4508% completely replaced without need to refer to their pre-existing values.
4509% The application is free to read and write the pixel buffer returned by
4510% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4511% initialize the pixel array values. Initializing pixel array values is the
4512% application's responsibility.
4513%
4514% Performance is maximized if the selected region is part of one row, or
4515% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004516% pixels in-place (without a copy) if the image is in memory, or in a
4517% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004518% by the user.
4519%
4520% Pixels accessed via the returned pointer represent a simple array of type
4521% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
4522% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
4523% the black color component or the colormap indexes (of type IndexPacket)
4524% corresponding to the region. Once the PixelPacket (and/or IndexPacket)
4525% array has been updated, the changes must be saved back to the underlying
4526% image using SyncAuthenticPixels() or they may be lost.
4527%
4528% The format of the QueueAuthenticPixels() method is:
4529%
4530% PixelPacket *QueueAuthenticPixels(Image *image,const long x,const long y,
4531% const unsigned long columns,const unsigned long rows,
4532% ExceptionInfo *exception)
4533%
4534% A description of each parameter follows:
4535%
4536% o image: the image.
4537%
4538% o x,y,columns,rows: These values define the perimeter of a region of
4539% pixels.
4540%
4541% o exception: return any errors or warnings in this structure.
4542%
4543*/
4544MagickExport PixelPacket *QueueAuthenticPixels(Image *image,const long x,
4545 const long y,const unsigned long columns,const unsigned long rows,
4546 ExceptionInfo *exception)
4547{
4548 CacheInfo
4549 *cache_info;
4550
4551 PixelPacket
4552 *pixels;
4553
4554 assert(image != (Image *) NULL);
4555 assert(image->signature == MagickSignature);
4556 if (image->debug != MagickFalse)
4557 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4558 assert(image->cache != (Cache) NULL);
4559 cache_info=(CacheInfo *) image->cache;
4560 assert(cache_info->signature == MagickSignature);
4561 if (cache_info->methods.queue_authentic_pixels_handler ==
4562 (QueueAuthenticPixelsHandler) NULL)
4563 return((PixelPacket *) NULL);
4564 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4565 rows,exception);
4566 return(pixels);
4567}
4568
4569/*
4570%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4571% %
4572% %
4573% %
4574+ R e a d P i x e l C a c h e I n d e x e s %
4575% %
4576% %
4577% %
4578%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4579%
4580% ReadPixelCacheIndexes() reads colormap indexes from the specified region of
4581% the pixel cache.
4582%
4583% The format of the ReadPixelCacheIndexes() method is:
4584%
4585% MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4586% NexusInfo *nexus_info,ExceptionInfo *exception)
4587%
4588% A description of each parameter follows:
4589%
4590% o cache_info: the pixel cache.
4591%
4592% o nexus_info: the cache nexus to read the colormap indexes.
4593%
4594% o exception: return any errors or warnings in this structure.
4595%
4596*/
4597static MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4598 NexusInfo *nexus_info,ExceptionInfo *exception)
4599{
4600 MagickOffsetType
4601 count,
4602 offset;
4603
4604 MagickSizeType
4605 length,
4606 number_pixels;
4607
4608 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004609 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004610
4611 register long
4612 y;
4613
4614 unsigned long
4615 rows;
4616
4617 if (cache_info->debug != MagickFalse)
4618 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4619 cache_info->filename);
4620 if (cache_info->active_index_channel == MagickFalse)
4621 return(MagickFalse);
4622 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4623 return(MagickTrue);
4624 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4625 nexus_info->region.x;
4626 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
4627 rows=nexus_info->region.height;
4628 number_pixels=length*rows;
4629 if ((cache_info->columns == nexus_info->region.width) &&
4630 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4631 {
4632 length=number_pixels;
4633 rows=1UL;
4634 }
4635 q=nexus_info->indexes;
4636 switch (cache_info->type)
4637 {
4638 case MemoryCache:
4639 case MapCache:
4640 {
4641 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004642 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004643
4644 /*
4645 Read indexes from memory.
4646 */
4647 p=cache_info->indexes+offset;
4648 for (y=0; y < (long) rows; y++)
4649 {
4650 (void) CopyMagickMemory(q,p,(size_t) length);
4651 p+=cache_info->columns;
4652 q+=nexus_info->region.width;
4653 }
4654 break;
4655 }
4656 case DiskCache:
4657 {
4658 /*
4659 Read indexes from disk.
4660 */
4661 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4662 {
4663 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4664 cache_info->cache_filename);
4665 return(MagickFalse);
4666 }
4667 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4668 for (y=0; y < (long) rows; y++)
4669 {
4670 count=ReadPixelCacheRegion(cache_info,cache_info->offset+number_pixels*
4671 sizeof(PixelPacket)+offset*sizeof(*q),length,(unsigned char *) q);
4672 if ((MagickSizeType) count < length)
4673 break;
4674 offset+=cache_info->columns;
4675 q+=nexus_info->region.width;
4676 }
4677 if (y < (long) rows)
4678 {
4679 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4680 cache_info->cache_filename);
4681 return(MagickFalse);
4682 }
4683 break;
4684 }
4685 default:
4686 break;
4687 }
4688 if ((cache_info->debug != MagickFalse) &&
4689 (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4690 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
4691 cache_info->filename,nexus_info->region.width,nexus_info->region.height,
4692 nexus_info->region.x,nexus_info->region.y);
4693 return(MagickTrue);
4694}
4695
4696/*
4697%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4698% %
4699% %
4700% %
4701+ R e a d P i x e l C a c h e P i x e l s %
4702% %
4703% %
4704% %
4705%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4706%
4707% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4708% cache.
4709%
4710% The format of the ReadPixelCachePixels() method is:
4711%
4712% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4713% NexusInfo *nexus_info,ExceptionInfo *exception)
4714%
4715% A description of each parameter follows:
4716%
4717% o cache_info: the pixel cache.
4718%
4719% o nexus_info: the cache nexus to read the pixels.
4720%
4721% o exception: return any errors or warnings in this structure.
4722%
4723*/
4724static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4725 NexusInfo *nexus_info,ExceptionInfo *exception)
4726{
4727 MagickOffsetType
4728 count,
4729 offset;
4730
4731 MagickSizeType
4732 length,
4733 number_pixels;
4734
4735 register long
4736 y;
4737
4738 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004739 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004740
4741 unsigned long
4742 rows;
4743
4744 if (cache_info->debug != MagickFalse)
4745 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4746 cache_info->filename);
4747 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4748 return(MagickTrue);
4749 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4750 nexus_info->region.x;
4751 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
4752 rows=nexus_info->region.height;
4753 number_pixels=length*rows;
4754 if ((cache_info->columns == nexus_info->region.width) &&
4755 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4756 {
4757 length=number_pixels;
4758 rows=1UL;
4759 }
4760 q=nexus_info->pixels;
4761 switch (cache_info->type)
4762 {
4763 case MemoryCache:
4764 case MapCache:
4765 {
4766 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004767 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004768
4769 /*
4770 Read pixels from memory.
4771 */
4772 p=cache_info->pixels+offset;
4773 for (y=0; y < (long) rows; y++)
4774 {
4775 (void) CopyMagickMemory(q,p,(size_t) length);
4776 p+=cache_info->columns;
4777 q+=nexus_info->region.width;
4778 }
4779 break;
4780 }
4781 case DiskCache:
4782 {
4783 /*
4784 Read pixels from disk.
4785 */
4786 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4787 {
4788 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4789 cache_info->cache_filename);
4790 return(MagickFalse);
4791 }
4792 for (y=0; y < (long) rows; y++)
4793 {
4794 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4795 sizeof(*q),length,(unsigned char *) q);
4796 if ((MagickSizeType) count < length)
4797 break;
4798 offset+=cache_info->columns;
4799 q+=nexus_info->region.width;
4800 }
4801 if (y < (long) rows)
4802 {
4803 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4804 cache_info->cache_filename);
4805 return(MagickFalse);
4806 }
4807 break;
4808 }
4809 default:
4810 break;
4811 }
4812 if ((cache_info->debug != MagickFalse) &&
4813 (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4814 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
4815 cache_info->filename,nexus_info->region.width,nexus_info->region.height,
4816 nexus_info->region.x,nexus_info->region.y);
4817 return(MagickTrue);
4818}
4819
4820/*
4821%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4822% %
4823% %
4824% %
4825+ R e f e r e n c e P i x e l C a c h e %
4826% %
4827% %
4828% %
4829%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4830%
4831% ReferencePixelCache() increments the reference count associated with the
4832% pixel cache returning a pointer to the cache.
4833%
4834% The format of the ReferencePixelCache method is:
4835%
4836% Cache ReferencePixelCache(Cache cache_info)
4837%
4838% A description of each parameter follows:
4839%
4840% o cache_info: the pixel cache.
4841%
4842*/
4843MagickExport Cache ReferencePixelCache(Cache cache)
4844{
4845 CacheInfo
4846 *cache_info;
4847
4848 assert(cache != (Cache *) NULL);
4849 cache_info=(CacheInfo *) cache;
4850 assert(cache_info->signature == MagickSignature);
4851 if (cache_info->debug != MagickFalse)
4852 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4853 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00004854 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004855 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004856 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004857 return(cache_info);
4858}
4859
4860/*
4861%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4862% %
4863% %
4864% %
4865+ S e t P i x e l C a c h e M e t h o d s %
4866% %
4867% %
4868% %
4869%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4870%
4871% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4872%
4873% The format of the SetPixelCacheMethods() method is:
4874%
4875% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4876%
4877% A description of each parameter follows:
4878%
4879% o cache: the pixel cache.
4880%
4881% o cache_methods: Specifies a pointer to a CacheMethods structure.
4882%
4883*/
4884MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4885{
4886 CacheInfo
4887 *cache_info;
4888
4889 GetOneAuthenticPixelFromHandler
4890 get_one_authentic_pixel_from_handler;
4891
4892 GetOneVirtualPixelFromHandler
4893 get_one_virtual_pixel_from_handler;
4894
4895 /*
4896 Set cache pixel methods.
4897 */
4898 assert(cache != (Cache) NULL);
4899 assert(cache_methods != (CacheMethods *) NULL);
4900 cache_info=(CacheInfo *) cache;
4901 assert(cache_info->signature == MagickSignature);
4902 if (cache_info->debug != MagickFalse)
4903 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4904 cache_info->filename);
4905 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4906 cache_info->methods.get_virtual_pixel_handler=
4907 cache_methods->get_virtual_pixel_handler;
4908 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4909 cache_info->methods.destroy_pixel_handler=
4910 cache_methods->destroy_pixel_handler;
4911 if (cache_methods->get_virtual_indexes_from_handler !=
4912 (GetVirtualIndexesFromHandler) NULL)
4913 cache_info->methods.get_virtual_indexes_from_handler=
4914 cache_methods->get_virtual_indexes_from_handler;
4915 if (cache_methods->get_authentic_pixels_handler !=
4916 (GetAuthenticPixelsHandler) NULL)
4917 cache_info->methods.get_authentic_pixels_handler=
4918 cache_methods->get_authentic_pixels_handler;
4919 if (cache_methods->queue_authentic_pixels_handler !=
4920 (QueueAuthenticPixelsHandler) NULL)
4921 cache_info->methods.queue_authentic_pixels_handler=
4922 cache_methods->queue_authentic_pixels_handler;
4923 if (cache_methods->sync_authentic_pixels_handler !=
4924 (SyncAuthenticPixelsHandler) NULL)
4925 cache_info->methods.sync_authentic_pixels_handler=
4926 cache_methods->sync_authentic_pixels_handler;
4927 if (cache_methods->get_authentic_pixels_from_handler !=
4928 (GetAuthenticPixelsFromHandler) NULL)
4929 cache_info->methods.get_authentic_pixels_from_handler=
4930 cache_methods->get_authentic_pixels_from_handler;
4931 if (cache_methods->get_authentic_indexes_from_handler !=
4932 (GetAuthenticIndexesFromHandler) NULL)
4933 cache_info->methods.get_authentic_indexes_from_handler=
4934 cache_methods->get_authentic_indexes_from_handler;
4935 get_one_virtual_pixel_from_handler=
4936 cache_info->methods.get_one_virtual_pixel_from_handler;
4937 if (get_one_virtual_pixel_from_handler !=
4938 (GetOneVirtualPixelFromHandler) NULL)
4939 cache_info->methods.get_one_virtual_pixel_from_handler=
4940 cache_methods->get_one_virtual_pixel_from_handler;
4941 get_one_authentic_pixel_from_handler=
4942 cache_methods->get_one_authentic_pixel_from_handler;
4943 if (get_one_authentic_pixel_from_handler !=
4944 (GetOneAuthenticPixelFromHandler) NULL)
4945 cache_info->methods.get_one_authentic_pixel_from_handler=
4946 cache_methods->get_one_authentic_pixel_from_handler;
4947}
4948
4949/*
4950%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4951% %
4952% %
4953% %
4954+ S e t P i x e l C a c h e N e x u s P i x e l s %
4955% %
4956% %
4957% %
4958%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4959%
4960% SetPixelCacheNexusPixels() defines the region of the cache for the
4961% specified cache nexus.
4962%
4963% The format of the SetPixelCacheNexusPixels() method is:
4964%
4965% PixelPacket SetPixelCacheNexusPixels(const Image *image,
4966% const RectangleInfo *region,NexusInfo *nexus_info,
4967% ExceptionInfo *exception)
4968%
4969% A description of each parameter follows:
4970%
4971% o image: the image.
4972%
4973% o region: A pointer to the RectangleInfo structure that defines the
4974% region of this particular cache nexus.
4975%
4976% o nexus_info: the cache nexus to set.
4977%
4978% o exception: return any errors or warnings in this structure.
4979%
4980*/
4981static PixelPacket *SetPixelCacheNexusPixels(const Image *image,
4982 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4983{
4984 CacheInfo
4985 *cache_info;
4986
4987 MagickBooleanType
4988 status;
4989
cristy3ed852e2009-09-05 21:47:34 +00004990 MagickSizeType
4991 length,
4992 number_pixels;
4993
4994 if (image->debug != MagickFalse)
4995 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4996 cache_info=(CacheInfo *) image->cache;
4997 assert(cache_info->signature == MagickSignature);
4998 if (cache_info->type == UndefinedCache)
4999 return((PixelPacket *) NULL);
5000 nexus_info->region.width=region->width == 0UL ? 1UL : region->width;
5001 nexus_info->region.height=region->height == 0UL ? 1UL : region->height;
5002 nexus_info->region.x=region->x;
5003 nexus_info->region.y=region->y;
5004 if ((cache_info->type != DiskCache) && (image->clip_mask == (Image *) NULL) &&
5005 (image->mask == (Image *) NULL))
5006 {
cristybad067a2010-02-15 17:20:55 +00005007 long
5008 x,
5009 y;
cristy3ed852e2009-09-05 21:47:34 +00005010
cristybad067a2010-02-15 17:20:55 +00005011 x=nexus_info->region.x+nexus_info->region.width-1;
5012 y=nexus_info->region.y+nexus_info->region.height-1;
5013 if (((nexus_info->region.x >= 0) && (x < (long) cache_info->columns) &&
5014 (nexus_info->region.y >= 0) && (y < (long) cache_info->rows)) &&
cristy731c3532010-02-15 15:40:03 +00005015 ((nexus_info->region.height == 1UL) ||
5016 ((nexus_info->region.x == 0) &&
5017 ((nexus_info->region.width == cache_info->columns) ||
5018 ((nexus_info->region.width % cache_info->columns) == 0)))))
5019 {
5020 MagickOffsetType
5021 offset;
5022
5023 /*
5024 Pixels are accessed directly from memory.
5025 */
5026 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5027 nexus_info->region.x;
5028 nexus_info->pixels=cache_info->pixels+offset;
5029 nexus_info->indexes=(IndexPacket *) NULL;
5030 if (cache_info->active_index_channel != MagickFalse)
5031 nexus_info->indexes=cache_info->indexes+offset;
5032 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00005033 }
5034 }
5035 /*
5036 Pixels are stored in a cache region until they are synced to the cache.
5037 */
5038 number_pixels=(MagickSizeType) nexus_info->region.width*
5039 nexus_info->region.height;
5040 length=number_pixels*sizeof(PixelPacket);
5041 if (cache_info->active_index_channel != MagickFalse)
5042 length+=number_pixels*sizeof(IndexPacket);
5043 if (nexus_info->cache == (PixelPacket *) NULL)
5044 {
5045 nexus_info->length=length;
5046 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5047 if (status == MagickFalse)
5048 return((PixelPacket *) NULL);
5049 }
5050 else
5051 if (nexus_info->length != length)
5052 {
5053 RelinquishCacheNexusPixels(nexus_info);
5054 nexus_info->length=length;
5055 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5056 if (status == MagickFalse)
5057 return((PixelPacket *) NULL);
5058 }
5059 nexus_info->pixels=nexus_info->cache;
5060 nexus_info->indexes=(IndexPacket *) NULL;
5061 if (cache_info->active_index_channel != MagickFalse)
5062 nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
5063 return(nexus_info->pixels);
5064}
5065
5066/*
5067%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5068% %
5069% %
5070% %
5071% 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 %
5072% %
5073% %
5074% %
5075%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5076%
5077% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5078% pixel cache and returns the previous setting. A virtual pixel is any pixel
5079% access that is outside the boundaries of the image cache.
5080%
5081% The format of the SetPixelCacheVirtualMethod() method is:
5082%
5083% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5084% const VirtualPixelMethod virtual_pixel_method)
5085%
5086% A description of each parameter follows:
5087%
5088% o image: the image.
5089%
5090% o virtual_pixel_method: choose the type of virtual pixel.
5091%
5092*/
5093MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5094 const VirtualPixelMethod virtual_pixel_method)
5095{
5096 CacheInfo
5097 *cache_info;
5098
5099 VirtualPixelMethod
5100 method;
5101
5102 assert(image != (Image *) NULL);
5103 assert(image->signature == MagickSignature);
5104 if (image->debug != MagickFalse)
5105 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5106 assert(image->cache != (Cache) NULL);
5107 cache_info=(CacheInfo *) image->cache;
5108 assert(cache_info->signature == MagickSignature);
5109 method=cache_info->virtual_pixel_method;
5110 cache_info->virtual_pixel_method=virtual_pixel_method;
5111 return(method);
5112}
5113
5114/*
5115%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5116% %
5117% %
5118% %
5119+ 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 %
5120% %
5121% %
5122% %
5123%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5124%
5125% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5126% in-memory or disk cache. The method returns MagickTrue if the pixel region
5127% is synced, otherwise MagickFalse.
5128%
5129% The format of the SyncAuthenticPixelCacheNexus() method is:
5130%
5131% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5132% NexusInfo *nexus_info,ExceptionInfo *exception)
5133%
5134% A description of each parameter follows:
5135%
5136% o image: the image.
5137%
5138% o nexus_info: the cache nexus to sync.
5139%
5140% o exception: return any errors or warnings in this structure.
5141%
5142*/
5143MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5144 NexusInfo *nexus_info,ExceptionInfo *exception)
5145{
5146 CacheInfo
5147 *cache_info;
5148
5149 MagickBooleanType
5150 status;
5151
5152 /*
5153 Transfer pixels to the cache.
5154 */
5155 assert(image != (Image *) NULL);
5156 assert(image->signature == MagickSignature);
5157 if (image->debug != MagickFalse)
5158 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5159 if (image->cache == (Cache) NULL)
5160 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5161 cache_info=(CacheInfo *) image->cache;
5162 if (cache_info->type == UndefinedCache)
5163 return(MagickFalse);
5164 if ((image->clip_mask != (Image *) NULL) &&
5165 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5166 return(MagickFalse);
5167 if ((image->mask != (Image *) NULL) &&
5168 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5169 return(MagickFalse);
5170 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5171 return(MagickTrue);
5172 assert(cache_info->signature == MagickSignature);
5173 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5174 if ((cache_info->active_index_channel != MagickFalse) &&
5175 (WritePixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse))
5176 return(MagickFalse);
5177 return(status);
5178}
5179
5180/*
5181%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5182% %
5183% %
5184% %
5185+ S y n c A u t h e n t i c P i x e l C a c h e %
5186% %
5187% %
5188% %
5189%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5190%
5191% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5192% or disk cache. The method returns MagickTrue if the pixel region is synced,
5193% otherwise MagickFalse.
5194%
5195% The format of the SyncAuthenticPixelsCache() method is:
5196%
5197% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5198% ExceptionInfo *exception)
5199%
5200% A description of each parameter follows:
5201%
5202% o image: the image.
5203%
5204% o exception: return any errors or warnings in this structure.
5205%
5206*/
5207static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5208 ExceptionInfo *exception)
5209{
5210 CacheInfo
5211 *cache_info;
5212
5213 long
5214 id;
5215
5216 MagickBooleanType
5217 status;
5218
5219 cache_info=(CacheInfo *) image->cache;
5220 id=GetOpenMPThreadId();
5221 assert(id < (long) cache_info->number_threads);
5222 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5223 exception);
5224 return(status);
5225}
5226
5227/*
5228%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5229% %
5230% %
5231% %
5232% S y n c A u t h e n t i c P i x e l s %
5233% %
5234% %
5235% %
5236%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5237%
5238% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5239% The method returns MagickTrue if the pixel region is flushed, otherwise
5240% MagickFalse.
5241%
5242% The format of the SyncAuthenticPixels() method is:
5243%
5244% MagickBooleanType SyncAuthenticPixels(Image *image,
5245% ExceptionInfo *exception)
5246%
5247% A description of each parameter follows:
5248%
5249% o image: the image.
5250%
5251% o exception: return any errors or warnings in this structure.
5252%
5253*/
5254MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5255 ExceptionInfo *exception)
5256{
5257 CacheInfo
5258 *cache_info;
5259
5260 assert(image != (Image *) NULL);
5261 assert(image->signature == MagickSignature);
5262 if (image->debug != MagickFalse)
5263 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5264 assert(image->cache != (Cache) NULL);
5265 cache_info=(CacheInfo *) image->cache;
5266 assert(cache_info->signature == MagickSignature);
5267 if (cache_info->methods.sync_authentic_pixels_handler ==
5268 (SyncAuthenticPixelsHandler) NULL)
5269 return(MagickFalse);
5270 return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
5271}
5272
5273/*
5274%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5275% %
5276% %
5277% %
5278+ W r i t e P i x e l C a c h e I n d e x e s %
5279% %
5280% %
5281% %
5282%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5283%
5284% WritePixelCacheIndexes() writes the colormap indexes to the specified
5285% region of the pixel cache.
5286%
5287% The format of the WritePixelCacheIndexes() method is:
5288%
5289% MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5290% NexusInfo *nexus_info,ExceptionInfo *exception)
5291%
5292% A description of each parameter follows:
5293%
5294% o cache_info: the pixel cache.
5295%
5296% o nexus_info: the cache nexus to write the colormap indexes.
5297%
5298% o exception: return any errors or warnings in this structure.
5299%
5300*/
5301static MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5302 NexusInfo *nexus_info,ExceptionInfo *exception)
5303{
5304 MagickOffsetType
5305 count,
5306 offset;
5307
5308 MagickSizeType
5309 length,
5310 number_pixels;
5311
5312 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005313 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005314
5315 register long
5316 y;
5317
5318 unsigned long
5319 rows;
5320
5321 if (cache_info->debug != MagickFalse)
5322 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
5323 cache_info->filename);
5324 if (cache_info->active_index_channel == MagickFalse)
5325 return(MagickFalse);
5326 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5327 return(MagickTrue);
5328 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5329 nexus_info->region.x;
5330 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
5331 rows=nexus_info->region.height;
5332 number_pixels=(MagickSizeType) length*rows;
5333 if ((cache_info->columns == nexus_info->region.width) &&
5334 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5335 {
5336 length=number_pixels;
5337 rows=1UL;
5338 }
5339 p=nexus_info->indexes;
5340 switch (cache_info->type)
5341 {
5342 case MemoryCache:
5343 case MapCache:
5344 {
5345 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005346 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005347
5348 /*
5349 Write indexes to memory.
5350 */
5351 q=cache_info->indexes+offset;
5352 for (y=0; y < (long) rows; y++)
5353 {
5354 (void) CopyMagickMemory(q,p,(size_t) length);
5355 p+=nexus_info->region.width;
5356 q+=cache_info->columns;
5357 }
5358 break;
5359 }
5360 case DiskCache:
5361 {
5362 /*
5363 Write indexes to disk.
5364 */
5365 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5366 {
5367 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5368 cache_info->cache_filename);
5369 return(MagickFalse);
5370 }
5371 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
5372 for (y=0; y < (long) rows; y++)
5373 {
5374 count=WritePixelCacheRegion(cache_info,cache_info->offset+number_pixels*
5375 sizeof(PixelPacket)+offset*sizeof(*p),length,
5376 (const unsigned char *) p);
5377 if ((MagickSizeType) count < length)
5378 break;
5379 p+=nexus_info->region.width;
5380 offset+=cache_info->columns;
5381 }
5382 if (y < (long) rows)
5383 {
5384 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5385 cache_info->cache_filename);
5386 return(MagickFalse);
5387 }
5388 break;
5389 }
5390 default:
5391 break;
5392 }
5393 if ((cache_info->debug != MagickFalse) &&
5394 (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5395 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
5396 cache_info->filename,nexus_info->region.width,nexus_info->region.height,
5397 nexus_info->region.x,nexus_info->region.y);
5398 return(MagickTrue);
5399}
5400
5401/*
5402%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5403% %
5404% %
5405% %
5406+ W r i t e C a c h e P i x e l s %
5407% %
5408% %
5409% %
5410%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5411%
5412% WritePixelCachePixels() writes image pixels to the specified region of the
5413% pixel cache.
5414%
5415% The format of the WritePixelCachePixels() method is:
5416%
5417% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5418% NexusInfo *nexus_info,ExceptionInfo *exception)
5419%
5420% A description of each parameter follows:
5421%
5422% o cache_info: the pixel cache.
5423%
5424% o nexus_info: the cache nexus to write the pixels.
5425%
5426% o exception: return any errors or warnings in this structure.
5427%
5428*/
5429static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5430 NexusInfo *nexus_info,ExceptionInfo *exception)
5431{
5432 MagickOffsetType
5433 count,
5434 offset;
5435
5436 MagickSizeType
5437 length,
5438 number_pixels;
5439
cristy3ed852e2009-09-05 21:47:34 +00005440 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005441 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005442
cristy25ffffb2009-12-07 17:15:07 +00005443 register long
5444 y;
5445
cristy3ed852e2009-09-05 21:47:34 +00005446 unsigned long
5447 rows;
5448
5449 if (cache_info->debug != MagickFalse)
5450 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
5451 cache_info->filename);
5452 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5453 return(MagickTrue);
5454 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5455 nexus_info->region.x;
5456 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
5457 rows=nexus_info->region.height;
5458 number_pixels=length*rows;
5459 if ((cache_info->columns == nexus_info->region.width) &&
5460 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5461 {
5462 length=number_pixels;
5463 rows=1UL;
5464 }
5465 p=nexus_info->pixels;
5466 switch (cache_info->type)
5467 {
5468 case MemoryCache:
5469 case MapCache:
5470 {
5471 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005472 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005473
5474 /*
5475 Write pixels to memory.
5476 */
5477 q=cache_info->pixels+offset;
5478 for (y=0; y < (long) rows; y++)
5479 {
5480 (void) CopyMagickMemory(q,p,(size_t) length);
5481 p+=nexus_info->region.width;
5482 q+=cache_info->columns;
5483 }
5484 break;
5485 }
5486 case DiskCache:
5487 {
5488 /*
5489 Write pixels to disk.
5490 */
5491 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5492 {
5493 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5494 cache_info->cache_filename);
5495 return(MagickFalse);
5496 }
5497 for (y=0; y < (long) rows; y++)
5498 {
5499 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5500 sizeof(*p),length,(const unsigned char *) p);
5501 if ((MagickSizeType) count < length)
5502 break;
5503 p+=nexus_info->region.width;
5504 offset+=cache_info->columns;
5505 }
5506 if (y < (long) rows)
5507 {
5508 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5509 cache_info->cache_filename);
5510 return(MagickFalse);
5511 }
5512 break;
5513 }
5514 default:
5515 break;
5516 }
5517 if ((cache_info->debug != MagickFalse) &&
5518 (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5519 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
5520 cache_info->filename,nexus_info->region.width,nexus_info->region.height,
5521 nexus_info->region.x,nexus_info->region.y);
5522 return(MagickTrue);
5523}