blob: 1ffe9190c6fc3f1adcd935c94e8bdc9fc46ac3cd [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;
cristyf84a1932010-01-03 18:00:18 +00002184 LockSemaphoreInfo(cache_info->semaphore);
cristy01b7eb02009-09-10 23:10:14 +00002185 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002186 {
2187 Image
2188 clone_image;
2189
2190 CacheInfo
2191 *clone_info;
2192
2193 /*
2194 Clone pixel cache.
2195 */
2196 clone_image=(*image);
2197 clone_image.cache=ClonePixelCache(cache_info);
2198 clone_info=(CacheInfo *) clone_image.cache;
2199 status=ClonePixelCacheNexus(cache_info,clone_info,exception);
2200 if (status != MagickFalse)
2201 {
2202 status=OpenPixelCache(&clone_image,IOMode,exception);
2203 if (status != MagickFalse)
2204 {
2205 if (clone != MagickFalse)
2206 status=ClonePixelCachePixels(clone_info,cache_info,exception);
2207 if (status != MagickFalse)
2208 {
cristy4320e0e2009-09-10 15:00:08 +00002209 destroy=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00002210 image->cache=clone_image.cache;
2211 }
2212 }
2213 }
2214 }
cristyf84a1932010-01-03 18:00:18 +00002215 UnlockSemaphoreInfo(cache_info->semaphore);
cristy4320e0e2009-09-10 15:00:08 +00002216 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002217 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002218 if (status != MagickFalse)
2219 {
2220 /*
2221 Ensure the image matches the pixel cache morphology.
2222 */
2223 image->taint=MagickTrue;
2224 image->type=UndefinedType;
2225 if (image->colorspace == GRAYColorspace)
2226 image->colorspace=RGBColorspace;
2227 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2228 status=OpenPixelCache(image,IOMode,exception);
2229 }
cristyf84a1932010-01-03 18:00:18 +00002230 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002231 if (status == MagickFalse)
2232 return((Cache) NULL);
2233 return(image->cache);
2234}
2235
2236/*
2237%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2238% %
2239% %
2240% %
2241% G e t O n e A u t h e n t i c P i x e l %
2242% %
2243% %
2244% %
2245%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2246%
2247% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2248% location. The image background color is returned if an error occurs.
2249%
2250% The format of the GetOneAuthenticPixel() method is:
2251%
2252% MagickBooleanType GetOneAuthenticPixel(const Image image,const long x,
2253% const long y,PixelPacket *pixel,ExceptionInfo *exception)
2254%
2255% A description of each parameter follows:
2256%
2257% o image: the image.
2258%
2259% o x,y: These values define the location of the pixel to return.
2260%
2261% o pixel: return a pixel at the specified (x,y) location.
2262%
2263% o exception: return any errors or warnings in this structure.
2264%
2265*/
2266MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,const long x,
2267 const long y,PixelPacket *pixel,ExceptionInfo *exception)
2268{
2269 CacheInfo
2270 *cache_info;
2271
2272 GetOneAuthenticPixelFromHandler
2273 get_one_authentic_pixel_from_handler;
2274
2275 MagickBooleanType
2276 status;
2277
2278 assert(image != (Image *) NULL);
2279 assert(image->signature == MagickSignature);
2280 if (image->debug != MagickFalse)
2281 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2282 assert(image->cache != (Cache) NULL);
2283 cache_info=(CacheInfo *) image->cache;
2284 assert(cache_info->signature == MagickSignature);
2285 *pixel=image->background_color;
2286 get_one_authentic_pixel_from_handler=
2287 cache_info->methods.get_one_authentic_pixel_from_handler;
2288 if (get_one_authentic_pixel_from_handler ==
2289 (GetOneAuthenticPixelFromHandler) NULL)
2290 return(MagickFalse);
2291 status=cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2292 pixel,exception);
2293 return(status);
2294}
2295
2296/*
2297%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2298% %
2299% %
2300% %
2301+ 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 %
2302% %
2303% %
2304% %
2305%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2306%
2307% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2308% location. The image background color is returned if an error occurs.
2309%
2310% The format of the GetOneAuthenticPixelFromCache() method is:
2311%
2312% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
2313% const long x,const long y,PixelPacket *pixel,ExceptionInfo *exception)
2314%
2315% A description of each parameter follows:
2316%
2317% o image: the image.
2318%
2319% o x,y: These values define the location of the pixel to return.
2320%
2321% o pixel: return a pixel at the specified (x,y) location.
2322%
2323% o exception: return any errors or warnings in this structure.
2324%
2325*/
2326static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
2327 const long x,const long y,PixelPacket *pixel,ExceptionInfo *exception)
2328{
2329 PixelPacket
2330 *pixels;
2331
2332 if (image->debug != MagickFalse)
2333 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2334 *pixel=image->background_color;
2335 pixels=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2336 if (pixels == (PixelPacket *) NULL)
2337 return(MagickFalse);
2338 *pixel=(*pixels);
2339 return(MagickTrue);
2340}
2341
2342/*
2343%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2344% %
2345% %
2346% %
2347% G e t O n e V i r t u a l M a g i c k P i x e l %
2348% %
2349% %
2350% %
2351%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2352%
2353% GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2354% location. The image background color is returned if an error occurs. If
2355% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2356%
2357% The format of the GetOneVirtualMagickPixel() method is:
2358%
2359% MagickBooleanType GetOneVirtualMagickPixel(const Image image,
2360% const long x,const long y,MagickPixelPacket *pixel,
2361% ExceptionInfo exception)
2362%
2363% A description of each parameter follows:
2364%
2365% o image: the image.
2366%
2367% o x,y: these values define the location of the pixel to return.
2368%
2369% o pixel: return a pixel at the specified (x,y) location.
2370%
2371% o exception: return any errors or warnings in this structure.
2372%
2373*/
2374MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
2375 const long x,const long y,MagickPixelPacket *pixel,ExceptionInfo *exception)
2376{
2377 CacheInfo
2378 *cache_info;
2379
2380 register const IndexPacket
2381 *indexes;
2382
2383 register const PixelPacket
2384 *p;
2385
2386 assert(image != (const Image *) NULL);
2387 assert(image->signature == MagickSignature);
2388 assert(image->cache != (Cache) NULL);
2389 cache_info=(CacheInfo *) image->cache;
2390 assert(cache_info->signature == MagickSignature);
2391 GetMagickPixelPacket(image,pixel);
2392 p=GetVirtualPixelCache(image,GetPixelCacheVirtualMethod(image),x,y,1,1,
2393 exception);
2394 if (p == (const PixelPacket *) NULL)
2395 return(MagickFalse);
2396 indexes=GetVirtualIndexQueue(image);
2397 SetMagickPixelPacket(image,p,indexes,pixel);
2398 return(MagickTrue);
2399}
2400
2401/*
2402%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2403% %
2404% %
2405% %
2406% G e t O n e V i r t u a l M e t h o d P i x e l %
2407% %
2408% %
2409% %
2410%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2411%
2412% GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2413% location as defined by specified pixel method. The image background color
2414% is returned if an error occurs. If you plan to modify the pixel, use
2415% GetOneAuthenticPixel() instead.
2416%
2417% The format of the GetOneVirtualMethodPixel() method is:
2418%
2419% MagickBooleanType GetOneVirtualMethodPixel(const Image image,
2420% const VirtualPixelMethod virtual_pixel_method,const long x,
2421% const long y,Pixelpacket *pixel,ExceptionInfo exception)
2422%
2423% A description of each parameter follows:
2424%
2425% o image: the image.
2426%
2427% o virtual_pixel_method: the virtual pixel method.
2428%
2429% o x,y: These values define the location of the pixel to return.
2430%
2431% o pixel: return a pixel at the specified (x,y) location.
2432%
2433% o exception: return any errors or warnings in this structure.
2434%
2435*/
2436MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
2437 const VirtualPixelMethod virtual_pixel_method,const long x,const long y,
2438 PixelPacket *pixel,ExceptionInfo *exception)
2439{
2440 GetOneVirtualPixelFromHandler
2441 get_one_virtual_pixel_from_handler;
2442
2443 CacheInfo
2444 *cache_info;
2445
2446 MagickBooleanType
2447 status;
2448
2449 assert(image != (const Image *) NULL);
2450 assert(image->signature == MagickSignature);
2451 assert(image->cache != (Cache) NULL);
2452 cache_info=(CacheInfo *) image->cache;
2453 assert(cache_info->signature == MagickSignature);
2454 *pixel=image->background_color;
2455 get_one_virtual_pixel_from_handler=
2456 cache_info->methods.get_one_virtual_pixel_from_handler;
2457 if (get_one_virtual_pixel_from_handler ==
2458 (GetOneVirtualPixelFromHandler) NULL)
2459 return(MagickFalse);
2460 status=get_one_virtual_pixel_from_handler(image,virtual_pixel_method,x,y,
2461 pixel,exception);
2462 return(status);
2463}
2464
2465/*
2466%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2467% %
2468% %
2469% %
2470% G e t O n e V i r t u a l P i x e l %
2471% %
2472% %
2473% %
2474%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2475%
2476% GetOneVirtualPixel() returns a single virtual pixel at the specified
2477% (x,y) location. The image background color is returned if an error occurs.
2478% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2479%
2480% The format of the GetOneVirtualPixel() method is:
2481%
2482% MagickBooleanType GetOneVirtualPixel(const Image image,const long x,
2483% const long y,PixelPacket *pixel,ExceptionInfo exception)
2484%
2485% A description of each parameter follows:
2486%
2487% o image: the image.
2488%
2489% o x,y: These values define the location of the pixel to return.
2490%
2491% o pixel: return a pixel at the specified (x,y) location.
2492%
2493% o exception: return any errors or warnings in this structure.
2494%
2495*/
2496MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
2497 const long x,const long y,PixelPacket *pixel,ExceptionInfo *exception)
2498{
2499 GetOneVirtualPixelFromHandler
2500 get_one_virtual_pixel_from_handler;
2501
2502 CacheInfo
2503 *cache_info;
2504
2505 MagickBooleanType
2506 status;
2507
2508 assert(image != (const Image *) NULL);
2509 assert(image->signature == MagickSignature);
2510 assert(image->cache != (Cache) NULL);
2511 cache_info=(CacheInfo *) image->cache;
2512 assert(cache_info->signature == MagickSignature);
2513 *pixel=image->background_color;
2514 get_one_virtual_pixel_from_handler=
2515 cache_info->methods.get_one_virtual_pixel_from_handler;
2516 if (get_one_virtual_pixel_from_handler ==
2517 (GetOneVirtualPixelFromHandler) NULL)
2518 return(MagickFalse);
2519 status=get_one_virtual_pixel_from_handler(image,GetPixelCacheVirtualMethod(
2520 image),x,y,pixel,exception);
2521 return(status);
2522}
2523
2524/*
2525%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2526% %
2527% %
2528% %
2529+ 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 %
2530% %
2531% %
2532% %
2533%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2534%
2535% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2536% specified (x,y) location. The image background color is returned if an
2537% error occurs.
2538%
2539% The format of the GetOneVirtualPixelFromCache() method is:
2540%
2541% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
2542% const VirtualPixelPacket method,const long x,const long y,
2543% PixelPacket *pixel,ExceptionInfo *exception)
2544%
2545% A description of each parameter follows:
2546%
2547% o image: the image.
2548%
2549% o virtual_pixel_method: the virtual pixel method.
2550%
2551% o x,y: These values define the location of the pixel to return.
2552%
2553% o pixel: return a pixel at the specified (x,y) location.
2554%
2555% o exception: return any errors or warnings in this structure.
2556%
2557*/
2558static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
2559 const VirtualPixelMethod virtual_pixel_method,const long x,const long y,
2560 PixelPacket *pixel,ExceptionInfo *exception)
2561{
2562 const PixelPacket
2563 *pixels;
2564
2565 *pixel=image->background_color;
2566 pixels=GetVirtualPixelCache(image,virtual_pixel_method,x,y,1UL,1UL,exception);
2567 if (pixels == (const PixelPacket *) NULL)
2568 return(MagickFalse);
2569 *pixel=(*pixels);
2570 return(MagickTrue);
2571}
2572
2573/*
2574%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2575% %
2576% %
2577% %
2578+ G e t P i x e l C a c h e C o l o r s p a c e %
2579% %
2580% %
2581% %
2582%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2583%
2584% GetPixelCacheColorspace() returns the class type of the pixel cache.
2585%
2586% The format of the GetPixelCacheColorspace() method is:
2587%
2588% Colorspace GetPixelCacheColorspace(Cache cache)
2589%
2590% A description of each parameter follows:
2591%
2592% o cache: the pixel cache.
2593%
2594*/
2595MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
2596{
2597 CacheInfo
2598 *cache_info;
2599
2600 assert(cache != (Cache) NULL);
2601 cache_info=(CacheInfo *) cache;
2602 assert(cache_info->signature == MagickSignature);
2603 if (cache_info->debug != MagickFalse)
2604 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2605 cache_info->filename);
2606 return(cache_info->colorspace);
2607}
2608
2609/*
2610%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2611% %
2612% %
2613% %
2614+ G e t P i x e l C a c h e M e t h o d s %
2615% %
2616% %
2617% %
2618%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2619%
2620% GetPixelCacheMethods() initializes the CacheMethods structure.
2621%
2622% The format of the GetPixelCacheMethods() method is:
2623%
2624% void GetPixelCacheMethods(CacheMethods *cache_methods)
2625%
2626% A description of each parameter follows:
2627%
2628% o cache_methods: Specifies a pointer to a CacheMethods structure.
2629%
2630*/
2631MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
2632{
2633 assert(cache_methods != (CacheMethods *) NULL);
2634 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2635 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2636 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2637 cache_methods->get_virtual_indexes_from_handler=GetVirtualIndexesFromCache;
2638 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2639 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2640 cache_methods->get_authentic_indexes_from_handler=
2641 GetAuthenticIndexesFromCache;
2642 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2643 cache_methods->get_one_authentic_pixel_from_handler=
2644 GetOneAuthenticPixelFromCache;
2645 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2646 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2647 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2648}
2649
2650/*
2651%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2652% %
2653% %
2654% %
2655+ G e t P i x e l C a c h e N e x u s E x t e n t %
2656% %
2657% %
2658% %
2659%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2660%
2661% GetPixelCacheNexusExtent() returns the extent of the pixels associated with
2662% the last call to SetPixelCacheNexusPixels() or GetPixelCacheNexusPixels().
2663%
2664% The format of the GetPixelCacheNexusExtent() method is:
2665%
2666% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2667% NexusInfo *nexus_info)
2668%
2669% A description of each parameter follows:
2670%
2671% o nexus_info: the nexus info.
2672%
2673*/
2674MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2675 NexusInfo *nexus_info)
2676{
2677 CacheInfo
2678 *cache_info;
2679
2680 MagickSizeType
2681 extent;
2682
2683 if (cache == (Cache) NULL)
2684 return(0);
2685 cache_info=(CacheInfo *) cache;
2686 assert(cache_info->signature == MagickSignature);
2687 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2688 if (extent == 0)
2689 return((MagickSizeType) cache_info->columns*cache_info->rows);
2690 return(extent);
2691}
2692
2693/*
2694%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2695% %
2696% %
2697% %
2698+ 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 %
2699% %
2700% %
2701% %
2702%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2703%
2704% GetPixelCacheNexusIndexes() returns the indexes associated with the
2705% specified cache nexus.
2706%
2707% The format of the GetPixelCacheNexusIndexes() method is:
2708%
2709% IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2710% NexusInfo *nexus_info)
2711%
2712% A description of each parameter follows:
2713%
2714% o cache: the pixel cache.
2715%
2716% o nexus_info: the cache nexus to return the colormap indexes.
2717%
2718*/
2719MagickExport IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2720 NexusInfo *nexus_info)
2721{
2722 CacheInfo
2723 *cache_info;
2724
2725 if (cache == (Cache) NULL)
2726 return((IndexPacket *) NULL);
2727 cache_info=(CacheInfo *) cache;
2728 assert(cache_info->signature == MagickSignature);
2729 if (cache_info->storage_class == UndefinedClass)
2730 return((IndexPacket *) NULL);
2731 return(nexus_info->indexes);
2732}
2733
2734/*
2735%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2736% %
2737% %
2738% %
2739+ G e t P i x e l C a c h e N e x u s P i x e l s %
2740% %
2741% %
2742% %
2743%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2744%
2745% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2746% cache nexus.
2747%
2748% The format of the GetPixelCacheNexusPixels() method is:
2749%
2750% PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2751% NexusInfo *nexus_info)
2752%
2753% A description of each parameter follows:
2754%
2755% o cache: the pixel cache.
2756%
2757% o nexus_info: the cache nexus to return the pixels.
2758%
2759*/
2760MagickExport PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2761 NexusInfo *nexus_info)
2762{
2763 CacheInfo
2764 *cache_info;
2765
2766 if (cache == (Cache) NULL)
2767 return((PixelPacket *) NULL);
2768 cache_info=(CacheInfo *) cache;
2769 assert(cache_info->signature == MagickSignature);
2770 if (cache_info->debug != MagickFalse)
2771 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2772 cache_info->filename);
2773 if (cache_info->storage_class == UndefinedClass)
2774 return((PixelPacket *) NULL);
2775 return(nexus_info->pixels);
2776}
2777
2778/*
2779%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2780% %
2781% %
2782% %
cristy056ba772010-01-02 23:33:54 +00002783+ G e t P i x e l C a c h e P i x e l s %
2784% %
2785% %
2786% %
2787%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2788%
2789% GetPixelCachePixels() returns the pixels associated with the specified image.
2790%
2791% The format of the GetPixelCachePixels() method is:
2792%
cristyf84a1932010-01-03 18:00:18 +00002793% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2794% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002795%
2796% A description of each parameter follows:
2797%
2798% o image: the image.
2799%
2800% o length: the pixel cache length.
2801%
cristyf84a1932010-01-03 18:00:18 +00002802% o exception: return any errors or warnings in this structure.
2803%
cristy056ba772010-01-02 23:33:54 +00002804*/
cristyf84a1932010-01-03 18:00:18 +00002805MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2806 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002807{
2808 CacheInfo
2809 *cache_info;
2810
2811 assert(image != (const Image *) NULL);
2812 assert(image->signature == MagickSignature);
2813 if (image->debug != MagickFalse)
2814 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2815 assert(image->cache != (Cache) NULL);
cristyc4c8d132010-01-07 01:58:38 +00002816 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
cristy056ba772010-01-02 23:33:54 +00002817 assert(cache_info->signature == MagickSignature);
2818 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002819 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002820 return((void *) NULL);
2821 *length=cache_info->length;
2822 return((void *) cache_info->pixels);
2823}
2824
2825/*
2826%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2827% %
2828% %
2829% %
cristyb32b90a2009-09-07 21:45:48 +00002830+ 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 +00002831% %
2832% %
2833% %
2834%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2835%
2836% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2837%
2838% The format of the GetPixelCacheStorageClass() method is:
2839%
2840% ClassType GetPixelCacheStorageClass(Cache cache)
2841%
2842% A description of each parameter follows:
2843%
2844% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2845%
2846% o cache: the pixel cache.
2847%
2848*/
2849MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
2850{
2851 CacheInfo
2852 *cache_info;
2853
2854 assert(cache != (Cache) NULL);
2855 cache_info=(CacheInfo *) cache;
2856 assert(cache_info->signature == MagickSignature);
2857 if (cache_info->debug != MagickFalse)
2858 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2859 cache_info->filename);
2860 return(cache_info->storage_class);
2861}
2862
2863/*
2864%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2865% %
2866% %
2867% %
cristyb32b90a2009-09-07 21:45:48 +00002868+ G e t P i x e l C a c h e T i l e S i z e %
2869% %
2870% %
2871% %
2872%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2873%
2874% GetPixelCacheTileSize() returns the pixel cache tile size.
2875%
2876% The format of the GetPixelCacheTileSize() method is:
2877%
2878% void GetPixelCacheTileSize(const Image *image,unsigned long *width,
2879% unsigned long *height)
2880%
2881% A description of each parameter follows:
2882%
2883% o image: the image.
2884%
2885% o width: the optimize cache tile width in pixels.
2886%
2887% o height: the optimize cache tile height in pixels.
2888%
2889*/
2890MagickExport void GetPixelCacheTileSize(const Image *image,unsigned long *width,
2891 unsigned long *height)
2892{
2893 CacheInfo
2894 *cache_info;
2895
2896 assert(image != (Image *) NULL);
2897 assert(image->signature == MagickSignature);
2898 if (image->debug != MagickFalse)
2899 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2900 assert(image->cache != (Cache) NULL);
2901 cache_info=(CacheInfo *) image->cache;
2902 assert(cache_info->signature == MagickSignature);
2903 *width=2048UL/sizeof(PixelPacket);
2904 if (GetPixelCacheType(image) == DiskCache)
cristydaa97692009-09-13 02:10:35 +00002905 *width=8192UL/sizeof(PixelPacket);
cristyb32b90a2009-09-07 21:45:48 +00002906 *height=(*width);
2907}
2908
2909/*
2910%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2911% %
2912% %
2913% %
2914+ G e t P i x e l C a c h e T y p e %
2915% %
2916% %
2917% %
2918%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2919%
2920% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2921%
2922% The format of the GetPixelCacheType() method is:
2923%
2924% CacheType GetPixelCacheType(const Image *image)
2925%
2926% A description of each parameter follows:
2927%
2928% o image: the image.
2929%
2930*/
2931MagickExport CacheType GetPixelCacheType(const Image *image)
2932{
2933 CacheInfo
2934 *cache_info;
2935
2936 assert(image != (Image *) NULL);
2937 assert(image->signature == MagickSignature);
2938 if (image->debug != MagickFalse)
2939 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2940 assert(image->cache != (Cache) NULL);
2941 cache_info=(CacheInfo *) image->cache;
2942 assert(cache_info->signature == MagickSignature);
2943 return(cache_info->type);
2944}
2945
2946/*
2947%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2948% %
2949% %
2950% %
cristy3ed852e2009-09-05 21:47:34 +00002951+ 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 %
2952% %
2953% %
2954% %
2955%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2956%
2957% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2958% pixel cache. A virtual pixel is any pixel access that is outside the
2959% boundaries of the image cache.
2960%
2961% The format of the GetPixelCacheVirtualMethod() method is:
2962%
2963% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2964%
2965% A description of each parameter follows:
2966%
2967% o image: the image.
2968%
2969*/
2970MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2971{
2972 CacheInfo
2973 *cache_info;
2974
2975 assert(image != (Image *) NULL);
2976 assert(image->signature == MagickSignature);
2977 if (image->debug != MagickFalse)
2978 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2979 assert(image->cache != (Cache) NULL);
2980 cache_info=(CacheInfo *) image->cache;
2981 assert(cache_info->signature == MagickSignature);
2982 return(cache_info->virtual_pixel_method);
2983}
2984
2985/*
2986%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2987% %
2988% %
2989% %
2990+ 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 %
2991% %
2992% %
2993% %
2994%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2995%
2996% GetVirtualIndexesFromCache() returns the indexes associated with the last
2997% call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2998%
2999% The format of the GetVirtualIndexesFromCache() method is:
3000%
3001% IndexPacket *GetVirtualIndexesFromCache(const Image *image)
3002%
3003% A description of each parameter follows:
3004%
3005% o image: the image.
3006%
3007*/
3008static const IndexPacket *GetVirtualIndexesFromCache(const Image *image)
3009{
3010 CacheInfo
3011 *cache_info;
3012
3013 const IndexPacket
3014 *indexes;
3015
3016 long
3017 id;
3018
3019 if (image->debug != MagickFalse)
3020 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3021 cache_info=(CacheInfo *) image->cache;
3022 id=GetOpenMPThreadId();
3023 assert(id < (long) cache_info->number_threads);
3024 indexes=GetVirtualIndexesFromNexus(image->cache,cache_info->nexus_info[id]);
3025 return(indexes);
3026}
3027
3028/*
3029%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3030% %
3031% %
3032% %
3033+ 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 %
3034% %
3035% %
3036% %
3037%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3038%
3039% GetVirtualIndexesFromNexus() returns the indexes associated with the
3040% specified cache nexus.
3041%
3042% The format of the GetVirtualIndexesFromNexus() method is:
3043%
3044% const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
3045% NexusInfo *nexus_info)
3046%
3047% A description of each parameter follows:
3048%
3049% o cache: the pixel cache.
3050%
3051% o nexus_info: the cache nexus to return the colormap indexes.
3052%
3053*/
3054MagickExport const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
3055 NexusInfo *nexus_info)
3056{
3057 CacheInfo
3058 *cache_info;
3059
3060 if (cache == (Cache) NULL)
3061 return((IndexPacket *) NULL);
3062 cache_info=(CacheInfo *) cache;
3063 assert(cache_info->signature == MagickSignature);
3064 if (cache_info->storage_class == UndefinedClass)
3065 return((IndexPacket *) NULL);
3066 return(nexus_info->indexes);
3067}
3068
3069/*
3070%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3071% %
3072% %
3073% %
3074% G e t V i r t u a l I n d e x Q u e u e %
3075% %
3076% %
3077% %
3078%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3079%
3080% GetVirtualIndexQueue() returns the virtual black channel or the
3081% colormap indexes associated with the last call to QueueAuthenticPixels() or
3082% GetVirtualPixels(). NULL is returned if the black channel or colormap
3083% indexes are not available.
3084%
3085% The format of the GetVirtualIndexQueue() method is:
3086%
3087% const IndexPacket *GetVirtualIndexQueue(const Image *image)
3088%
3089% A description of each parameter follows:
3090%
3091% o image: the image.
3092%
3093*/
3094MagickExport const IndexPacket *GetVirtualIndexQueue(const Image *image)
3095{
3096 CacheInfo
3097 *cache_info;
3098
3099 assert(image != (const Image *) NULL);
3100 assert(image->signature == MagickSignature);
3101 if (image->debug != MagickFalse)
3102 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3103 assert(image->cache != (Cache) NULL);
3104 cache_info=(CacheInfo *) image->cache;
3105 assert(cache_info->signature == MagickSignature);
3106 if (cache_info->methods.get_virtual_indexes_from_handler ==
3107 (GetVirtualIndexesFromHandler) NULL)
3108 return((IndexPacket *) NULL);
3109 return(cache_info->methods.get_virtual_indexes_from_handler(image));
3110}
3111
3112/*
3113%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3114% %
3115% %
3116% %
3117+ 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 %
3118% %
3119% %
3120% %
3121%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3122%
3123% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3124% pixel cache as defined by the geometry parameters. A pointer to the pixels
3125% is returned if the pixels are transferred, otherwise a NULL is returned.
3126%
3127% The format of the GetVirtualPixelsFromNexus() method is:
3128%
3129% PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
3130% const VirtualPixelMethod method,const long x,const long y,
3131% const unsigned long columns,const unsigned long rows,
3132% NexusInfo *nexus_info,ExceptionInfo *exception)
3133%
3134% A description of each parameter follows:
3135%
3136% o image: the image.
3137%
3138% o virtual_pixel_method: the virtual pixel method.
3139%
3140% o x,y,columns,rows: These values define the perimeter of a region of
3141% pixels.
3142%
3143% o nexus_info: the cache nexus to acquire.
3144%
3145% o exception: return any errors or warnings in this structure.
3146%
3147*/
3148
3149static long
3150 DitherMatrix[64] =
3151 {
3152 0, 48, 12, 60, 3, 51, 15, 63,
3153 32, 16, 44, 28, 35, 19, 47, 31,
3154 8, 56, 4, 52, 11, 59, 7, 55,
3155 40, 24, 36, 20, 43, 27, 39, 23,
3156 2, 50, 14, 62, 1, 49, 13, 61,
3157 34, 18, 46, 30, 33, 17, 45, 29,
3158 10, 58, 6, 54, 9, 57, 5, 53,
3159 42, 26, 38, 22, 41, 25, 37, 21
3160 };
3161
cristy222528c2010-01-09 23:36:34 +00003162static inline long DitherX(const long x,const unsigned long columns)
cristy3ed852e2009-09-05 21:47:34 +00003163{
3164 long
3165 index;
3166
3167 index=x+DitherMatrix[x & 0x07]-32L;
3168 if (index < 0L)
3169 return(0L);
3170 if (index >= (long) columns)
3171 return((long) columns-1L);
3172 return(index);
3173}
3174
cristy222528c2010-01-09 23:36:34 +00003175static inline long DitherY(const long y,const unsigned long rows)
cristy3ed852e2009-09-05 21:47:34 +00003176{
3177 long
3178 index;
3179
3180 index=y+DitherMatrix[y & 0x07]-32L;
3181 if (index < 0L)
3182 return(0L);
3183 if (index >= (long) rows)
3184 return((long) rows-1L);
3185 return(index);
3186}
3187
cristy222528c2010-01-09 23:36:34 +00003188static inline long EdgeX(const long x,const unsigned long columns)
cristy3ed852e2009-09-05 21:47:34 +00003189{
3190 if (x < 0L)
3191 return(0L);
3192 if (x >= (long) columns)
cristy97be2b92010-01-09 23:37:55 +00003193 return((long) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003194 return(x);
3195}
3196
cristy222528c2010-01-09 23:36:34 +00003197static inline long EdgeY(const long y,const unsigned long rows)
cristy3ed852e2009-09-05 21:47:34 +00003198{
3199 if (y < 0L)
3200 return(0L);
3201 if (y >= (long) rows)
cristy97be2b92010-01-09 23:37:55 +00003202 return((long) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003203 return(y);
3204}
3205
cristy222528c2010-01-09 23:36:34 +00003206static inline long RandomX(RandomInfo *random_info,const unsigned long columns)
cristy3ed852e2009-09-05 21:47:34 +00003207{
3208 return((long) (columns*GetPseudoRandomValue(random_info)));
3209}
3210
cristy222528c2010-01-09 23:36:34 +00003211static inline long RandomY(RandomInfo *random_info,const unsigned long rows)
cristy3ed852e2009-09-05 21:47:34 +00003212{
3213 return((long) (rows*GetPseudoRandomValue(random_info)));
3214}
3215
3216/*
3217 VirtualPixelModulo() computes the remainder of dividing offset by extent. It
3218 returns not only the quotient (tile the offset falls in) but also the positive
3219 remainer within that tile such that 0 <= remainder < extent. This method is
3220 essentially a ldiv() using a floored modulo division rather than the normal
3221 default truncated modulo division.
3222*/
3223static inline MagickModulo VirtualPixelModulo(const long offset,
3224 const unsigned long extent)
3225{
3226 MagickModulo
3227 modulo;
3228
3229 modulo.quotient=offset/(long) extent;
3230 if (offset < 0L)
3231 modulo.quotient--;
3232 modulo.remainder=offset-modulo.quotient*(long) extent;
3233 return(modulo);
3234}
3235
3236MagickExport const PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
3237 const VirtualPixelMethod virtual_pixel_method,const long x,const long y,
3238 const unsigned long columns,const unsigned long rows,NexusInfo *nexus_info,
3239 ExceptionInfo *exception)
3240{
3241 CacheInfo
3242 *cache_info;
3243
3244 MagickOffsetType
3245 offset;
3246
3247 MagickSizeType
3248 length,
3249 number_pixels;
3250
3251 NexusInfo
3252 **virtual_nexus;
3253
3254 PixelPacket
3255 *pixels,
3256 virtual_pixel;
3257
3258 RectangleInfo
3259 region;
3260
3261 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003262 *restrict nexus_indexes;
cristy3ed852e2009-09-05 21:47:34 +00003263
3264 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003265 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003266
3267 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003268 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003269
3270 register long
3271 u,
3272 v;
3273
3274 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003275 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003276
3277 /*
3278 Acquire pixels.
3279 */
3280 if (image->debug != MagickFalse)
3281 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3282 cache_info=(CacheInfo *) image->cache;
3283 if (cache_info->type == UndefinedCache)
3284 return((const PixelPacket *) NULL);
3285 region.x=x;
3286 region.y=y;
3287 region.width=columns;
3288 region.height=rows;
3289 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
3290 if (pixels == (PixelPacket *) NULL)
3291 return((const PixelPacket *) NULL);
3292 offset=(MagickOffsetType) region.y*cache_info->columns+region.x;
cristy4789f0d2010-01-10 00:01:06 +00003293 length=(MagickSizeType) (region.height-1L)*cache_info->columns+
3294 region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003295 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3296 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
3297 if ((x >= 0) && ((long) (x+columns) <= (long) cache_info->columns) &&
3298 (y >= 0) && ((long) (y+rows) <= (long) cache_info->rows))
3299 {
3300 MagickBooleanType
3301 status;
3302
3303 /*
3304 Pixel request is inside cache extents.
3305 */
3306 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
3307 return(pixels);
3308 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3309 if (status == MagickFalse)
3310 return((const PixelPacket *) NULL);
3311 if ((cache_info->storage_class == PseudoClass) ||
3312 (cache_info->colorspace == CMYKColorspace))
3313 {
3314 status=ReadPixelCacheIndexes(cache_info,nexus_info,exception);
3315 if (status == MagickFalse)
3316 return((const PixelPacket *) NULL);
3317 }
3318 return(pixels);
3319 }
3320 /*
3321 Pixel request is outside cache extents.
3322 */
3323 q=pixels;
3324 indexes=GetPixelCacheNexusIndexes(cache_info,nexus_info);
3325 virtual_nexus=AcquirePixelCacheNexus(1);
3326 if (virtual_nexus == (NexusInfo **) NULL)
3327 {
3328 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3329 "UnableToGetCacheNexus","`%s'",image->filename);
3330 return((const PixelPacket *) NULL);
3331 }
3332 switch (virtual_pixel_method)
3333 {
3334 case BlackVirtualPixelMethod:
3335 {
cristy4789f0d2010-01-10 00:01:06 +00003336 SetRedPixelComponent(&virtual_pixel,0);
3337 SetGreenPixelComponent(&virtual_pixel,0);
3338 SetBluePixelComponent(&virtual_pixel,0);
3339 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003340 break;
3341 }
3342 case GrayVirtualPixelMethod:
3343 {
cristy4789f0d2010-01-10 00:01:06 +00003344 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3345 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3346 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3347 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003348 break;
3349 }
3350 case TransparentVirtualPixelMethod:
3351 {
cristy4789f0d2010-01-10 00:01:06 +00003352 SetRedPixelComponent(&virtual_pixel,0);
3353 SetGreenPixelComponent(&virtual_pixel,0);
3354 SetBluePixelComponent(&virtual_pixel,0);
3355 SetOpacityPixelComponent(&virtual_pixel,TransparentOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003356 break;
3357 }
3358 case MaskVirtualPixelMethod:
3359 case WhiteVirtualPixelMethod:
3360 {
cristy4789f0d2010-01-10 00:01:06 +00003361 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3362 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3363 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3364 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003365 break;
3366 }
3367 default:
3368 {
3369 virtual_pixel=image->background_color;
3370 break;
3371 }
3372 }
3373 for (v=0; v < (long) rows; v++)
3374 {
3375 for (u=0; u < (long) columns; u+=length)
3376 {
3377 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
3378 if ((((x+u) < 0) || ((x+u) >= (long) cache_info->columns)) ||
3379 (((y+v) < 0) || ((y+v) >= (long) cache_info->rows)) || (length == 0))
3380 {
3381 MagickModulo
3382 x_modulo,
3383 y_modulo;
3384
3385 /*
3386 Transfer a single pixel.
3387 */
3388 length=(MagickSizeType) 1;
3389 switch (virtual_pixel_method)
3390 {
3391 case BackgroundVirtualPixelMethod:
3392 case ConstantVirtualPixelMethod:
3393 case BlackVirtualPixelMethod:
3394 case GrayVirtualPixelMethod:
3395 case TransparentVirtualPixelMethod:
3396 case MaskVirtualPixelMethod:
3397 case WhiteVirtualPixelMethod:
3398 {
3399 p=(&virtual_pixel);
3400 break;
3401 }
3402 case EdgeVirtualPixelMethod:
3403 default:
3404 {
3405 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003406 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003407 1UL,1UL,virtual_nexus[0],exception);
3408 break;
3409 }
3410 case RandomVirtualPixelMethod:
3411 {
3412 if (cache_info->random_info == (RandomInfo *) NULL)
3413 cache_info->random_info=AcquireRandomInfo();
3414 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003415 RandomX(cache_info->random_info,cache_info->columns),
3416 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003417 virtual_nexus[0],exception);
3418 break;
3419 }
3420 case DitherVirtualPixelMethod:
3421 {
3422 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003423 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003424 1UL,1UL,virtual_nexus[0],exception);
3425 break;
3426 }
3427 case TileVirtualPixelMethod:
3428 {
3429 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3430 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3431 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3432 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3433 exception);
3434 break;
3435 }
3436 case MirrorVirtualPixelMethod:
3437 {
3438 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3439 if ((x_modulo.quotient & 0x01) == 1L)
3440 x_modulo.remainder=(long) cache_info->columns-
3441 x_modulo.remainder-1L;
3442 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3443 if ((y_modulo.quotient & 0x01) == 1L)
3444 y_modulo.remainder=(long) cache_info->rows-
3445 y_modulo.remainder-1L;
3446 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3447 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3448 exception);
3449 break;
3450 }
3451 case CheckerTileVirtualPixelMethod:
3452 {
3453 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3454 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3455 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3456 {
3457 p=(&virtual_pixel);
3458 break;
3459 }
3460 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3461 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3462 exception);
3463 break;
3464 }
3465 case HorizontalTileVirtualPixelMethod:
3466 {
3467 if (((y+v) < 0) || ((y+v) >= (long) cache_info->rows))
3468 {
3469 p=(&virtual_pixel);
3470 break;
3471 }
3472 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3473 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3474 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3475 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3476 exception);
3477 break;
3478 }
3479 case VerticalTileVirtualPixelMethod:
3480 {
3481 if (((x+u) < 0) || ((x+u) >= (long) cache_info->columns))
3482 {
3483 p=(&virtual_pixel);
3484 break;
3485 }
3486 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3487 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3488 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3489 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3490 exception);
3491 break;
3492 }
3493 case HorizontalTileEdgeVirtualPixelMethod:
3494 {
3495 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3496 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003497 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003498 virtual_nexus[0],exception);
3499 break;
3500 }
3501 case VerticalTileEdgeVirtualPixelMethod:
3502 {
3503 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3504 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003505 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003506 virtual_nexus[0],exception);
3507 break;
3508 }
3509 }
3510 if (p == (const PixelPacket *) NULL)
3511 break;
3512 *q++=(*p);
3513 if (indexes != (IndexPacket *) NULL)
3514 {
3515 nexus_indexes=GetVirtualIndexesFromNexus(cache_info,
3516 virtual_nexus[0]);
3517 if (nexus_indexes != (const IndexPacket *) NULL)
3518 *indexes++=(*nexus_indexes);
3519 }
3520 continue;
3521 }
3522 /*
3523 Transfer a run of pixels.
3524 */
3525 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,
3526 (unsigned long) length,1UL,virtual_nexus[0],exception);
3527 if (p == (const PixelPacket *) NULL)
3528 break;
3529 (void) CopyMagickMemory(q,p,(size_t) length*sizeof(*p));
3530 q+=length;
3531 if (indexes != (IndexPacket *) NULL)
3532 {
3533 nexus_indexes=GetVirtualIndexesFromNexus(cache_info,virtual_nexus[0]);
3534 if (nexus_indexes != (const IndexPacket *) NULL)
3535 {
3536 (void) CopyMagickMemory(indexes,nexus_indexes,(size_t) length*
3537 sizeof(*nexus_indexes));
3538 indexes+=length;
3539 }
3540 }
3541 }
3542 }
3543 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3544 return(pixels);
3545}
3546
3547/*
3548%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3549% %
3550% %
3551% %
3552+ G e t V i r t u a l P i x e l C a c h e %
3553% %
3554% %
3555% %
3556%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3557%
3558% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3559% cache as defined by the geometry parameters. A pointer to the pixels
3560% is returned if the pixels are transferred, otherwise a NULL is returned.
3561%
3562% The format of the GetVirtualPixelCache() method is:
3563%
3564% const PixelPacket *GetVirtualPixelCache(const Image *image,
3565% const VirtualPixelMethod virtual_pixel_method,const long x,
3566% const long y,const unsigned long columns,const unsigned long rows,
3567% ExceptionInfo *exception)
3568%
3569% A description of each parameter follows:
3570%
3571% o image: the image.
3572%
3573% o virtual_pixel_method: the virtual pixel method.
3574%
3575% o x,y,columns,rows: These values define the perimeter of a region of
3576% pixels.
3577%
3578% o exception: return any errors or warnings in this structure.
3579%
3580*/
3581static const PixelPacket *GetVirtualPixelCache(const Image *image,
3582 const VirtualPixelMethod virtual_pixel_method,const long x,const long y,
3583 const unsigned long columns,const unsigned long rows,ExceptionInfo *exception)
3584{
3585 CacheInfo
3586 *cache_info;
3587
3588 const PixelPacket
3589 *pixels;
3590
3591 long
3592 id;
3593
3594 if (image->debug != MagickFalse)
3595 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3596 cache_info=(CacheInfo *) image->cache;
3597 id=GetOpenMPThreadId();
3598 assert(id < (long) cache_info->number_threads);
3599 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3600 cache_info->nexus_info[id],exception);
3601 return(pixels);
3602}
3603
3604/*
3605%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3606% %
3607% %
3608% %
3609% G e t V i r t u a l P i x e l Q u e u e %
3610% %
3611% %
3612% %
3613%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3614%
3615% GetVirtualPixelQueue() returns the virtual pixels associated with the
3616% last call to QueueAuthenticPixels() or GetVirtualPixels().
3617%
3618% The format of the GetVirtualPixelQueue() method is:
3619%
3620% const PixelPacket *GetVirtualPixelQueue(const Image image)
3621%
3622% A description of each parameter follows:
3623%
3624% o image: the image.
3625%
3626*/
3627MagickExport const PixelPacket *GetVirtualPixelQueue(const Image *image)
3628{
3629 CacheInfo
3630 *cache_info;
3631
3632 assert(image != (const Image *) NULL);
3633 assert(image->signature == MagickSignature);
3634 if (image->debug != MagickFalse)
3635 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3636 assert(image->cache != (Cache) NULL);
3637 cache_info=(CacheInfo *) image->cache;
3638 assert(cache_info->signature == MagickSignature);
3639 if (cache_info->methods.get_virtual_pixels_handler ==
3640 (GetVirtualPixelsHandler) NULL)
3641 return((PixelPacket *) NULL);
3642 return(cache_info->methods.get_virtual_pixels_handler(image));
3643}
3644
3645/*
3646%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3647% %
3648% %
3649% %
3650% G e t V i r t u a l P i x e l s %
3651% %
3652% %
3653% %
3654%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3655%
3656% GetVirtualPixels() returns an immutable pixel region. If the
3657% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003658% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003659% copy of the pixels or it may point to the original pixels in memory.
3660% Performance is maximized if the selected region is part of one row, or one
3661% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003662% (without a copy) if the image is in memory, or in a memory-mapped file. The
3663% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003664%
3665% Pixels accessed via the returned pointer represent a simple array of type
3666% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
3667% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to access
3668% the black color component or to obtain the colormap indexes (of type
3669% IndexPacket) corresponding to the region.
3670%
3671% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3672%
3673% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3674% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3675% GetCacheViewAuthenticPixels() instead.
3676%
3677% The format of the GetVirtualPixels() method is:
3678%
3679% const PixelPacket *GetVirtualPixels(const Image *image,const long x,
3680% const long y,const unsigned long columns,const unsigned long rows,
3681% ExceptionInfo *exception)
3682%
3683% A description of each parameter follows:
3684%
3685% o image: the image.
3686%
3687% o x,y,columns,rows: These values define the perimeter of a region of
3688% pixels.
3689%
3690% o exception: return any errors or warnings in this structure.
3691%
3692*/
3693MagickExport const PixelPacket *GetVirtualPixels(const Image *image,
3694 const long x,const long y,const unsigned long columns,
3695 const unsigned long rows,ExceptionInfo *exception)
3696{
3697 CacheInfo
3698 *cache_info;
3699
3700 const PixelPacket
3701 *pixels;
3702
3703 assert(image != (const Image *) NULL);
3704 assert(image->signature == MagickSignature);
3705 if (image->debug != MagickFalse)
3706 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3707 assert(image->cache != (Cache) NULL);
3708 cache_info=(CacheInfo *) image->cache;
3709 assert(cache_info->signature == MagickSignature);
3710 if (cache_info->methods.get_virtual_pixel_handler ==
3711 (GetVirtualPixelHandler) NULL)
3712 return((const PixelPacket *) NULL);
3713 pixels=cache_info->methods.get_virtual_pixel_handler(image,
3714 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception);
3715 return(pixels);
3716}
3717
3718/*
3719%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3720% %
3721% %
3722% %
3723+ 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 %
3724% %
3725% %
3726% %
3727%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3728%
3729% GetVirtualPixelsCache() returns the pixels associated with the last call
3730% to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3731%
3732% The format of the GetVirtualPixelsCache() method is:
3733%
3734% PixelPacket *GetVirtualPixelsCache(const Image *image)
3735%
3736% A description of each parameter follows:
3737%
3738% o image: the image.
3739%
3740*/
3741static const PixelPacket *GetVirtualPixelsCache(const Image *image)
3742{
3743 CacheInfo
3744 *cache_info;
3745
3746 const PixelPacket
3747 *pixels;
3748
3749 long
3750 id;
3751
3752 if (image->debug != MagickFalse)
3753 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3754 cache_info=(CacheInfo *) image->cache;
3755 id=GetOpenMPThreadId();
3756 assert(id < (long) cache_info->number_threads);
3757 pixels=GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]);
3758 return(pixels);
3759}
3760
3761/*
3762%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3763% %
3764% %
3765% %
3766+ G e t V i r t u a l P i x e l s N e x u s %
3767% %
3768% %
3769% %
3770%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3771%
3772% GetVirtualPixelsNexus() returns the pixels associated with the specified
3773% cache nexus.
3774%
3775% The format of the GetVirtualPixelsNexus() method is:
3776%
3777% const IndexPacket *GetVirtualPixelsNexus(const Cache cache,
3778% NexusInfo *nexus_info)
3779%
3780% A description of each parameter follows:
3781%
3782% o cache: the pixel cache.
3783%
3784% o nexus_info: the cache nexus to return the colormap pixels.
3785%
3786*/
3787MagickExport const PixelPacket *GetVirtualPixelsNexus(const Cache cache,
3788 NexusInfo *nexus_info)
3789{
3790 CacheInfo
3791 *cache_info;
3792
3793 if (cache == (Cache) NULL)
3794 return((PixelPacket *) NULL);
3795 cache_info=(CacheInfo *) cache;
3796 assert(cache_info->signature == MagickSignature);
3797 if (cache_info->storage_class == UndefinedClass)
3798 return((PixelPacket *) NULL);
3799 return((const PixelPacket *) nexus_info->pixels);
3800}
3801
3802/*
3803%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3804% %
3805% %
3806% %
3807+ M a s k P i x e l C a c h e N e x u s %
3808% %
3809% %
3810% %
3811%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3812%
3813% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3814% The method returns MagickTrue if the pixel region is masked, otherwise
3815% MagickFalse.
3816%
3817% The format of the MaskPixelCacheNexus() method is:
3818%
3819% MagickBooleanType MaskPixelCacheNexus(Image *image,
3820% NexusInfo *nexus_info,ExceptionInfo *exception)
3821%
3822% A description of each parameter follows:
3823%
3824% o image: the image.
3825%
3826% o nexus_info: the cache nexus to clip.
3827%
3828% o exception: return any errors or warnings in this structure.
3829%
3830*/
3831
3832static inline void MagickPixelCompositeMask(const MagickPixelPacket *p,
3833 const MagickRealType alpha,const MagickPixelPacket *q,
3834 const MagickRealType beta,MagickPixelPacket *composite)
3835{
3836 MagickRealType
3837 gamma;
3838
3839 if (alpha == TransparentOpacity)
3840 {
3841 *composite=(*q);
3842 return;
3843 }
3844 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3845 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3846 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3847 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3848 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3849 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3850 composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
3851}
3852
3853static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3854 ExceptionInfo *exception)
3855{
3856 CacheInfo
3857 *cache_info;
3858
3859 MagickPixelPacket
3860 alpha,
3861 beta;
3862
3863 MagickSizeType
3864 number_pixels;
3865
3866 NexusInfo
3867 **clip_nexus,
3868 **image_nexus;
3869
3870 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003871 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003872
3873 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003874 *restrict nexus_indexes,
3875 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003876
3877 register long
3878 i;
3879
3880 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003881 *restrict p,
3882 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003883
3884 /*
3885 Apply clip mask.
3886 */
3887 if (image->debug != MagickFalse)
3888 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3889 if (image->mask == (Image *) NULL)
3890 return(MagickFalse);
3891 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
3892 if (cache_info == (Cache) NULL)
3893 return(MagickFalse);
3894 image_nexus=AcquirePixelCacheNexus(1);
3895 clip_nexus=AcquirePixelCacheNexus(1);
3896 if ((image_nexus == (NexusInfo **) NULL) ||
3897 (clip_nexus == (NexusInfo **) NULL))
3898 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy09449f72010-01-23 03:08:36 +00003899 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,
3900 nexus_info->region.y,nexus_info->region.width,nexus_info->region.height,
3901 image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003902 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
3903 q=nexus_info->pixels;
3904 nexus_indexes=nexus_info->indexes;
3905 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3906 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3907 nexus_info->region.height,clip_nexus[0],&image->exception);
3908 GetMagickPixelPacket(image,&alpha);
3909 GetMagickPixelPacket(image,&beta);
3910 number_pixels=(MagickSizeType) nexus_info->region.width*
3911 nexus_info->region.height;
3912 for (i=0; i < (long) number_pixels; i++)
3913 {
3914 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
3915 break;
3916 SetMagickPixelPacket(image,p,indexes+i,&alpha);
3917 SetMagickPixelPacket(image,q,nexus_indexes+i,&beta);
3918 MagickPixelCompositeMask(&beta,(MagickRealType) PixelIntensityToQuantum(r),
3919 &alpha,alpha.opacity,&beta);
cristyce70c172010-01-07 17:15:30 +00003920 q->red=ClampToQuantum(beta.red);
3921 q->green=ClampToQuantum(beta.green);
3922 q->blue=ClampToQuantum(beta.blue);
3923 q->opacity=ClampToQuantum(beta.opacity);
cristy3ed852e2009-09-05 21:47:34 +00003924 if (cache_info->active_index_channel != MagickFalse)
3925 nexus_indexes[i]=indexes[i];
3926 p++;
3927 q++;
3928 r++;
3929 }
3930 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3931 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
3932 if (i < (long) number_pixels)
3933 return(MagickFalse);
3934 return(MagickTrue);
3935}
3936
3937/*
3938%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3939% %
3940% %
3941% %
3942+ O p e n P i x e l C a c h e %
3943% %
3944% %
3945% %
3946%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3947%
3948% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3949% dimensions, allocating space for the image pixels and optionally the
3950% colormap indexes, and memory mapping the cache if it is disk based. The
3951% cache nexus array is initialized as well.
3952%
3953% The format of the OpenPixelCache() method is:
3954%
3955% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3956% ExceptionInfo *exception)
3957%
3958% A description of each parameter follows:
3959%
3960% o image: the image.
3961%
3962% o mode: ReadMode, WriteMode, or IOMode.
3963%
3964% o exception: return any errors or warnings in this structure.
3965%
3966*/
3967
cristyd43a46b2010-01-21 02:13:41 +00003968static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003969{
3970 cache_info->mapped=MagickFalse;
3971 cache_info->pixels=(PixelPacket *) AcquireMagickMemory((size_t)
3972 cache_info->length);
3973 if (cache_info->pixels == (PixelPacket *) NULL)
3974 {
3975 cache_info->mapped=MagickTrue;
3976 cache_info->pixels=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
3977 cache_info->length);
3978 }
3979}
3980
3981static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3982{
3983 CacheInfo
3984 *cache_info;
3985
3986 MagickOffsetType
3987 count,
3988 extent,
3989 offset;
3990
3991 cache_info=(CacheInfo *) image->cache;
3992 if (image->debug != MagickFalse)
3993 {
3994 char
3995 format[MaxTextExtent],
3996 message[MaxTextExtent];
3997
cristyb9080c92009-12-01 20:13:26 +00003998 (void) FormatMagickSize(length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00003999 (void) FormatMagickString(message,MaxTextExtent,
4000 "extend %s (%s[%d], disk, %s)",cache_info->filename,
4001 cache_info->cache_filename,cache_info->file,format);
4002 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4003 }
4004 if (length != (MagickSizeType) ((MagickOffsetType) length))
4005 return(MagickFalse);
4006 extent=(MagickOffsetType) MagickSeek(cache_info->file,0,SEEK_END);
4007 if (extent < 0)
4008 return(MagickFalse);
4009 if ((MagickSizeType) extent >= length)
4010 return(MagickTrue);
4011 offset=(MagickOffsetType) length-1;
4012 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
4013 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
4014}
4015
4016static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
4017 ExceptionInfo *exception)
4018{
4019 char
4020 format[MaxTextExtent],
4021 message[MaxTextExtent];
4022
4023 CacheInfo
4024 *cache_info,
4025 source_info;
4026
4027 MagickSizeType
4028 length,
4029 number_pixels;
4030
4031 MagickStatusType
4032 status;
4033
4034 size_t
4035 packet_size;
4036
4037 unsigned long
4038 columns;
4039
4040 if (image->debug != MagickFalse)
4041 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4042 if ((image->columns == 0) || (image->rows == 0))
4043 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
4044 cache_info=(CacheInfo *) image->cache;
4045 source_info=(*cache_info);
4046 source_info.file=(-1);
4047 (void) FormatMagickString(cache_info->filename,MaxTextExtent,"%s[%ld]",
4048 image->filename,GetImageIndexInList(image));
cristy87528ea2009-09-10 14:53:56 +00004049 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +00004050 cache_info->rows=image->rows;
4051 cache_info->columns=image->columns;
4052 cache_info->active_index_channel=((image->storage_class == PseudoClass) ||
4053 (image->colorspace == CMYKColorspace)) ? MagickTrue : MagickFalse;
4054 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4055 packet_size=sizeof(PixelPacket);
4056 if (cache_info->active_index_channel != MagickFalse)
4057 packet_size+=sizeof(IndexPacket);
4058 length=number_pixels*packet_size;
4059 columns=(unsigned long) (length/cache_info->rows/packet_size);
4060 if (cache_info->columns != columns)
4061 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4062 image->filename);
4063 cache_info->length=length;
4064 status=AcquireMagickResource(AreaResource,cache_info->length);
4065 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4066 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4067 {
4068 status=AcquireMagickResource(MemoryResource,cache_info->length);
4069 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4070 (cache_info->type == MemoryCache))
4071 {
cristyd43a46b2010-01-21 02:13:41 +00004072 AllocatePixelCachePixels(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004073 if (cache_info->pixels == (PixelPacket *) NULL)
4074 cache_info->pixels=source_info.pixels;
4075 else
4076 {
4077 /*
4078 Create memory pixel cache.
4079 */
4080 if (image->debug != MagickFalse)
4081 {
cristy97e7a572009-12-05 15:07:53 +00004082 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004083 format);
cristy3ed852e2009-09-05 21:47:34 +00004084 (void) FormatMagickString(message,MaxTextExtent,
4085 "open %s (%s memory, %lux%lu %s)",cache_info->filename,
4086 cache_info->mapped != MagickFalse ? "anonymous" : "heap",
4087 cache_info->columns,cache_info->rows,format);
4088 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4089 message);
4090 }
4091 cache_info->storage_class=image->storage_class;
4092 cache_info->colorspace=image->colorspace;
4093 cache_info->type=MemoryCache;
4094 cache_info->indexes=(IndexPacket *) NULL;
4095 if (cache_info->active_index_channel != MagickFalse)
4096 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4097 number_pixels);
4098 if (source_info.storage_class != UndefinedClass)
4099 {
4100 status|=ClonePixelCachePixels(cache_info,&source_info,
4101 exception);
4102 RelinquishPixelCachePixels(&source_info);
4103 }
4104 return(MagickTrue);
4105 }
4106 }
4107 RelinquishMagickResource(MemoryResource,cache_info->length);
4108 }
4109 /*
4110 Create pixel cache on disk.
4111 */
4112 status=AcquireMagickResource(DiskResource,cache_info->length);
4113 if (status == MagickFalse)
4114 {
4115 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4116 "CacheResourcesExhausted","`%s'",image->filename);
4117 return(MagickFalse);
4118 }
4119 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4120 {
4121 RelinquishMagickResource(DiskResource,cache_info->length);
4122 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4123 image->filename);
4124 return(MagickFalse);
4125 }
4126 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4127 cache_info->length);
4128 if (status == MagickFalse)
4129 {
4130 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4131 image->filename);
4132 return(MagickFalse);
4133 }
4134 cache_info->storage_class=image->storage_class;
4135 cache_info->colorspace=image->colorspace;
4136 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4137 status=AcquireMagickResource(AreaResource,cache_info->length);
4138 if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4139 cache_info->type=DiskCache;
4140 else
4141 {
4142 status=AcquireMagickResource(MapResource,cache_info->length);
4143 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4144 (cache_info->type != MemoryCache))
4145 cache_info->type=DiskCache;
4146 else
4147 {
4148 cache_info->pixels=(PixelPacket *) MapBlob(cache_info->file,mode,
4149 cache_info->offset,(size_t) cache_info->length);
4150 if (cache_info->pixels == (PixelPacket *) NULL)
4151 {
4152 cache_info->pixels=source_info.pixels;
4153 cache_info->type=DiskCache;
4154 }
4155 else
4156 {
4157 /*
4158 Create file-backed memory-mapped pixel cache.
4159 */
4160 (void) ClosePixelCacheOnDisk(cache_info);
4161 cache_info->type=MapCache;
4162 cache_info->mapped=MagickTrue;
4163 cache_info->indexes=(IndexPacket *) NULL;
4164 if (cache_info->active_index_channel != MagickFalse)
4165 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4166 number_pixels);
4167 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4168 {
4169 status=ClonePixelCachePixels(cache_info,&source_info,
4170 exception);
4171 RelinquishPixelCachePixels(&source_info);
4172 }
4173 if (image->debug != MagickFalse)
4174 {
cristy97e7a572009-12-05 15:07:53 +00004175 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004176 format);
cristy3ed852e2009-09-05 21:47:34 +00004177 (void) FormatMagickString(message,MaxTextExtent,
4178 "open %s (%s[%d], memory-mapped, %lux%lu %s)",
4179 cache_info->filename,cache_info->cache_filename,
4180 cache_info->file,cache_info->columns,cache_info->rows,
4181 format);
4182 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4183 message);
4184 }
4185 return(MagickTrue);
4186 }
4187 }
4188 RelinquishMagickResource(MapResource,cache_info->length);
4189 }
4190 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4191 {
4192 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4193 RelinquishPixelCachePixels(&source_info);
4194 }
4195 if (image->debug != MagickFalse)
4196 {
cristyb9080c92009-12-01 20:13:26 +00004197 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00004198 (void) FormatMagickString(message,MaxTextExtent,
4199 "open %s (%s[%d], disk, %lux%lu %s)",cache_info->filename,
4200 cache_info->cache_filename,cache_info->file,cache_info->columns,
4201 cache_info->rows,format);
4202 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4203 }
4204 return(MagickTrue);
4205}
4206
4207/*
4208%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4209% %
4210% %
4211% %
4212+ P e r s i s t P i x e l C a c h e %
4213% %
4214% %
4215% %
4216%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4217%
4218% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4219% persistent pixel cache is one that resides on disk and is not destroyed
4220% when the program exits.
4221%
4222% The format of the PersistPixelCache() method is:
4223%
4224% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4225% const MagickBooleanType attach,MagickOffsetType *offset,
4226% ExceptionInfo *exception)
4227%
4228% A description of each parameter follows:
4229%
4230% o image: the image.
4231%
4232% o filename: the persistent pixel cache filename.
4233%
cristy01b7eb02009-09-10 23:10:14 +00004234% o attach: A value other than zero initializes the persistent pixel
4235% cache.
4236%
cristy3ed852e2009-09-05 21:47:34 +00004237% o initialize: A value other than zero initializes the persistent pixel
4238% cache.
4239%
4240% o offset: the offset in the persistent cache to store pixels.
4241%
4242% o exception: return any errors or warnings in this structure.
4243%
4244*/
4245MagickExport MagickBooleanType PersistPixelCache(Image *image,
4246 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4247 ExceptionInfo *exception)
4248{
4249 CacheInfo
4250 *cache_info,
4251 *clone_info;
4252
4253 Image
4254 clone_image;
4255
4256 long
cristy688f07b2009-09-27 15:19:13 +00004257 page_size;
cristy3ed852e2009-09-05 21:47:34 +00004258
4259 MagickBooleanType
4260 status;
4261
4262 assert(image != (Image *) NULL);
4263 assert(image->signature == MagickSignature);
4264 if (image->debug != MagickFalse)
4265 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4266 assert(image->cache != (void *) NULL);
4267 assert(filename != (const char *) NULL);
4268 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004269 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004270 cache_info=(CacheInfo *) image->cache;
4271 assert(cache_info->signature == MagickSignature);
4272 if (attach != MagickFalse)
4273 {
4274 /*
cristy01b7eb02009-09-10 23:10:14 +00004275 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004276 */
4277 if (image->debug != MagickFalse)
4278 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4279 "attach persistent cache");
4280 (void) CopyMagickString(cache_info->cache_filename,filename,
4281 MaxTextExtent);
4282 cache_info->type=DiskCache;
4283 cache_info->offset=(*offset);
4284 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4285 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004286 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004287 return(MagickTrue);
4288 }
cristy01b7eb02009-09-10 23:10:14 +00004289 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4290 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004291 {
cristyf84a1932010-01-03 18:00:18 +00004292 LockSemaphoreInfo(cache_info->semaphore);
cristy09449f72010-01-23 03:08:36 +00004293 if ((cache_info->mode != ReadMode) &&
4294 (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004295 (cache_info->reference_count == 1))
4296 {
4297 int
4298 status;
4299
4300 /*
cristy01b7eb02009-09-10 23:10:14 +00004301 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004302 */
4303 status=rename(cache_info->cache_filename,filename);
4304 if (status == 0)
4305 {
4306 (void) CopyMagickString(cache_info->cache_filename,filename,
4307 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004308 *offset+=cache_info->length+page_size-(cache_info->length %
4309 page_size);
cristyf84a1932010-01-03 18:00:18 +00004310 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004311 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004312 if (image->debug != MagickFalse)
4313 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4314 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004315 return(MagickTrue);
4316 }
4317 }
cristyf84a1932010-01-03 18:00:18 +00004318 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004319 }
4320 /*
cristy01b7eb02009-09-10 23:10:14 +00004321 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004322 */
4323 clone_image=(*image);
4324 clone_info=(CacheInfo *) clone_image.cache;
4325 image->cache=ClonePixelCache(cache_info);
4326 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4327 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4328 cache_info->type=DiskCache;
4329 cache_info->offset=(*offset);
4330 cache_info=(CacheInfo *) image->cache;
4331 status=ClonePixelCacheNexus(cache_info,clone_info,exception);
4332 if (status != MagickFalse)
4333 {
4334 status=OpenPixelCache(image,IOMode,exception);
4335 if (status != MagickFalse)
4336 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
4337 }
cristy688f07b2009-09-27 15:19:13 +00004338 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004339 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4340 return(status);
4341}
4342
4343/*
4344%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4345% %
4346% %
4347% %
4348+ Q u e u e A u t h e n t i c N e x u s %
4349% %
4350% %
4351% %
4352%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4353%
4354% QueueAuthenticNexus() allocates an region to store image pixels as defined
4355% by the region rectangle and returns a pointer to the region. This region is
4356% subsequently transferred from the pixel cache with
4357% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4358% pixels are transferred, otherwise a NULL is returned.
4359%
4360% The format of the QueueAuthenticNexus() method is:
4361%
4362% PixelPacket *QueueAuthenticNexus(Image *image,const long x,const long y,
4363% const unsigned long columns,const unsigned long rows,
4364% NexusInfo *nexus_info,ExceptionInfo *exception)
4365%
4366% A description of each parameter follows:
4367%
4368% o image: the image.
4369%
4370% o x,y,columns,rows: These values define the perimeter of a region of
4371% pixels.
4372%
4373% o nexus_info: the cache nexus to set.
4374%
4375% o exception: return any errors or warnings in this structure.
4376%
4377*/
4378MagickExport PixelPacket *QueueAuthenticNexus(Image *image,const long x,
4379 const long y,const unsigned long columns,const unsigned long rows,
4380 NexusInfo *nexus_info,ExceptionInfo *exception)
4381{
4382 CacheInfo
4383 *cache_info;
4384
4385 MagickOffsetType
4386 offset;
4387
4388 MagickSizeType
4389 number_pixels;
4390
4391 RectangleInfo
4392 region;
4393
4394 /*
4395 Validate pixel cache geometry.
4396 */
4397 cache_info=(CacheInfo *) image->cache;
4398 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4399 {
4400 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4401 "NoPixelsDefinedInCache","`%s'",image->filename);
4402 return((PixelPacket *) NULL);
4403 }
4404 if ((x < 0) || (y < 0) || (x >= (long) cache_info->columns) ||
4405 (y >= (long) cache_info->rows))
4406 {
4407 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4408 "PixelsAreNotAuthentic","`%s'",image->filename);
4409 return((PixelPacket *) NULL);
4410 }
4411 offset=(MagickOffsetType) y*cache_info->columns+x;
4412 if (offset < 0)
4413 return((PixelPacket *) NULL);
4414 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4415 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4416 if ((MagickSizeType) offset >= number_pixels)
4417 return((PixelPacket *) NULL);
4418 /*
4419 Return pixel cache.
4420 */
4421 region.x=x;
4422 region.y=y;
4423 region.width=columns;
4424 region.height=rows;
4425 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4426}
4427
4428/*
4429%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4430% %
4431% %
4432% %
4433+ 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 %
4434% %
4435% %
4436% %
4437%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4438%
4439% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4440% defined by the region rectangle and returns a pointer to the region. This
4441% region is subsequently transferred from the pixel cache with
4442% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4443% pixels are transferred, otherwise a NULL is returned.
4444%
4445% The format of the QueueAuthenticPixelsCache() method is:
4446%
4447% PixelPacket *QueueAuthenticPixelsCache(Image *image,const long x,
4448% const long y,const unsigned long columns,const unsigned long rows,
4449% ExceptionInfo *exception)
4450%
4451% A description of each parameter follows:
4452%
4453% o image: the image.
4454%
4455% o x,y,columns,rows: These values define the perimeter of a region of
4456% pixels.
4457%
4458% o exception: return any errors or warnings in this structure.
4459%
4460*/
4461static PixelPacket *QueueAuthenticPixelsCache(Image *image,const long x,
4462 const long y,const unsigned long columns,const unsigned long rows,
4463 ExceptionInfo *exception)
4464{
4465 CacheInfo
4466 *cache_info;
4467
4468 long
4469 id;
4470
4471 PixelPacket
4472 *pixels;
4473
4474 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickFalse,exception);
4475 if (cache_info == (Cache) NULL)
4476 return((PixelPacket *) NULL);
4477 id=GetOpenMPThreadId();
4478 assert(id < (long) cache_info->number_threads);
4479 pixels=QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4480 exception);
4481 return(pixels);
4482}
4483
4484/*
4485%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4486% %
4487% %
4488% %
4489% Q u e u e A u t h e n t i c P i x e l s %
4490% %
4491% %
4492% %
4493%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4494%
4495% QueueAuthenticPixels() queues a mutable pixel region. If the region is
4496% successfully intialized a pointer to a PixelPacket array representing the
4497% region is returned, otherwise NULL is returned. The returned pointer may
4498% point to a temporary working buffer for the pixels or it may point to the
4499% final location of the pixels in memory.
4500%
4501% Write-only access means that any existing pixel values corresponding to
4502% the region are ignored. This is useful if the initial image is being
4503% created from scratch, or if the existing pixel values are to be
4504% completely replaced without need to refer to their pre-existing values.
4505% The application is free to read and write the pixel buffer returned by
4506% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4507% initialize the pixel array values. Initializing pixel array values is the
4508% application's responsibility.
4509%
4510% Performance is maximized if the selected region is part of one row, or
4511% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004512% pixels in-place (without a copy) if the image is in memory, or in a
4513% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004514% by the user.
4515%
4516% Pixels accessed via the returned pointer represent a simple array of type
4517% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
4518% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
4519% the black color component or the colormap indexes (of type IndexPacket)
4520% corresponding to the region. Once the PixelPacket (and/or IndexPacket)
4521% array has been updated, the changes must be saved back to the underlying
4522% image using SyncAuthenticPixels() or they may be lost.
4523%
4524% The format of the QueueAuthenticPixels() method is:
4525%
4526% PixelPacket *QueueAuthenticPixels(Image *image,const long x,const long y,
4527% const unsigned long columns,const unsigned long rows,
4528% ExceptionInfo *exception)
4529%
4530% A description of each parameter follows:
4531%
4532% o image: the image.
4533%
4534% o x,y,columns,rows: These values define the perimeter of a region of
4535% pixels.
4536%
4537% o exception: return any errors or warnings in this structure.
4538%
4539*/
4540MagickExport PixelPacket *QueueAuthenticPixels(Image *image,const long x,
4541 const long y,const unsigned long columns,const unsigned long rows,
4542 ExceptionInfo *exception)
4543{
4544 CacheInfo
4545 *cache_info;
4546
4547 PixelPacket
4548 *pixels;
4549
4550 assert(image != (Image *) NULL);
4551 assert(image->signature == MagickSignature);
4552 if (image->debug != MagickFalse)
4553 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4554 assert(image->cache != (Cache) NULL);
4555 cache_info=(CacheInfo *) image->cache;
4556 assert(cache_info->signature == MagickSignature);
4557 if (cache_info->methods.queue_authentic_pixels_handler ==
4558 (QueueAuthenticPixelsHandler) NULL)
4559 return((PixelPacket *) NULL);
4560 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4561 rows,exception);
4562 return(pixels);
4563}
4564
4565/*
4566%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4567% %
4568% %
4569% %
4570+ R e a d P i x e l C a c h e I n d e x e s %
4571% %
4572% %
4573% %
4574%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4575%
4576% ReadPixelCacheIndexes() reads colormap indexes from the specified region of
4577% the pixel cache.
4578%
4579% The format of the ReadPixelCacheIndexes() method is:
4580%
4581% MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4582% NexusInfo *nexus_info,ExceptionInfo *exception)
4583%
4584% A description of each parameter follows:
4585%
4586% o cache_info: the pixel cache.
4587%
4588% o nexus_info: the cache nexus to read the colormap indexes.
4589%
4590% o exception: return any errors or warnings in this structure.
4591%
4592*/
4593static MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4594 NexusInfo *nexus_info,ExceptionInfo *exception)
4595{
4596 MagickOffsetType
4597 count,
4598 offset;
4599
4600 MagickSizeType
4601 length,
4602 number_pixels;
4603
4604 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004605 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004606
4607 register long
4608 y;
4609
4610 unsigned long
4611 rows;
4612
4613 if (cache_info->debug != MagickFalse)
4614 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4615 cache_info->filename);
4616 if (cache_info->active_index_channel == MagickFalse)
4617 return(MagickFalse);
4618 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4619 return(MagickTrue);
4620 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4621 nexus_info->region.x;
4622 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
4623 rows=nexus_info->region.height;
4624 number_pixels=length*rows;
4625 if ((cache_info->columns == nexus_info->region.width) &&
4626 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4627 {
4628 length=number_pixels;
4629 rows=1UL;
4630 }
4631 q=nexus_info->indexes;
4632 switch (cache_info->type)
4633 {
4634 case MemoryCache:
4635 case MapCache:
4636 {
4637 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004638 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004639
4640 /*
4641 Read indexes from memory.
4642 */
4643 p=cache_info->indexes+offset;
4644 for (y=0; y < (long) rows; y++)
4645 {
4646 (void) CopyMagickMemory(q,p,(size_t) length);
4647 p+=cache_info->columns;
4648 q+=nexus_info->region.width;
4649 }
4650 break;
4651 }
4652 case DiskCache:
4653 {
4654 /*
4655 Read indexes from disk.
4656 */
4657 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4658 {
4659 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4660 cache_info->cache_filename);
4661 return(MagickFalse);
4662 }
4663 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4664 for (y=0; y < (long) rows; y++)
4665 {
4666 count=ReadPixelCacheRegion(cache_info,cache_info->offset+number_pixels*
4667 sizeof(PixelPacket)+offset*sizeof(*q),length,(unsigned char *) q);
4668 if ((MagickSizeType) count < length)
4669 break;
4670 offset+=cache_info->columns;
4671 q+=nexus_info->region.width;
4672 }
4673 if (y < (long) rows)
4674 {
4675 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4676 cache_info->cache_filename);
4677 return(MagickFalse);
4678 }
4679 break;
4680 }
4681 default:
4682 break;
4683 }
4684 if ((cache_info->debug != MagickFalse) &&
4685 (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4686 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
4687 cache_info->filename,nexus_info->region.width,nexus_info->region.height,
4688 nexus_info->region.x,nexus_info->region.y);
4689 return(MagickTrue);
4690}
4691
4692/*
4693%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4694% %
4695% %
4696% %
4697+ R e a d P i x e l C a c h e P i x e l s %
4698% %
4699% %
4700% %
4701%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4702%
4703% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4704% cache.
4705%
4706% The format of the ReadPixelCachePixels() method is:
4707%
4708% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4709% NexusInfo *nexus_info,ExceptionInfo *exception)
4710%
4711% A description of each parameter follows:
4712%
4713% o cache_info: the pixel cache.
4714%
4715% o nexus_info: the cache nexus to read the pixels.
4716%
4717% o exception: return any errors or warnings in this structure.
4718%
4719*/
4720static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4721 NexusInfo *nexus_info,ExceptionInfo *exception)
4722{
4723 MagickOffsetType
4724 count,
4725 offset;
4726
4727 MagickSizeType
4728 length,
4729 number_pixels;
4730
4731 register long
4732 y;
4733
4734 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004735 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004736
4737 unsigned long
4738 rows;
4739
4740 if (cache_info->debug != MagickFalse)
4741 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4742 cache_info->filename);
4743 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4744 return(MagickTrue);
4745 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4746 nexus_info->region.x;
4747 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
4748 rows=nexus_info->region.height;
4749 number_pixels=length*rows;
4750 if ((cache_info->columns == nexus_info->region.width) &&
4751 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4752 {
4753 length=number_pixels;
4754 rows=1UL;
4755 }
4756 q=nexus_info->pixels;
4757 switch (cache_info->type)
4758 {
4759 case MemoryCache:
4760 case MapCache:
4761 {
4762 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004763 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004764
4765 /*
4766 Read pixels from memory.
4767 */
4768 p=cache_info->pixels+offset;
4769 for (y=0; y < (long) rows; y++)
4770 {
4771 (void) CopyMagickMemory(q,p,(size_t) length);
4772 p+=cache_info->columns;
4773 q+=nexus_info->region.width;
4774 }
4775 break;
4776 }
4777 case DiskCache:
4778 {
4779 /*
4780 Read pixels from disk.
4781 */
4782 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4783 {
4784 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4785 cache_info->cache_filename);
4786 return(MagickFalse);
4787 }
4788 for (y=0; y < (long) rows; y++)
4789 {
4790 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4791 sizeof(*q),length,(unsigned char *) q);
4792 if ((MagickSizeType) count < length)
4793 break;
4794 offset+=cache_info->columns;
4795 q+=nexus_info->region.width;
4796 }
4797 if (y < (long) rows)
4798 {
4799 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4800 cache_info->cache_filename);
4801 return(MagickFalse);
4802 }
4803 break;
4804 }
4805 default:
4806 break;
4807 }
4808 if ((cache_info->debug != MagickFalse) &&
4809 (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4810 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
4811 cache_info->filename,nexus_info->region.width,nexus_info->region.height,
4812 nexus_info->region.x,nexus_info->region.y);
4813 return(MagickTrue);
4814}
4815
4816/*
4817%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4818% %
4819% %
4820% %
4821+ R e f e r e n c e P i x e l C a c h e %
4822% %
4823% %
4824% %
4825%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4826%
4827% ReferencePixelCache() increments the reference count associated with the
4828% pixel cache returning a pointer to the cache.
4829%
4830% The format of the ReferencePixelCache method is:
4831%
4832% Cache ReferencePixelCache(Cache cache_info)
4833%
4834% A description of each parameter follows:
4835%
4836% o cache_info: the pixel cache.
4837%
4838*/
4839MagickExport Cache ReferencePixelCache(Cache cache)
4840{
4841 CacheInfo
4842 *cache_info;
4843
4844 assert(cache != (Cache *) NULL);
4845 cache_info=(CacheInfo *) cache;
4846 assert(cache_info->signature == MagickSignature);
4847 if (cache_info->debug != MagickFalse)
4848 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4849 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00004850 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004851 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004852 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004853 return(cache_info);
4854}
4855
4856/*
4857%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4858% %
4859% %
4860% %
4861+ S e t P i x e l C a c h e M e t h o d s %
4862% %
4863% %
4864% %
4865%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4866%
4867% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4868%
4869% The format of the SetPixelCacheMethods() method is:
4870%
4871% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4872%
4873% A description of each parameter follows:
4874%
4875% o cache: the pixel cache.
4876%
4877% o cache_methods: Specifies a pointer to a CacheMethods structure.
4878%
4879*/
4880MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4881{
4882 CacheInfo
4883 *cache_info;
4884
4885 GetOneAuthenticPixelFromHandler
4886 get_one_authentic_pixel_from_handler;
4887
4888 GetOneVirtualPixelFromHandler
4889 get_one_virtual_pixel_from_handler;
4890
4891 /*
4892 Set cache pixel methods.
4893 */
4894 assert(cache != (Cache) NULL);
4895 assert(cache_methods != (CacheMethods *) NULL);
4896 cache_info=(CacheInfo *) cache;
4897 assert(cache_info->signature == MagickSignature);
4898 if (cache_info->debug != MagickFalse)
4899 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4900 cache_info->filename);
4901 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4902 cache_info->methods.get_virtual_pixel_handler=
4903 cache_methods->get_virtual_pixel_handler;
4904 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4905 cache_info->methods.destroy_pixel_handler=
4906 cache_methods->destroy_pixel_handler;
4907 if (cache_methods->get_virtual_indexes_from_handler !=
4908 (GetVirtualIndexesFromHandler) NULL)
4909 cache_info->methods.get_virtual_indexes_from_handler=
4910 cache_methods->get_virtual_indexes_from_handler;
4911 if (cache_methods->get_authentic_pixels_handler !=
4912 (GetAuthenticPixelsHandler) NULL)
4913 cache_info->methods.get_authentic_pixels_handler=
4914 cache_methods->get_authentic_pixels_handler;
4915 if (cache_methods->queue_authentic_pixels_handler !=
4916 (QueueAuthenticPixelsHandler) NULL)
4917 cache_info->methods.queue_authentic_pixels_handler=
4918 cache_methods->queue_authentic_pixels_handler;
4919 if (cache_methods->sync_authentic_pixels_handler !=
4920 (SyncAuthenticPixelsHandler) NULL)
4921 cache_info->methods.sync_authentic_pixels_handler=
4922 cache_methods->sync_authentic_pixels_handler;
4923 if (cache_methods->get_authentic_pixels_from_handler !=
4924 (GetAuthenticPixelsFromHandler) NULL)
4925 cache_info->methods.get_authentic_pixels_from_handler=
4926 cache_methods->get_authentic_pixels_from_handler;
4927 if (cache_methods->get_authentic_indexes_from_handler !=
4928 (GetAuthenticIndexesFromHandler) NULL)
4929 cache_info->methods.get_authentic_indexes_from_handler=
4930 cache_methods->get_authentic_indexes_from_handler;
4931 get_one_virtual_pixel_from_handler=
4932 cache_info->methods.get_one_virtual_pixel_from_handler;
4933 if (get_one_virtual_pixel_from_handler !=
4934 (GetOneVirtualPixelFromHandler) NULL)
4935 cache_info->methods.get_one_virtual_pixel_from_handler=
4936 cache_methods->get_one_virtual_pixel_from_handler;
4937 get_one_authentic_pixel_from_handler=
4938 cache_methods->get_one_authentic_pixel_from_handler;
4939 if (get_one_authentic_pixel_from_handler !=
4940 (GetOneAuthenticPixelFromHandler) NULL)
4941 cache_info->methods.get_one_authentic_pixel_from_handler=
4942 cache_methods->get_one_authentic_pixel_from_handler;
4943}
4944
4945/*
4946%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4947% %
4948% %
4949% %
4950+ S e t P i x e l C a c h e N e x u s P i x e l s %
4951% %
4952% %
4953% %
4954%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4955%
4956% SetPixelCacheNexusPixels() defines the region of the cache for the
4957% specified cache nexus.
4958%
4959% The format of the SetPixelCacheNexusPixels() method is:
4960%
4961% PixelPacket SetPixelCacheNexusPixels(const Image *image,
4962% const RectangleInfo *region,NexusInfo *nexus_info,
4963% ExceptionInfo *exception)
4964%
4965% A description of each parameter follows:
4966%
4967% o image: the image.
4968%
4969% o region: A pointer to the RectangleInfo structure that defines the
4970% region of this particular cache nexus.
4971%
4972% o nexus_info: the cache nexus to set.
4973%
4974% o exception: return any errors or warnings in this structure.
4975%
4976*/
4977static PixelPacket *SetPixelCacheNexusPixels(const Image *image,
4978 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4979{
4980 CacheInfo
4981 *cache_info;
4982
4983 MagickBooleanType
4984 status;
4985
cristy3ed852e2009-09-05 21:47:34 +00004986 MagickSizeType
4987 length,
4988 number_pixels;
4989
4990 if (image->debug != MagickFalse)
4991 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4992 cache_info=(CacheInfo *) image->cache;
4993 assert(cache_info->signature == MagickSignature);
4994 if (cache_info->type == UndefinedCache)
4995 return((PixelPacket *) NULL);
4996 nexus_info->region.width=region->width == 0UL ? 1UL : region->width;
4997 nexus_info->region.height=region->height == 0UL ? 1UL : region->height;
4998 nexus_info->region.x=region->x;
4999 nexus_info->region.y=region->y;
5000 if ((cache_info->type != DiskCache) && (image->clip_mask == (Image *) NULL) &&
5001 (image->mask == (Image *) NULL))
5002 {
cristybad067a2010-02-15 17:20:55 +00005003 long
5004 x,
5005 y;
cristy3ed852e2009-09-05 21:47:34 +00005006
cristybad067a2010-02-15 17:20:55 +00005007 x=nexus_info->region.x+nexus_info->region.width-1;
5008 y=nexus_info->region.y+nexus_info->region.height-1;
5009 if (((nexus_info->region.x >= 0) && (x < (long) cache_info->columns) &&
5010 (nexus_info->region.y >= 0) && (y < (long) cache_info->rows)) &&
cristy731c3532010-02-15 15:40:03 +00005011 ((nexus_info->region.height == 1UL) ||
5012 ((nexus_info->region.x == 0) &&
5013 ((nexus_info->region.width == cache_info->columns) ||
5014 ((nexus_info->region.width % cache_info->columns) == 0)))))
5015 {
5016 MagickOffsetType
5017 offset;
5018
5019 /*
5020 Pixels are accessed directly from memory.
5021 */
5022 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5023 nexus_info->region.x;
5024 nexus_info->pixels=cache_info->pixels+offset;
5025 nexus_info->indexes=(IndexPacket *) NULL;
5026 if (cache_info->active_index_channel != MagickFalse)
5027 nexus_info->indexes=cache_info->indexes+offset;
5028 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00005029 }
5030 }
5031 /*
5032 Pixels are stored in a cache region until they are synced to the cache.
5033 */
5034 number_pixels=(MagickSizeType) nexus_info->region.width*
5035 nexus_info->region.height;
5036 length=number_pixels*sizeof(PixelPacket);
5037 if (cache_info->active_index_channel != MagickFalse)
5038 length+=number_pixels*sizeof(IndexPacket);
5039 if (nexus_info->cache == (PixelPacket *) NULL)
5040 {
5041 nexus_info->length=length;
5042 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5043 if (status == MagickFalse)
5044 return((PixelPacket *) NULL);
5045 }
5046 else
5047 if (nexus_info->length != length)
5048 {
5049 RelinquishCacheNexusPixels(nexus_info);
5050 nexus_info->length=length;
5051 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5052 if (status == MagickFalse)
5053 return((PixelPacket *) NULL);
5054 }
5055 nexus_info->pixels=nexus_info->cache;
5056 nexus_info->indexes=(IndexPacket *) NULL;
5057 if (cache_info->active_index_channel != MagickFalse)
5058 nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
5059 return(nexus_info->pixels);
5060}
5061
5062/*
5063%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5064% %
5065% %
5066% %
5067% 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 %
5068% %
5069% %
5070% %
5071%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5072%
5073% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5074% pixel cache and returns the previous setting. A virtual pixel is any pixel
5075% access that is outside the boundaries of the image cache.
5076%
5077% The format of the SetPixelCacheVirtualMethod() method is:
5078%
5079% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5080% const VirtualPixelMethod virtual_pixel_method)
5081%
5082% A description of each parameter follows:
5083%
5084% o image: the image.
5085%
5086% o virtual_pixel_method: choose the type of virtual pixel.
5087%
5088*/
5089MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5090 const VirtualPixelMethod virtual_pixel_method)
5091{
5092 CacheInfo
5093 *cache_info;
5094
5095 VirtualPixelMethod
5096 method;
5097
5098 assert(image != (Image *) NULL);
5099 assert(image->signature == MagickSignature);
5100 if (image->debug != MagickFalse)
5101 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5102 assert(image->cache != (Cache) NULL);
5103 cache_info=(CacheInfo *) image->cache;
5104 assert(cache_info->signature == MagickSignature);
5105 method=cache_info->virtual_pixel_method;
5106 cache_info->virtual_pixel_method=virtual_pixel_method;
5107 return(method);
5108}
5109
5110/*
5111%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5112% %
5113% %
5114% %
5115+ 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 %
5116% %
5117% %
5118% %
5119%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5120%
5121% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5122% in-memory or disk cache. The method returns MagickTrue if the pixel region
5123% is synced, otherwise MagickFalse.
5124%
5125% The format of the SyncAuthenticPixelCacheNexus() method is:
5126%
5127% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5128% NexusInfo *nexus_info,ExceptionInfo *exception)
5129%
5130% A description of each parameter follows:
5131%
5132% o image: the image.
5133%
5134% o nexus_info: the cache nexus to sync.
5135%
5136% o exception: return any errors or warnings in this structure.
5137%
5138*/
5139MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5140 NexusInfo *nexus_info,ExceptionInfo *exception)
5141{
5142 CacheInfo
5143 *cache_info;
5144
5145 MagickBooleanType
5146 status;
5147
5148 /*
5149 Transfer pixels to the cache.
5150 */
5151 assert(image != (Image *) NULL);
5152 assert(image->signature == MagickSignature);
5153 if (image->debug != MagickFalse)
5154 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5155 if (image->cache == (Cache) NULL)
5156 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5157 cache_info=(CacheInfo *) image->cache;
5158 if (cache_info->type == UndefinedCache)
5159 return(MagickFalse);
5160 if ((image->clip_mask != (Image *) NULL) &&
5161 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5162 return(MagickFalse);
5163 if ((image->mask != (Image *) NULL) &&
5164 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5165 return(MagickFalse);
5166 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5167 return(MagickTrue);
5168 assert(cache_info->signature == MagickSignature);
5169 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5170 if ((cache_info->active_index_channel != MagickFalse) &&
5171 (WritePixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse))
5172 return(MagickFalse);
5173 return(status);
5174}
5175
5176/*
5177%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5178% %
5179% %
5180% %
5181+ S y n c A u t h e n t i c P i x e l C a c h e %
5182% %
5183% %
5184% %
5185%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5186%
5187% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5188% or disk cache. The method returns MagickTrue if the pixel region is synced,
5189% otherwise MagickFalse.
5190%
5191% The format of the SyncAuthenticPixelsCache() method is:
5192%
5193% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5194% ExceptionInfo *exception)
5195%
5196% A description of each parameter follows:
5197%
5198% o image: the image.
5199%
5200% o exception: return any errors or warnings in this structure.
5201%
5202*/
5203static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5204 ExceptionInfo *exception)
5205{
5206 CacheInfo
5207 *cache_info;
5208
5209 long
5210 id;
5211
5212 MagickBooleanType
5213 status;
5214
5215 cache_info=(CacheInfo *) image->cache;
5216 id=GetOpenMPThreadId();
5217 assert(id < (long) cache_info->number_threads);
5218 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5219 exception);
5220 return(status);
5221}
5222
5223/*
5224%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5225% %
5226% %
5227% %
5228% S y n c A u t h e n t i c P i x e l s %
5229% %
5230% %
5231% %
5232%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5233%
5234% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5235% The method returns MagickTrue if the pixel region is flushed, otherwise
5236% MagickFalse.
5237%
5238% The format of the SyncAuthenticPixels() method is:
5239%
5240% MagickBooleanType SyncAuthenticPixels(Image *image,
5241% ExceptionInfo *exception)
5242%
5243% A description of each parameter follows:
5244%
5245% o image: the image.
5246%
5247% o exception: return any errors or warnings in this structure.
5248%
5249*/
5250MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5251 ExceptionInfo *exception)
5252{
5253 CacheInfo
5254 *cache_info;
5255
5256 assert(image != (Image *) NULL);
5257 assert(image->signature == MagickSignature);
5258 if (image->debug != MagickFalse)
5259 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5260 assert(image->cache != (Cache) NULL);
5261 cache_info=(CacheInfo *) image->cache;
5262 assert(cache_info->signature == MagickSignature);
5263 if (cache_info->methods.sync_authentic_pixels_handler ==
5264 (SyncAuthenticPixelsHandler) NULL)
5265 return(MagickFalse);
5266 return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
5267}
5268
5269/*
5270%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5271% %
5272% %
5273% %
5274+ W r i t e P i x e l C a c h e I n d e x e s %
5275% %
5276% %
5277% %
5278%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5279%
5280% WritePixelCacheIndexes() writes the colormap indexes to the specified
5281% region of the pixel cache.
5282%
5283% The format of the WritePixelCacheIndexes() method is:
5284%
5285% MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5286% NexusInfo *nexus_info,ExceptionInfo *exception)
5287%
5288% A description of each parameter follows:
5289%
5290% o cache_info: the pixel cache.
5291%
5292% o nexus_info: the cache nexus to write the colormap indexes.
5293%
5294% o exception: return any errors or warnings in this structure.
5295%
5296*/
5297static MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5298 NexusInfo *nexus_info,ExceptionInfo *exception)
5299{
5300 MagickOffsetType
5301 count,
5302 offset;
5303
5304 MagickSizeType
5305 length,
5306 number_pixels;
5307
5308 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005309 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005310
5311 register long
5312 y;
5313
5314 unsigned long
5315 rows;
5316
5317 if (cache_info->debug != MagickFalse)
5318 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
5319 cache_info->filename);
5320 if (cache_info->active_index_channel == MagickFalse)
5321 return(MagickFalse);
5322 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5323 return(MagickTrue);
5324 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5325 nexus_info->region.x;
5326 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
5327 rows=nexus_info->region.height;
5328 number_pixels=(MagickSizeType) length*rows;
5329 if ((cache_info->columns == nexus_info->region.width) &&
5330 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5331 {
5332 length=number_pixels;
5333 rows=1UL;
5334 }
5335 p=nexus_info->indexes;
5336 switch (cache_info->type)
5337 {
5338 case MemoryCache:
5339 case MapCache:
5340 {
5341 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005342 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005343
5344 /*
5345 Write indexes to memory.
5346 */
5347 q=cache_info->indexes+offset;
5348 for (y=0; y < (long) rows; y++)
5349 {
5350 (void) CopyMagickMemory(q,p,(size_t) length);
5351 p+=nexus_info->region.width;
5352 q+=cache_info->columns;
5353 }
5354 break;
5355 }
5356 case DiskCache:
5357 {
5358 /*
5359 Write indexes to disk.
5360 */
5361 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5362 {
5363 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5364 cache_info->cache_filename);
5365 return(MagickFalse);
5366 }
5367 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
5368 for (y=0; y < (long) rows; y++)
5369 {
5370 count=WritePixelCacheRegion(cache_info,cache_info->offset+number_pixels*
5371 sizeof(PixelPacket)+offset*sizeof(*p),length,
5372 (const unsigned char *) p);
5373 if ((MagickSizeType) count < length)
5374 break;
5375 p+=nexus_info->region.width;
5376 offset+=cache_info->columns;
5377 }
5378 if (y < (long) rows)
5379 {
5380 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5381 cache_info->cache_filename);
5382 return(MagickFalse);
5383 }
5384 break;
5385 }
5386 default:
5387 break;
5388 }
5389 if ((cache_info->debug != MagickFalse) &&
5390 (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5391 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
5392 cache_info->filename,nexus_info->region.width,nexus_info->region.height,
5393 nexus_info->region.x,nexus_info->region.y);
5394 return(MagickTrue);
5395}
5396
5397/*
5398%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5399% %
5400% %
5401% %
5402+ W r i t e C a c h e P i x e l s %
5403% %
5404% %
5405% %
5406%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5407%
5408% WritePixelCachePixels() writes image pixels to the specified region of the
5409% pixel cache.
5410%
5411% The format of the WritePixelCachePixels() method is:
5412%
5413% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5414% NexusInfo *nexus_info,ExceptionInfo *exception)
5415%
5416% A description of each parameter follows:
5417%
5418% o cache_info: the pixel cache.
5419%
5420% o nexus_info: the cache nexus to write the pixels.
5421%
5422% o exception: return any errors or warnings in this structure.
5423%
5424*/
5425static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5426 NexusInfo *nexus_info,ExceptionInfo *exception)
5427{
5428 MagickOffsetType
5429 count,
5430 offset;
5431
5432 MagickSizeType
5433 length,
5434 number_pixels;
5435
cristy3ed852e2009-09-05 21:47:34 +00005436 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005437 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005438
cristy25ffffb2009-12-07 17:15:07 +00005439 register long
5440 y;
5441
cristy3ed852e2009-09-05 21:47:34 +00005442 unsigned long
5443 rows;
5444
5445 if (cache_info->debug != MagickFalse)
5446 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
5447 cache_info->filename);
5448 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5449 return(MagickTrue);
5450 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5451 nexus_info->region.x;
5452 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
5453 rows=nexus_info->region.height;
5454 number_pixels=length*rows;
5455 if ((cache_info->columns == nexus_info->region.width) &&
5456 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5457 {
5458 length=number_pixels;
5459 rows=1UL;
5460 }
5461 p=nexus_info->pixels;
5462 switch (cache_info->type)
5463 {
5464 case MemoryCache:
5465 case MapCache:
5466 {
5467 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005468 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005469
5470 /*
5471 Write pixels to memory.
5472 */
5473 q=cache_info->pixels+offset;
5474 for (y=0; y < (long) rows; y++)
5475 {
5476 (void) CopyMagickMemory(q,p,(size_t) length);
5477 p+=nexus_info->region.width;
5478 q+=cache_info->columns;
5479 }
5480 break;
5481 }
5482 case DiskCache:
5483 {
5484 /*
5485 Write pixels to disk.
5486 */
5487 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5488 {
5489 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5490 cache_info->cache_filename);
5491 return(MagickFalse);
5492 }
5493 for (y=0; y < (long) rows; y++)
5494 {
5495 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5496 sizeof(*p),length,(const unsigned char *) p);
5497 if ((MagickSizeType) count < length)
5498 break;
5499 p+=nexus_info->region.width;
5500 offset+=cache_info->columns;
5501 }
5502 if (y < (long) rows)
5503 {
5504 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5505 cache_info->cache_filename);
5506 return(MagickFalse);
5507 }
5508 break;
5509 }
5510 default:
5511 break;
5512 }
5513 if ((cache_info->debug != MagickFalse) &&
5514 (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5515 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
5516 cache_info->filename,nexus_info->region.width,nexus_info->region.height,
5517 nexus_info->region.x,nexus_info->region.y);
5518 return(MagickTrue);
5519}