root / ImageMagick / trunk / magick / cache.c

Revision 12129, 177.5 kB (checked in by cristy, 28 hours ago)
Line 
1/*
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%                      ImageMagick Pixel Cache Methods                        %
14%                                                                             %
15%                              Software Design                                %
16%                                John Cristy                                  %
17%                                 July 1999                                   %
18%                                                                             %
19%                                                                             %
20%  Copyright 1999-2008 ImageMagick Studio LLC, a non-profit organization      %
21%  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"
52#include "magick/list.h"
53#include "magick/log.h"
54#include "magick/magick.h"
55#include "magick/memory_.h"
56#include "magick/pixel-private.h"
57#include "magick/quantum.h"
58#include "magick/random_.h"
59#include "magick/resource_.h"
60#include "magick/semaphore.h"
61#include "magick/splay-tree.h"
62#include "magick/string_.h"
63#include "magick/utility.h"
64#if defined(MAGICKCORE_ZLIB_DELEGATE)
65#include "zlib.h"
66#endif
67#if defined(MAGICKCORE_HAVE_PTHREAD)
68#include <pthread.h>
69#endif
70#if defined(__WINDOWS__)
71#include <windows.h>
72#endif
73
74/*
75  Define declarations.
76*/
77#define CacheViewReserve  256
78
79/*
80  Typedef declarations.
81*/
82struct _NexusInfo
83{
84  MagickBooleanType
85    reserve,
86    mapped;
87
88  unsigned long
89    columns,
90    rows;
91
92  long
93    x,
94    y;
95
96  MagickSizeType
97    length;
98
99  PixelPacket
100    *cache,
101    *pixels;
102
103  IndexPacket
104    *indexes;
105};
106
107/*
108  Forward declarations.
109*/
110#if defined(__cplusplus) || defined(c_plusplus)
111extern "C" {
112#endif
113
114static const PixelPacket
115  *AcquirePixelCache(const Image *,const VirtualPixelMethod,const long,
116    const long,const unsigned long,const unsigned long,ExceptionInfo *);
117
118static IndexPacket
119  *GetIndexesFromCache(const Image *);
120
121static MagickBooleanType
122  OpenCache(Image *,const MapMode,ExceptionInfo *),
123  SyncCache(Image *),
124  SyncPixelCache(Image *);
125
126static PixelPacket
127  AcquireOnePixelFromCache(const Image *,const VirtualPixelMethod,const long,
128    const long,ExceptionInfo *),
129  GetOnePixelFromCache(Image *,const long,const long),
130  *GetPixelCache(Image *,const long,const long,const unsigned long,
131    const unsigned long),
132  *GetPixelsFromCache(const Image *),
133  *SetPixelCache(Image *,const long,const long,const unsigned long,
134    const unsigned long);
135
136static void
137  DestroyPixelCache(Image *);
138
139#if defined(__cplusplus) || defined(c_plusplus)
140}
141#endif
142
143/*
144  Forward declarations.
145*/
146static PixelPacket
147  *SetNexus(const Image *,const RectangleInfo *,const unsigned long);
148
149static MagickBooleanType
150  ReadCacheIndexes(CacheInfo *,const unsigned long,ExceptionInfo *),
151  ReadCachePixels(CacheInfo *,const unsigned long,ExceptionInfo *),
152  WriteCacheIndexes(CacheInfo *,const unsigned long,ExceptionInfo *),
153  WriteCachePixels(CacheInfo *,const unsigned long,ExceptionInfo *);
154
155/*
156  Global declarations.
157*/
158static MagickSizeType
159  serial_number = 0;
160
161static SemaphoreInfo
162  *cache_semaphore = (SemaphoreInfo *) NULL;
163
164static SplayTreeInfo
165  *cache_resources = (SplayTreeInfo *) NULL;
166
167/*
168%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
169%                                                                             %
170%                                                                             %
171%                                                                             %
172+   A c q u i r e C a c h e N e x u s                                         %
173%                                                                             %
174%                                                                             %
175%                                                                             %
176%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
177%
178%  AcquireCacheNexus() acquires pixels from the in-memory or disk pixel cache
179%  as defined by the geometry parameters.   A pointer to the pixels is
180%  returned if the pixels are transferred, otherwise a NULL is returned.
181%
182%  The format of the AcquireCacheNexus() method is:
183%
184%      PixelPacket *AcquireCacheNexus(const Image *image,
185%        const VirtualPixelMethod method,const long x,const long y,
186%        const unsigned long columns,const unsigned long rows,
187%        const unsigned long nexus,ExceptionInfo *exception)
188%
189%  A description of each parameter follows:
190%
191%    o image: the image.
192%
193%    o virtual_pixel_method: the virtual pixel method.
194%
195%    o x,y,columns,rows:  These values define the perimeter of a region of
196%      pixels.
197%
198%    o nexus: specifies which cache nexus to acquire.
199%
200%    o exception: Return any errors or warnings in this structure.
201%
202*/
203
204static long
205  DitherMatrix[64] =
206  {
207     0,  48,  12,  60,   3,  51,  15,  63,
208    32,  16,  44,  28,  35,  19,  47,  31,
209     8,  56,   4,  52,  11,  59,   7,  55,
210    40,  24,  36,  20,  43,  27,  39,  23,
211     2,  50,  14,  62,   1,  49,  13,  61,
212    34,  18,  46,  30,  33,  17,  45,  29,
213    10,  58,   6,  54,   9,  57,   5,  53,
214    42,  26,  38,  22,  41,  25,  37,  21
215  };
216
217static inline long DitherX(const unsigned long columns,const long x)
218{
219  long
220    index;
221
222  index=x+DitherMatrix[x & 0x07]-32L;
223  if (index < 0L)
224    return(0L);
225  if (index >= (long) columns)
226    return((long) columns-1L);
227  return(index);
228}
229
230static inline long DitherY(const unsigned long rows,const long y)
231{
232  long
233    index;
234
235  index=y+DitherMatrix[y & 0x07]-32L;
236  if (index < 0L)
237    return(0L);
238  if (index >= (long) rows)
239    return((long) rows-1L);
240  return(index);
241}
242
243static inline long EdgeX(const unsigned long columns,const long x)
244{
245  if (x < 0L)
246    return(0L);
247  if (x >= (long) columns)
248    return((long) columns-1L);
249  return(x);
250}
251
252static inline long EdgeY(const unsigned long rows,const long y)
253{
254  if (y < 0L)
255    return(0L);
256  if (y >= (long) rows)
257    return((long) rows-1L);
258  return(y);
259}
260
261static inline MagickSizeType MagickMax(const MagickSizeType x,
262  const MagickSizeType y)
263{
264  if (x > y)
265    return(x);
266  return(y);
267}
268
269static inline MagickSizeType MagickMin(const MagickSizeType x,
270  const MagickSizeType y)
271{
272  if (x < y)
273    return(x);
274  return(y);
275}
276
277
278static inline long RandomX(const unsigned long columns)
279{
280  long
281    x;
282
283  x=(long) (columns*GetPseudoRandomValue()+0.5);
284  if (x >= (long) columns)
285    return((long) columns-1L);
286  return(x);
287}
288
289static inline long RandomY(const unsigned long rows)
290{
291  long
292    y;
293
294  y=(long) (rows*GetPseudoRandomValue()+0.5);
295  if (y >= (long) rows)
296    return((long) rows-1L);
297  return(y);
298}
299
300static inline long TileX(const unsigned long columns,const long x)
301{
302  if (x < 0L)
303    return((long) columns+((x+1) % (long) columns)-1);
304  if (x >= (long) columns)
305    return(x % (long) columns);
306  return(x);
307}
308
309static inline long TileY(const unsigned long rows,const long y)
310{
311  if (y < 0L)
312    return((long) rows+((y+1) % (long) rows)-1L);
313  if (y >= (long) rows)
314    return(y % (long) rows);
315  return(y);
316}
317
318static inline long MirrorX(const unsigned long columns,const long x)
319{
320  if ((x < 0) || (x >= (long) columns))
321    return((long) columns-TileX(columns,x)-1L);
322  return(x);
323}
324
325static inline long MirrorY(const unsigned long rows,const long y)
326{
327  if ((y < 0) || (y >= (long) rows))
328    return((long) rows-TileX(rows,y)-1L);
329  return(y);
330}
331
332static inline MagickBooleanType IsNexusInCore(const CacheInfo *cache_info,
333  const unsigned long nexus)
334{
335  MagickOffsetType
336    offset;
337
338  register NexusInfo
339    *nexus_info;
340
341  nexus_info=cache_info->nexus_info+nexus;
342  offset=(MagickOffsetType) nexus_info->y*cache_info->columns+nexus_info->x;
343  if (nexus_info->pixels != (cache_info->pixels+offset))
344    return(MagickFalse);
345  return(MagickTrue);
346}
347
348MagickExport const PixelPacket *AcquireCacheNexus(const Image *image,
349  const VirtualPixelMethod virtual_pixel_method,const long x,const long y,
350  const unsigned long columns,const unsigned long rows,
351  const unsigned long nexus,ExceptionInfo *exception)
352{
353  CacheInfo
354    *cache_info;
355
356  IndexPacket
357    *indexes,
358    *nexus_indexes;
359
360  MagickOffsetType
361    offset;
362
363  MagickSizeType
364    length,
365    number_pixels;
366
367  PixelPacket
368    *pixels;
369
370  RectangleInfo
371    region;
372
373  register const PixelPacket
374    *p;
375
376  register long
377    u,
378    v;
379
380  register PixelPacket
381    *q;
382
383  unsigned long
384    virtual_nexus;
385
386  /*
387    Acquire pixels.
388  */
389  assert(image != (const Image *) NULL);
390  assert(image->signature == MagickSignature);
391  if (image->debug != MagickFalse)
392    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
393  assert(image->cache != (Cache) NULL);
394  cache_info=(CacheInfo *) image->cache;
395  if (cache_info->type == UndefinedCache)
396    return((const PixelPacket *) NULL);
397  region.x=x;
398  region.y=y;
399  region.width=columns;
400  region.height=rows;
401  pixels=SetNexus(image,&region,nexus);
402  if (pixels == (PixelPacket *) NULL)
403    return((const PixelPacket *) NULL);
404  offset=(MagickOffsetType) region.y*cache_info->columns+region.x;
405  length=(MagickSizeType) (region.height-1)*cache_info->columns+region.width-1;
406  number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
407  if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
408    if ((x >= 0) && ((long) (x+columns) <= (long) cache_info->columns) &&
409        (y >= 0) && ((long) (y+rows) <= (long) cache_info->rows))
410      {
411        /*
412          Pixel request is inside cache extents.
413        */
414        if (IsNexusInCore(cache_info,nexus) != MagickFalse)
415          return(pixels);
416        if (ReadCachePixels(cache_info,nexus,exception) == MagickFalse)
417          return((const PixelPacket *) NULL);
418        if ((cache_info->storage_class == PseudoClass) ||
419            (cache_info->colorspace == CMYKColorspace))
420          if (ReadCacheIndexes(cache_info,nexus,exception) == MagickFalse)
421            return((const PixelPacket *) NULL);
422        return(pixels);
423      }
424  /*
425    Pixel request is outside cache extents.
426  */
427  q=pixels;
428  indexes=GetNexusIndexes(cache_info,nexus);
429  virtual_nexus=GetNexus(cache_info);
430  if (virtual_nexus == 0)
431    {
432      (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
433        "UnableToGetCacheNexus","`%s'",image->filename);
434      return((const PixelPacket *) NULL);
435    }
436  for (v=0; v < (long) rows; v++)
437  {
438    for (u=0; u < (long) columns; u+=length)
439    {
440      length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
441      if ((((x+u) < 0) || ((x+u) >= (long) cache_info->columns)) ||
442          (((y+v) < 0) || ((y+v) >= (long) cache_info->rows)) || (length == 0))
443        {
444          /*
445            Transfer a single pixel.
446          */
447          length=(MagickSizeType) 1;
448          switch (virtual_pixel_method)
449          {
450            case BackgroundVirtualPixelMethod:
451            case ConstantVirtualPixelMethod:
452            {
453              p=AcquireCacheNexus(image,virtual_pixel_method,
454                EdgeX(cache_info->columns,x+u),EdgeY(cache_info->rows,y+v),
455                1UL,1UL,virtual_nexus,exception);
456              cache_info->virtual_pixel=image->background_color;
457              p=(&cache_info->virtual_pixel);
458              break;
459            }
460            case BlackVirtualPixelMethod:
461            {
462              p=AcquireCacheNexus(image,virtual_pixel_method,
463                EdgeX(cache_info->columns,x+u),EdgeY(cache_info->rows,y+v),
464                1UL,1UL,virtual_nexus,exception);
465              cache_info->virtual_pixel.red=0;
466              cache_info->virtual_pixel.green=0;
467              cache_info->virtual_pixel.blue=0;
468              cache_info->virtual_pixel.opacity=OpaqueOpacity;
469              p=(&cache_info->virtual_pixel);
470              break;
471            }
472            case DitherVirtualPixelMethod:
473            {
474              p=AcquireCacheNexus(image,virtual_pixel_method,
475                DitherX(cache_info->columns,x+u),DitherY(cache_info->rows,y+v),
476                1UL,1UL,virtual_nexus,exception);
477              break;
478            }
479            case EdgeVirtualPixelMethod:
480            default:
481            {
482              p=AcquireCacheNexus(image,virtual_pixel_method,
483                EdgeX(cache_info->columns,x+u),EdgeY(cache_info->rows,y+v),
484                1UL,1UL,virtual_nexus,exception);
485              break;
486            }
487            case GrayVirtualPixelMethod:
488            {
489              p=AcquireCacheNexus(image,virtual_pixel_method,
490                EdgeX(cache_info->columns,x+u),EdgeY(cache_info->rows,y+v),
491                1UL,1UL,virtual_nexus,exception);
492              cache_info->virtual_pixel.red=(Quantum) QuantumRange/2;
493              cache_info->virtual_pixel.green=(Quantum) QuantumRange/2;
494              cache_info->virtual_pixel.blue=(Quantum) QuantumRange/2;
495              cache_info->virtual_pixel.opacity=(Quantum) OpaqueOpacity;
496              p=(&cache_info->virtual_pixel);
497              break;
498            }
499            case HorizontalTileVirtualPixelMethod:
500            {
501              p=AcquireCacheNexus(image,virtual_pixel_method,
502                TileX(cache_info->columns,x+u),TileY(cache_info->rows,y+v),
503                1UL,1UL,virtual_nexus,exception);
504              if (((y+v) < 0) || ((y+v) >= (long) cache_info->rows))
505                {
506                  cache_info->virtual_pixel=image->background_color;
507                  p=(&cache_info->virtual_pixel);
508                }
509              break;
510            }
511            case MirrorVirtualPixelMethod:
512            {
513              p=AcquireCacheNexus(image,virtual_pixel_method,
514                MirrorX(cache_info->columns,x+u),MirrorY(cache_info->rows,y+v),
515                1UL,1UL,virtual_nexus,exception);
516              break;
517            }
518            case RandomVirtualPixelMethod:
519            {
520              p=AcquireCacheNexus(image,virtual_pixel_method,
521                RandomX(cache_info->columns),RandomY(cache_info->rows),
522                1UL,1UL,virtual_nexus,exception);
523              break;
524            }
525            case TileVirtualPixelMethod:
526            {
527              p=AcquireCacheNexus(image,virtual_pixel_method,
528                TileX(cache_info->columns,x+u),TileY(cache_info->rows,y+v),
529                1UL,1UL,virtual_nexus,exception);
530              break;
531            }
532            case TransparentVirtualPixelMethod:
533            {
534              p=AcquireCacheNexus(image,virtual_pixel_method,
535                EdgeX(cache_info->columns,x+u),EdgeY(cache_info->rows,y+v),
536                1UL,1UL,virtual_nexus,exception);
537              cache_info->virtual_pixel.red=(Quantum) 0;
538              cache_info->virtual_pixel.green=(Quantum) 0;
539              cache_info->virtual_pixel.blue=(Quantum) 0;
540              cache_info->virtual_pixel.opacity=(Quantum) TransparentOpacity;
541              p=(&cache_info->virtual_pixel);
542              break;
543            }
544            case VerticalTileVirtualPixelMethod:
545            {
546              p=AcquireCacheNexus(image,virtual_pixel_method,
547                TileX(cache_info->columns,x+u),TileY(cache_info->rows,y+v),
548                1UL,1UL,virtual_nexus,exception);
549              if (((x+u) < 0) || ((x+u) >= (long) cache_info->columns))
550                {
551                  cache_info->virtual_pixel=image->background_color;
552                  p=(&cache_info->virtual_pixel);
553                }
554              break;
555            }
556            case MaskVirtualPixelMethod:
557            case WhiteVirtualPixelMethod:
558            {
559              p=AcquireCacheNexus(image,virtual_pixel_method,
560                EdgeX(cache_info->columns,x+u),EdgeY(cache_info->rows,y+v),
561                1UL,1UL,virtual_nexus,exception);
562              cache_info->virtual_pixel.red=(Quantum) QuantumRange;
563              cache_info->virtual_pixel.green=(Quantum) QuantumRange;
564              cache_info->virtual_pixel.blue=(Quantum) QuantumRange;
565              cache_info->virtual_pixel.opacity=OpaqueOpacity;
566              p=(&cache_info->virtual_pixel);
567              break;
568            }
569          }
570          if (p == (const PixelPacket *) NULL)
571            break;
572          *q++=(*p);
573          if (indexes != (IndexPacket *) NULL)
574            {
575              nexus_indexes=GetNexusIndexes(cache_info,virtual_nexus);
576              if (nexus_indexes != (IndexPacket *) NULL)
577                *indexes++=(*nexus_indexes);
578            }
579          continue;
580        }
581      /*
582        Transfer a run of pixels.
583      */
584      p=AcquireCacheNexus(image,virtual_pixel_method,x+u,y+v,(unsigned long)
585        length,1UL,virtual_nexus,exception);
586      if (p == (const PixelPacket *) NULL)
587        break;
588      (void) CopyMagickMemory(q,p,(size_t) length*sizeof(*q));
589      q+=length;
590      if (indexes != (IndexPacket *) NULL)
591        {
592          nexus_indexes=GetNexusIndexes(cache_info,virtual_nexus);
593          if (nexus_indexes != (IndexPacket *) NULL)
594            {
595              (void) CopyMagickMemory(indexes,nexus_indexes,(size_t) length*
596                sizeof(*indexes));
597              indexes+=length;
598            }
599        }
600    }
601  }
602  DestroyCacheNexus(cache_info,virtual_nexus);
603  return(pixels);
604}
605
606/*
607%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
608%                                                                             %
609%                                                                             %
610%                                                                             %
611%   A c q u i r e I m a g e P i x e l s                                       %
612%                                                                             %
613%                                                                             %
614%                                                                             %
615%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
616%
617%  AcquireImagePixels() obtains a pixel region for read-only access. If the
618%  region is successfully accessed, a pointer to it is returned, otherwise
619%  NULL is returned. The returned pointer may point to a temporary working
620%  copy of the pixels or it may point to the original pixels in memory.
621%  Performance is maximized if the selected region is part of one row, or one
622%  or more full rows, since there is opportunity to access the pixels in-place
623%  (without a copy) if the image is in RAM, or in a memory-mapped file.  The
624%  returned pointer should *never* be deallocated by the user.
625%
626%  Pixels accessed via the returned pointer represent a simple array of type
627%  PixelPacket.  If the image type is CMYK or the storage class is PseudoClass,
628%  call GetIndexes() after invoking GetImagePixels() to access the black
629%  color component or to obtain the colormap indexes (of type IndexPacket)
630%  corresponding to the region.
631%
632%  If you plan to modify the pixels, use GetImagePixels() instead.
633%
634%  Note, the AcquireImagePixels() and GetImagePixels() methods are not thread-
635%  safe.  In a threaded environment, use AcquireCacheViewPixels() or
636%  GetCacheViewPixels() instead.
637%
638%  The format of the AcquireImagePixels() method is:
639%
640%      const PixelPacket *AcquireImagePixels(const Image *image,const long x,
641%        const long y,const unsigned long columns,const unsigned long rows,
642%        ExceptionInfo *exception)
643%
644%  A description of each parameter follows:
645%
646%    o image: the image.
647%
648%    o x,y,columns,rows:  These values define the perimeter of a region of
649%      pixels.
650%
651%    o exception: Return any errors or warnings in this structure.
652%
653*/
654MagickExport const PixelPacket *AcquireImagePixels(const Image *image,
655  const long x,const long y,const unsigned long columns,
656  const unsigned long rows,ExceptionInfo *exception)
657{
658  CacheInfo
659    *cache_info;
660
661  const PixelPacket
662    *pixels;
663
664  assert(image != (const Image *) NULL);
665  assert(image->signature == MagickSignature);
666  if (image->debug != MagickFalse)
667    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
668  assert(image->cache != (Cache) NULL);
669  cache_info=(CacheInfo *) image->cache;
670  assert(cache_info->signature == MagickSignature);
671  if (cache_info->methods.acquire_pixel_handler == (AcquirePixelHandler) NULL)
672    return((const PixelPacket *) NULL);
673  pixels=cache_info->methods.acquire_pixel_handler(image,
674    GetCacheVirtualPixelMethod(image),x,y,columns,rows,exception);
675  return(pixels);
676}
677
678/*
679%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
680%                                                                             %
681%                                                                             %
682%                                                                             %
683%   A c q u i r e I n d e x e s                                               %
684%                                                                             %
685%                                                                             %
686%                                                                             %
687%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
688%
689%  AcquireIndexes() returns the black channel or the colormap indexes
690%  associated with the last call to SetImagePixels() or AcquireImagePixels().
691%  NULL is returned if the black channel or colormap indexes are not available.
692%
693%  The format of the AcquireIndexes() method is:
694%
695%      const IndexPacket *AcquireIndexes(const Image *image)
696%
697%  A description of each parameter follows:
698%
699%    o indexes: AcquireIndexes() returns the indexes associated with the last
700%      call to SetImagePixels() or AcquireImagePixels().
701%
702%    o image: the image.
703%
704*/
705MagickExport const IndexPacket *AcquireIndexes(const Image *image)
706{
707  CacheInfo
708    *cache_info;
709
710  assert(image != (const Image *) NULL);
711  assert(image->signature == MagickSignature);
712  if (image->debug != MagickFalse)
713    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
714  assert(image->cache != (Cache) NULL);
715  cache_info=(CacheInfo *) image->cache;
716  assert(cache_info->signature == MagickSignature);
717  if (cache_info->methods.acquire_indexes_from_handler ==
718      (AcquireIndexesFromHandler) NULL)
719    return((IndexPacket *) NULL);
720  return(cache_info->methods.acquire_indexes_from_handler(image));
721}
722
723/*
724%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
725%                                                                             %
726%                                                                             %
727%                                                                             %
728+   G e t I n d e x e s F r o m C a c h e                                     %
729%                                                                             %
730%                                                                             %
731%                                                                             %
732%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
733%
734%  AcquireIndexesFromCache() returns the indexes associated with the last callV
735%  to SetPixelCache() or AcquirePixelCache().
736%
737%  The format of the AcquireIndexesFromCache() method is:
738%
739%      IndexPacket *AcquireIndexesFromCache(const Image *image)
740%
741%  A description of each parameter follows:
742%
743%    o indexes: AcquireIndexesFromCache() returns the indexes associated with the
744%      last call to SetPixelCache() or AcquirePixelCache().
745%
746%    o image: the image.
747%
748*/
749static const IndexPacket *AcquireIndexesFromCache(const Image *image)
750{
751  assert(image != (Image *) NULL);
752  assert(image->signature == MagickSignature);
753  if (image->debug != MagickFalse)
754    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
755  assert(image->cache != (Cache) NULL);
756  return(AcquireNexusIndexes(image->cache,0));
757}
758
759/*
760%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
761%                                                                             %
762%                                                                             %
763%                                                                             %
764+   A c q u i r e N e x u s I n d e x e s                                     %
765%                                                                             %
766%                                                                             %
767%                                                                             %
768%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
769%
770%  AcquireNexusIndexes() returns the indexes associated with the specified
771%  cache nexus.
772%
773%  The format of the AcquireNexusIndexes() method is:
774%
775%      const IndexPacket *AcquireNexusIndexes(const Cache cache,
776%        const unsigned long nexus)
777%
778%  A description of each parameter follows:
779%
780%    o indexes: AcquireNexusIndexes returns the indexes associated with the
781%      specified cache nexus.
782%
783%    o cache: the pixel cache.
784%
785%    o nexus: specifies which cache nexus to return the colormap indexes.
786%
787*/
788MagickExport const IndexPacket *AcquireNexusIndexes(const Cache cache,
789  const unsigned long nexus)
790{
791  CacheInfo
792    *cache_info;
793
794  register NexusInfo
795    *nexus_info;
796
797  if (cache == (Cache) NULL)
798    return((IndexPacket *) NULL);
799  cache_info=(CacheInfo *) cache;
800  assert(cache_info->signature == MagickSignature);
801  if (cache_info->storage_class == UndefinedClass)
802    return((IndexPacket *) NULL);
803  nexus_info=cache_info->nexus_info+nexus;
804  return(nexus_info->indexes);
805}
806
807/*
808%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
809%                                                                             %
810%                                                                             %
811%                                                                             %
812+   A c q u i r e P i x e l C a c h e                                         %
813%                                                                             %
814%                                                                             %
815%                                                                             %
816%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
817%
818%  AcquirePixelCache() acquires pixels from the in-memory or disk pixel
819%  cache as defined by the geometry parameters.   A pointer to the pixels
820%  is returned if the pixels are transferred, otherwise a NULL is returned.
821%
822%  The format of the AcquirePixelCache() method is:
823%
824%      const PixelPacket *AcquirePixelCache(const Image *image,
825%        const VirtualPixelMethod virtual_pixel_method,const long x,
826%        const long y,const unsigned long columns,const unsigned long rows,
827%        ExceptionInfo *exception)
828%
829%  A description of each parameter follows:
830%
831%    o image: the image.
832%
833%    o virtual_pixel_method: the virtual pixel method.
834%
835%    o x,y,columns,rows:  These values define the perimeter of a region of
836%      pixels.
837%
838%    o exception: Return any errors or warnings in this structure.
839%
840*/
841static const PixelPacket *AcquirePixelCache(const Image *image,
842  const VirtualPixelMethod virtual_pixel_method,const long x,const long y,
843  const unsigned long columns,const unsigned long rows,ExceptionInfo *exception)
844{
845  const PixelPacket
846    *pixels;
847
848  if (image->debug != MagickFalse)
849    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
850  pixels=AcquireCacheNexus(image,virtual_pixel_method,x,y,columns,
851    rows,0,exception);
852  return(pixels);
853}
854
855/*
856%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
857%                                                                             %
858%                                                                             %
859%                                                                             %
860%   A c q u i r e O n e M a g i c k P i x e l                                 %
861%                                                                             %
862%                                                                             %
863%                                                                             %
864%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
865%
866%  AcquireOneMagickPixel() returns a single pixel at the specified (x,y)
867%  location.  The image background color is returned if an error occurs.  If
868%  you plan to modify the pixel, use GetOnePixel() instead.
869%
870%  The format of the AcquireOneMagickPixel() method is:
871%
872%      MagickPixelPacket AcquireOneMagickPixel(const Image image,const long x,
873%        const long y,ExceptionInfo exception)
874%
875%  A description of each parameter follows:
876%
877%    o pixels: AcquireOneMagickPixel() returns a pixel at the specified (x,y)
878%      location.
879%
880%    o image: the image.
881%
882%    o x,y:  These values define the location of the pixel to return.
883%
884%    o exception: Return any errors or warnings in this structure.
885%
886*/
887MagickExport MagickPixelPacket AcquireOneMagickPixel(const Image *image,
888  const long x,const long y,ExceptionInfo *exception)
889{
890  CacheInfo
891    *cache_info;
892
893  MagickPixelPacket
894    pixel;
895
896  register const PixelPacket
897    *p;
898
899  register IndexPacket
900    *indexes;
901
902  assert(image != (const Image *) NULL);
903  assert(image->signature == MagickSignature);
904  assert(image->cache != (Cache) NULL);
905  cache_info=(CacheInfo *) image->cache;
906  assert(cache_info->signature == MagickSignature);
907  GetMagickPixelPacket(image,&pixel);
908  p=AcquirePixelCache(image,GetCacheVirtualPixelMethod(image),x,y,1,1,
909    exception);
910  indexes=GetIndexes(image);
911  SetMagickPixelPacket(image,p,indexes,&pixel);
912  return(pixel);
913}
914
915/*
916%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
917%                                                                             %
918%                                                                             %
919%                                                                             %
920%   A c q u i r e O n e P i x e l                                             %
921%                                                                             %
922%                                                                             %
923%        Â