cache.c

Go to the documentation of this file.
00001 /*
00002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00003 %                                                                             %
00004 %                                                                             %
00005 %                                                                             %
00006 %                      CCCC   AAA    CCCC  H   H  EEEEE                       %
00007 %                     C      A   A  C      H   H  E                           %
00008 %                     C      AAAAA  C      HHHHH  EEE                         %
00009 %                     C      A   A  C      H   H  E                           %
00010 %                      CCCC  A   A   CCCC  H   H  EEEEE                       %
00011 %                                                                             %
00012 %                                                                             %
00013 %                       MagickCore Pixel Cache Methods                        %
00014 %                                                                             %
00015 %                              Software Design                                %
00016 %                                John Cristy                                  %
00017 %                                 July 1999                                   %
00018 %                                                                             %
00019 %                                                                             %
00020 %  Copyright 1999-2008 ImageMagick Studio LLC, a non-profit organization      %
00021 %  dedicated to making software imaging solutions freely available.           %
00022 %                                                                             %
00023 %  You may not use this file except in compliance with the License.  You may  %
00024 %  obtain a copy of the License at                                            %
00025 %                                                                             %
00026 %    http://www.imagemagick.org/script/license.php                            %
00027 %                                                                             %
00028 %  Unless required by applicable law or agreed to in writing, software        %
00029 %  distributed under the License is distributed on an "AS IS" BASIS,          %
00030 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
00031 %  See the License for the specific language governing permissions and        %
00032 %  limitations under the License.                                             %
00033 %                                                                             %
00034 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00035 %
00036 %
00037 %
00038 */
00039 
00040 /*
00041   Include declarations.
00042 */
00043 #include "magick/studio.h"
00044 #include "magick/blob.h"
00045 #include "magick/blob-private.h"
00046 #include "magick/cache.h"
00047 #include "magick/cache-private.h"
00048 #include "magick/color-private.h"
00049 #include "magick/composite-private.h"
00050 #include "magick/exception.h"
00051 #include "magick/exception-private.h"
00052 #include "magick/list.h"
00053 #include "magick/log.h"
00054 #include "magick/magick.h"
00055 #include "magick/memory_.h"
00056 #include "magick/pixel-private.h"
00057 #include "magick/quantum.h"
00058 #include "magick/random_.h"
00059 #include "magick/resource_.h"
00060 #include "magick/semaphore.h"
00061 #include "magick/splay-tree.h"
00062 #include "magick/string_.h"
00063 #include "magick/utility.h"
00064 #if defined(MAGICKCORE_ZLIB_DELEGATE)
00065 #include "zlib.h"
00066 #endif
00067 #if defined(MAGICKCORE_HAVE_PTHREAD)
00068 #include <pthread.h>
00069 #endif
00070 #if defined(__WINDOWS__)
00071 #include <windows.h>
00072 #endif
00073 
00074 /*
00075   Typedef declarations.
00076 */
00077 struct _NexusInfo
00078 {
00079   MagickBooleanType
00080     reserve,
00081     mapped;
00082 
00083   RectangleInfo
00084     region;
00085 
00086   MagickSizeType
00087     length;
00088 
00089   PixelPacket
00090     *cache,
00091     *pixels;
00092 
00093   IndexPacket
00094     *indexes;
00095 
00096   unsigned long
00097     signature;
00098 };
00099 
00100 /*
00101   Forward declarations.
00102 */
00103 #if defined(__cplusplus) || defined(c_plusplus)
00104 extern "C" {
00105 #endif
00106 
00107 static const PixelPacket
00108   *AcquirePixelCache(const Image *,const VirtualPixelMethod,const long,
00109     const long,const unsigned long,const unsigned long,ExceptionInfo *);
00110 
00111 static IndexPacket
00112   *GetIndexesFromCache(const Image *);
00113 
00114 static MagickBooleanType
00115   GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
00116     const long,const long,PixelPacket *,ExceptionInfo *),
00117   GetOneAuthenticPixelFromCache(Image *,const long,const long,PixelPacket *,
00118     ExceptionInfo *),
00119   OpenCache(Image *,const MapMode,ExceptionInfo *),
00120   SyncCache(Image *,ExceptionInfo *),
00121   SyncPixelCache(Image *,ExceptionInfo *),
00122   SyncImagePixelCache(Image *,ExceptionInfo *);
00123 
00124 static PixelPacket
00125   *GetPixelCache(Image *,const long,const long,const unsigned long,
00126     const unsigned long,ExceptionInfo *),
00127   *GetPixelsFromCache(const Image *),
00128   *SetPixelCache(Image *,const long,const long,const unsigned long,
00129     const unsigned long,ExceptionInfo *);
00130 
00131 static void
00132   DestroyPixelCache(Image *);
00133 
00134 #if defined(__cplusplus) || defined(c_plusplus)
00135 }
00136 #endif
00137 
00138 /*
00139   Forward declarations.
00140 */
00141 static PixelPacket
00142   *SetNexus(const Image *,const RectangleInfo *,NexusInfo *);
00143 
00144 static MagickBooleanType
00145   ReadCacheIndexes(CacheInfo *,NexusInfo *,ExceptionInfo *),
00146   ReadCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
00147   WriteCacheIndexes(CacheInfo *,NexusInfo *,ExceptionInfo *),
00148   WriteCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
00149 
00150 /*
00151   Global declarations.
00152 */
00153 static volatile MagickBooleanType
00154   instantiate_cache = MagickFalse;
00155 
00156 static SemaphoreInfo
00157   *cache_semaphore = (SemaphoreInfo *) NULL;
00158 
00159 static SplayTreeInfo
00160   *cache_resources = (SplayTreeInfo *) NULL;
00161 
00162 /*
00163 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00164 %                                                                             %
00165 %                                                                             %
00166 %                                                                             %
00167 +   A c q u i r e C a c h e N e x u s                                         %
00168 %                                                                             %
00169 %                                                                             %
00170 %                                                                             %
00171 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00172 %
00173 %  AcquireCacheNexus() acquires pixels from the in-memory or disk pixel cache
00174 %  as defined by the geometry parameters.   A pointer to the pixels is
00175 %  returned if the pixels are transferred, otherwise a NULL is returned.
00176 %
00177 %  The format of the AcquireCacheNexus() method is:
00178 %
00179 %      PixelPacket *AcquireCacheNexus(const Image *image,
00180 %        const VirtualPixelMethod method,const long x,const long y,
00181 %        const unsigned long columns,const unsigned long rows,
00182 %        NexusInfo *nexus_info,ExceptionInfo *exception)
00183 %
00184 %  A description of each parameter follows:
00185 %
00186 %    o image: the image.
00187 %
00188 %    o virtual_pixel_method: the virtual pixel method.
00189 %
00190 %    o x,y,columns,rows:  These values define the perimeter of a region of
00191 %      pixels.
00192 %
00193 %    o nexus_info: the cache nexus to acquire.
00194 %
00195 %    o exception: return any errors or warnings in this structure.
00196 %
00197 */
00198 
00199 static long
00200   DitherMatrix[64] =
00201   {
00202      0,  48,  12,  60,   3,  51,  15,  63,
00203     32,  16,  44,  28,  35,  19,  47,  31,
00204      8,  56,   4,  52,  11,  59,   7,  55,
00205     40,  24,  36,  20,  43,  27,  39,  23,
00206      2,  50,  14,  62,   1,  49,  13,  61,
00207     34,  18,  46,  30,  33,  17,  45,  29,
00208     10,  58,   6,  54,   9,  57,   5,  53,
00209     42,  26,  38,  22,  41,  25,  37,  21
00210   };
00211 
00212 static inline long DitherX(const unsigned long columns,const long x)
00213 {
00214   long
00215     index;
00216 
00217   index=x+DitherMatrix[x & 0x07]-32L;
00218   if (index < 0L)
00219     return(0L);
00220   if (index >= (long) columns)
00221     return((long) columns-1L);
00222   return(index);
00223 }
00224 
00225 static inline long DitherY(const unsigned long rows,const long y)
00226 {
00227   long
00228     index;
00229 
00230   index=y+DitherMatrix[y & 0x07]-32L;
00231   if (index < 0L)
00232     return(0L);
00233   if (index >= (long) rows)
00234     return((long) rows-1L);
00235   return(index);
00236 }
00237 
00238 static inline long EdgeX(const unsigned long columns,const long x)
00239 {
00240   if (x < 0L)
00241     return(0L);
00242   if (x >= (long) columns)
00243     return((long) columns-1L);
00244   return(x);
00245 }
00246 
00247 static inline long EdgeY(const unsigned long rows,const long y)
00248 {
00249   if (y < 0L)
00250     return(0L);
00251   if (y >= (long) rows)
00252     return((long) rows-1L);
00253   return(y);
00254 }
00255 
00256 static inline MagickSizeType MagickMax(const MagickSizeType x,
00257   const MagickSizeType y)
00258 {
00259   if (x > y)
00260     return(x);
00261   return(y);
00262 }
00263 
00264 static inline MagickSizeType MagickMin(const MagickSizeType x,
00265   const MagickSizeType y)
00266 {
00267   if (x < y)
00268     return(x);
00269   return(y);
00270 }
00271 
00272 
00273 static inline long RandomX(const unsigned long columns)
00274 {
00275   long
00276     x;
00277 
00278   x=(long) (columns*GetPseudoRandomValue()+0.5);
00279   if (x >= (long) columns)
00280     return((long) columns-1L);
00281   return(x);
00282 }
00283 
00284 static inline long RandomY(const unsigned long rows)
00285 {
00286   long
00287     y;
00288 
00289   y=(long) (rows*GetPseudoRandomValue()+0.5);
00290   if (y >= (long) rows)
00291     return((long) rows-1L);
00292   return(y);
00293 }
00294 
00295 static inline long TileX(const unsigned long columns,const long x)
00296 {
00297   if (x < 0L)
00298     return((long) columns+((x+1) % (long) columns)-1);
00299   if (x >= (long) columns)
00300     return(x % (long) columns);
00301   return(x);
00302 }
00303 
00304 static inline long TileY(const unsigned long rows,const long y)
00305 {
00306   if (y < 0L)
00307     return((long) rows+((y+1) % (long) rows)-1L);
00308   if (y >= (long) rows)
00309     return(y % (long) rows);
00310   return(y);
00311 }
00312 
00313 static inline long MirrorX(const unsigned long columns,const long x)
00314 {
00315   if ((x < 0) || (x >= (long) columns))
00316     return((long) columns-TileX(columns,x)-1L);
00317   return(x);
00318 }
00319 
00320 static inline long MirrorY(const unsigned long rows,const long y)
00321 {
00322   if ((y < 0) || (y >= (long) rows))
00323     return((long) rows-TileX(rows,y)-1L);
00324   return(y);
00325 }
00326 
00327 static inline MagickBooleanType IsNexusInCore(const CacheInfo *cache_info,
00328   NexusInfo *nexus_info)
00329 {
00330   MagickOffsetType
00331     offset;
00332 
00333   offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
00334     nexus_info->region.x;
00335   if (nexus_info->pixels != (cache_info->pixels+offset))
00336     return(MagickFalse);
00337   return(MagickTrue);
00338 }
00339 
00340 MagickExport const PixelPacket *AcquireCacheNexus(const Image *image,
00341   const VirtualPixelMethod virtual_pixel_method,const long x,const long y,
00342   const unsigned long columns,const unsigned long rows,NexusInfo *nexus_info,
00343   ExceptionInfo *exception)
00344 {
00345   CacheInfo
00346     *cache_info;
00347 
00348   IndexPacket
00349     *indexes;
00350 
00351   MagickOffsetType
00352     offset;
00353 
00354   MagickSizeType
00355     length,
00356     number_pixels;
00357 
00358   NexusInfo
00359     *virtual_nexus;
00360 
00361   PixelPacket
00362     *pixels;
00363 
00364   RectangleInfo
00365     region;
00366 
00367   register const IndexPacket
00368     *nexus_indexes;
00369 
00370   register const PixelPacket
00371     *p;
00372 
00373   register long
00374     u,
00375     v;
00376 
00377   register PixelPacket
00378     *q;
00379 
00380   /*
00381     Acquire pixels.
00382   */
00383   if (image->debug != MagickFalse)
00384     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00385   cache_info=(CacheInfo *) image->cache;
00386   if (cache_info->type == UndefinedCache)
00387     return((const PixelPacket *) NULL);
00388   region.x=x;
00389   region.y=y;
00390   region.width=columns;
00391   region.height=rows;
00392   pixels=SetNexus(image,&region,nexus_info);
00393   if (pixels == (PixelPacket *) NULL)
00394     return((const PixelPacket *) NULL);
00395   offset=(MagickOffsetType) region.y*cache_info->columns+region.x;
00396   length=(MagickSizeType) (region.height-1)*cache_info->columns+region.width-1;
00397   number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
00398   if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
00399     if ((x >= 0) && ((long) (x+columns) <= (long) cache_info->columns) &&
00400         (y >= 0) && ((long) (y+rows) <= (long) cache_info->rows))
00401       {
00402         /*
00403           Pixel request is inside cache extents.
00404         */
00405         if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
00406           return(pixels);
00407         if (ReadCachePixels(cache_info,nexus_info,exception) == MagickFalse)
00408           return((const PixelPacket *) NULL);
00409         if ((cache_info->storage_class == PseudoClass) ||
00410             (cache_info->colorspace == CMYKColorspace))
00411           if (ReadCacheIndexes(cache_info,nexus_info,exception) == MagickFalse)
00412             return((const PixelPacket *) NULL);
00413         return(pixels);
00414       }
00415   /*
00416     Pixel request is outside cache extents.
00417   */
00418   q=pixels;
00419   indexes=GetNexusIndexes(cache_info,nexus_info);
00420   virtual_nexus=AcquireNexusInfo();
00421   if (virtual_nexus == (NexusInfo *) NULL)
00422     {
00423       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
00424         "UnableToGetCacheNexus","`%s'",image->filename);
00425       return((const PixelPacket *) NULL);
00426     }
00427   for (v=0; v < (long) rows; v++)
00428   {
00429     for (u=0; u < (long) columns; u+=length)
00430     {
00431       length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
00432       if ((((x+u) < 0) || ((x+u) >= (long) cache_info->columns)) ||
00433           (((y+v) < 0) || ((y+v) >= (long) cache_info->rows)) || (length == 0))
00434         {
00435           /*
00436             Transfer a single pixel.
00437           */
00438           length=(MagickSizeType) 1;
00439           switch (virtual_pixel_method)
00440           {
00441             case BackgroundVirtualPixelMethod:
00442             case ConstantVirtualPixelMethod:
00443             {
00444               p=AcquireCacheNexus(image,virtual_pixel_method,
00445                 EdgeX(cache_info->columns,x+u),EdgeY(cache_info->rows,y+v),
00446                 1UL,1UL,virtual_nexus,exception);
00447               cache_info->virtual_pixel=image->background_color;
00448               p=(&cache_info->virtual_pixel);
00449               break;
00450             }
00451             case BlackVirtualPixelMethod:
00452             {
00453               p=AcquireCacheNexus(image,virtual_pixel_method,
00454                 EdgeX(cache_info->columns,x+u),EdgeY(cache_info->rows,y+v),
00455                 1UL,1UL,virtual_nexus,exception);
00456               cache_info->virtual_pixel.red=0;
00457               cache_info->virtual_pixel.green=0;
00458               cache_info->virtual_pixel.blue=0;
00459               cache_info->virtual_pixel.opacity=OpaqueOpacity;
00460               p=(&cache_info->virtual_pixel);
00461               break;
00462             }
00463             case DitherVirtualPixelMethod:
00464             {
00465               p=AcquireCacheNexus(image,virtual_pixel_method,
00466                 DitherX(cache_info->columns,x+u),DitherY(cache_info->rows,y+v),
00467                 1UL,1UL,virtual_nexus,exception);
00468               break;
00469             }
00470             case EdgeVirtualPixelMethod:
00471             default:
00472             {
00473               p=AcquireCacheNexus(image,virtual_pixel_method,
00474                 EdgeX(cache_info->columns,x+u),EdgeY(cache_info->rows,y+v),
00475                 1UL,1UL,virtual_nexus,exception);
00476               break;
00477             }
00478             case GrayVirtualPixelMethod:
00479             {
00480               p=AcquireCacheNexus(image,virtual_pixel_method,
00481                 EdgeX(cache_info->columns,x+u),EdgeY(cache_info->rows,y+v),
00482                 1UL,1UL,virtual_nexus,exception);
00483               cache_info->virtual_pixel.red=(Quantum) QuantumRange/2;
00484               cache_info->virtual_pixel.green=(Quantum) QuantumRange/2;
00485               cache_info->virtual_pixel.blue=(Quantum) QuantumRange/2;
00486               cache_info->virtual_pixel.opacity=(Quantum) OpaqueOpacity;
00487               p=(&cache_info->virtual_pixel);
00488               break;
00489             }
00490             case HorizontalTileVirtualPixelMethod:
00491             {
00492               p=AcquireCacheNexus(image,virtual_pixel_method,
00493                 TileX(cache_info->columns,x+u),TileY(cache_info->rows,y+v),
00494                 1UL,1UL,virtual_nexus,exception);
00495               if (((y+v) < 0) || ((y+v) >= (long) cache_info->rows))
00496                 {
00497                   cache_info->virtual_pixel=image->background_color;
00498                   p=(&cache_info->virtual_pixel);
00499                 }
00500               break;
00501             }
00502             case MirrorVirtualPixelMethod:
00503             {
00504               p=AcquireCacheNexus(image,virtual_pixel_method,
00505                 MirrorX(cache_info->columns,x+u),MirrorY(cache_info->rows,y+v),
00506                 1UL,1UL,virtual_nexus,exception);
00507               break;
00508             }
00509             case RandomVirtualPixelMethod:
00510             {
00511               p=AcquireCacheNexus(image,virtual_pixel_method,
00512                 RandomX(cache_info->columns),RandomY(cache_info->rows),
00513                 1UL,1UL,virtual_nexus,exception);
00514               break;
00515             }
00516             case TileVirtualPixelMethod:
00517             {
00518               p=AcquireCacheNexus(image,virtual_pixel_method,
00519                 TileX(cache_info->columns,x+u),TileY(cache_info->rows,y+v),
00520                 1UL,1UL,virtual_nexus,exception);
00521               break;
00522             }
00523             case TransparentVirtualPixelMethod:
00524             {
00525               p=AcquireCacheNexus(image,virtual_pixel_method,
00526                 EdgeX(cache_info->columns,x+u),EdgeY(cache_info->rows,y+v),
00527                 1UL,1UL,virtual_nexus,exception);
00528               cache_info->virtual_pixel.red=(Quantum) 0;
00529               cache_info->virtual_pixel.green=(Quantum) 0;
00530               cache_info->virtual_pixel.blue=(Quantum) 0;
00531               cache_info->virtual_pixel.opacity=(Quantum) TransparentOpacity;
00532               p=(&cache_info->virtual_pixel);
00533               break;
00534             }
00535             case VerticalTileVirtualPixelMethod:
00536             {
00537               p=AcquireCacheNexus(image,virtual_pixel_method,
00538                 TileX(cache_info->columns,x+u),TileY(cache_info->rows,y+v),
00539                 1UL,1UL,virtual_nexus,exception);
00540               if (((x+u) < 0) || ((x+u) >= (long) cache_info->columns))
00541                 {
00542                   cache_info->virtual_pixel=image->background_color;
00543                   p=(&cache_info->virtual_pixel);
00544                 }
00545               break;
00546             }
00547             case MaskVirtualPixelMethod:
00548             case WhiteVirtualPixelMethod:
00549             {
00550               p=AcquireCacheNexus(image,virtual_pixel_method,
00551                 EdgeX(cache_info->columns,x+u),EdgeY(cache_info->rows,y+v),
00552                 1UL,1UL,virtual_nexus,exception);
00553               cache_info->virtual_pixel.red=(Quantum) QuantumRange;
00554               cache_info->virtual_pixel.green=(Quantum) QuantumRange;
00555               cache_info->virtual_pixel.blue=(Quantum) QuantumRange;
00556               cache_info->virtual_pixel.opacity=OpaqueOpacity;
00557               p=(&cache_info->virtual_pixel);
00558               break;
00559             }
00560           }
00561           if (p == (const PixelPacket *) NULL)
00562             break;
00563           *q++=(*p);
00564           if (indexes != (IndexPacket *) NULL)
00565             {
00566               nexus_indexes=AcquireNexusIndexes(cache_info,virtual_nexus);
00567               if (nexus_indexes != (const IndexPacket *) NULL)
00568                 *indexes++=(*nexus_indexes);
00569             }
00570           continue;
00571         }
00572       /*
00573         Transfer a run of pixels.
00574       */
00575       p=AcquireCacheNexus(image,virtual_pixel_method,x+u,y+v,(unsigned long)
00576         length,1UL,virtual_nexus,exception);
00577       if (p == (const PixelPacket *) NULL)
00578         break;
00579       (void) CopyMagickMemory(q,p,(size_t) length*sizeof(*p));
00580       q+=length;
00581       if (indexes != (IndexPacket *) NULL)
00582         {
00583           nexus_indexes=AcquireNexusIndexes(cache_info,virtual_nexus);
00584           if (nexus_indexes != (const IndexPacket *) NULL)
00585             {
00586               (void) CopyMagickMemory(indexes,nexus_indexes,(size_t) length*
00587                 sizeof(*nexus_indexes));
00588               indexes+=length;
00589             }
00590         }
00591     }
00592   }
00593   virtual_nexus=DestroyNexusInfo(virtual_nexus);
00594   return(pixels);
00595 }
00596 
00597 /*
00598 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00599 %                                                                             %
00600 %                                                                             %
00601 %                                                                             %
00602 +   A c q u i r e I n d e x e s F r o m C a c h e                             %
00603 %                                                                             %
00604 %                                                                             %
00605 %                                                                             %
00606 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00607 %
00608 %  AcquireIndexesFromCache() returns the indexes associated with the last call
00609 %  to SetPixelCache() or AcquirePixelCache().
00610 %
00611 %  The format of the AcquireIndexesFromCache() method is:
00612 %
00613 %      IndexPacket *AcquireIndexesFromCache(const Image *image)
00614 %
00615 %  A description of each parameter follows:
00616 %
00617 %    o image: the image.
00618 %
00619 */
00620 
00621 static inline long GetNexusInfoThreadId(void)
00622 {
00623 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00624   return(omp_get_thread_num());
00625 #else
00626   return(0);
00627 #endif
00628 }
00629 
00630 static const IndexPacket *AcquireIndexesFromCache(const Image *image)
00631 {
00632   CacheInfo
00633     *cache_info;
00634 
00635   const IndexPacket
00636     *indexes;
00637 
00638   long
00639     id;
00640 
00641   if (image->debug != MagickFalse)
00642     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00643   cache_info=(CacheInfo *) image->cache;
00644   id=GetNexusInfoThreadId();
00645   indexes=AcquireNexusIndexes(image->cache,cache_info->nexus_info[id]);
00646   return(indexes);
00647 }
00648 
00649 /*
00650 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00651 %                                                                             %
00652 %                                                                             %
00653 %                                                                             %
00654 +   A c q u i r e P i x e l s F r o m C a c h e                               %
00655 %                                                                             %
00656 %                                                                             %
00657 %                                                                             %
00658 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00659 %
00660 %  AcquirePixelsFromCache() returns the pixels associated with the last call
00661 %  to SetPixelCache() or AcquirePixelCache().
00662 %
00663 %  The format of the AcquirePixelsFromCache() method is:
00664 %
00665 %      IndexPacket *AcquirePixelsFromCache(const Image *image)
00666 %
00667 %  A description of each parameter follows:
00668 %
00669 %    o pixels: AcquirePixelsFromCache() returns the pixels associated with the
00670 %      last call to SetPixelCache() or AcquirePixelCache().
00671 %
00672 %    o image: the image.
00673 %
00674 */
00675 static const PixelPacket *AcquirePixelsFromCache(const Image *image)
00676 {
00677   CacheInfo
00678     *cache_info;
00679 
00680   const PixelPacket
00681     *pixels;
00682 
00683   long
00684     id;
00685 
00686   if (image->debug != MagickFalse)
00687     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00688   cache_info=(CacheInfo *) image->cache;
00689   id=GetNexusInfoThreadId();
00690   pixels=AcquireNexusPixels(image->cache,cache_info->nexus_info[id]);
00691   return(pixels);
00692 }
00693 
00694 /*
00695 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00696 %                                                                             %
00697 %                                                                             %
00698 %                                                                             %
00699 +   A c q u i r e N e x u s I n d e x e s                                     %
00700 %                                                                             %
00701 %                                                                             %
00702 %                                                                             %
00703 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00704 %
00705 %  AcquireNexusIndexes() returns the indexes associated with the specified
00706 %  cache nexus.
00707 %
00708 %  The format of the AcquireNexusIndexes() method is:
00709 %
00710 %      const IndexPacket *AcquireNexusIndexes(const Cache cache,
00711 %        NexusInfo *nexus_info)
00712 %
00713 %  A description of each parameter follows:
00714 %
00715 %    o cache: the pixel cache.
00716 %
00717 %    o nexus_info: the cache nexus to return the colormap indexes.
00718 %
00719 */
00720 MagickExport const IndexPacket *AcquireNexusIndexes(const Cache cache,
00721   NexusInfo *nexus_info)
00722 {
00723   CacheInfo
00724     *cache_info;
00725 
00726   if (cache == (Cache) NULL)
00727     return((IndexPacket *) NULL);
00728   cache_info=(CacheInfo *) cache;
00729   assert(cache_info->signature == MagickSignature);
00730   if (cache_info->storage_class == UndefinedClass)
00731     return((IndexPacket *) NULL);
00732   return(nexus_info->indexes);
00733 }
00734 
00735 /*
00736 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00737 %                                                                             %
00738 %                                                                             %
00739 %                                                                             %
00740 %   A c q u i r e N e x u s I n f o                                           %
00741 %                                                                             %
00742 %                                                                             %
00743 %                                                                             %
00744 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00745 %
00746 %  AcquireNexusInfo() allocates the NexusInfo structure.
00747 %
00748 %  The format of the AcquireNexusInfo method is:
00749 %
00750 %      NexusInfo *AcquireNexusInfo(void)
00751 %
00752 */
00753 MagickExport NexusInfo *AcquireNexusInfo(void)
00754 {
00755   NexusInfo
00756     *nexus_info;
00757 
00758   nexus_info=(NexusInfo *) AcquireMagickMemory(sizeof(*nexus_info));
00759         if (nexus_info == (NexusInfo *) NULL)
00760     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
00761         (void) ResetMagickMemory(nexus_info,0,sizeof(*nexus_info));
00762   nexus_info->signature=MagickSignature;
00763   return(nexus_info);
00764 }
00765 
00766 /*
00767 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00768 %                                                                             %
00769 %                                                                             %
00770 %                                                                             %
00771 %   A c q u i r e N e x u s I n f o T h r e a d S e t                         %
00772 %                                                                             %
00773 %                                                                             %
00774 %                                                                             %
00775 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00776 %
00777 %  AcquireNexusInfoThreadSet() acquires a set of views, one for each possible
00778 %  thread.
00779 %
00780 %  The format of the AcquireNexusInfoThreadSet method is:
00781 %
00782 %      NexusInfo **AcquireNexusInfoThreadSet(const unsigned long nexuses)
00783 %
00784 %  A description of each parameter follows:
00785 %
00786 %    o nexuses: the number of nexus to acquire.
00787 %
00788 */
00789 MagickExport NexusInfo **AcquireNexusInfoThreadSet(const unsigned long nexuses)
00790 {
00791   register long
00792     i;
00793 
00794   NexusInfo
00795     **nexus_info;
00796 
00797   nexus_info=(NexusInfo **) AcquireQuantumMemory(nexuses,sizeof(**nexus_info));
00798   if (nexus_info == (NexusInfo **) NULL)
00799     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
00800   for (i=0; i < (long) nexuses; i++)
00801     nexus_info[i]=AcquireNexusInfo();
00802   return(nexus_info);
00803 }
00804 
00805 /*
00806 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00807 %                                                                             %
00808 %                                                                             %
00809 %                                                                             %
00810 +   A c q u i r e N e x u s P i x e l s                                       %
00811 %                                                                             %
00812 %                                                                             %
00813 %                                                                             %
00814 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00815 %
00816 %  AcquireNexusPixels() returns the pixels associated with the specified
00817 %  cache nexus.
00818 %
00819 %  The format of the AcquireNexusPixels() method is:
00820 %
00821 %      const IndexPacket *AcquireNexusPixels(const Cache cache,
00822 %        NexusInfo *nexus_info)
00823 %
00824 %  A description of each parameter follows:
00825 %
00826 %    o cache: the pixel cache.
00827 %
00828 %    o nexus_info: the cache nexus to return the colormap pixels.
00829 %
00830 */
00831 MagickExport const PixelPacket *AcquireNexusPixels(const Cache cache,
00832   NexusInfo *nexus_info)
00833 {
00834   CacheInfo
00835     *cache_info;
00836 
00837   if (cache == (Cache) NULL)
00838     return((PixelPacket *) NULL);
00839   cache_info=(CacheInfo *) cache;
00840   assert(cache_info->signature == MagickSignature);
00841   if (cache_info->storage_class == UndefinedClass)
00842     return((PixelPacket *) NULL);
00843   return((const PixelPacket *) nexus_info->pixels);
00844 }
00845 
00846 /*
00847 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00848 %                                                                             %
00849 %                                                                             %
00850 %                                                                             %
00851 +   A c q u i r e P i x e l C a c h e                                         %
00852 %                                                                             %
00853 %                                                                             %
00854 %                                                                             %
00855 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00856 %
00857 %  AcquirePixelCache() acquires pixels from the in-memory or disk pixel
00858 %  cache as defined by the geometry parameters.   A pointer to the pixels
00859 %  is returned if the pixels are transferred, otherwise a NULL is returned.
00860 %
00861 %  The format of the AcquirePixelCache() method is:
00862 %
00863 %      const PixelPacket *AcquirePixelCache(const Image *image,
00864 %        const VirtualPixelMethod virtual_pixel_method,const long x,
00865 %        const long y,const unsigned long columns,const unsigned long rows,
00866 %        ExceptionInfo *exception)
00867 %
00868 %  A description of each parameter follows:
00869 %
00870 %    o image: the image.
00871 %
00872 %    o virtual_pixel_method: the virtual pixel method.
00873 %
00874 %    o x,y,columns,rows:  These values define the perimeter of a region of
00875 %      pixels.
00876 %
00877 %    o exception: return any errors or warnings in this structure.
00878 %
00879 */
00880 static const PixelPacket *AcquirePixelCache(const Image *image,
00881   const VirtualPixelMethod virtual_pixel_method,const long x,const long y,
00882   const unsigned long columns,const unsigned long rows,ExceptionInfo *exception)
00883 {
00884   CacheInfo
00885    *cache_info;
00886 
00887   const PixelPacket
00888     *pixels;
00889 
00890   long
00891     id;
00892 
00893   if (image->debug != MagickFalse)
00894     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00895   cache_info=(CacheInfo *) image->cache;
00896   id=GetNexusInfoThreadId();
00897   pixels=AcquireCacheNexus(image,virtual_pixel_method,x,y,columns,rows,
00898     cache_info->nexus_info[id],exception);
00899   return(pixels);
00900 }
00901 
00902 /*
00903 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00904 %                                                                             %
00905 %                                                                             %
00906 %                                                                             %
00907 +   C l i p C a c h e N e x u s                                               %
00908 %                                                                             %
00909 %                                                                             %
00910 %                                                                             %
00911 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00912 %
00913 %  ClipCacheNexus() clips the cache nexus as defined by the image clip mask.
00914 %  The method returns MagickTrue if the pixel region is clipped, otherwise
00915 %  MagickFalse.
00916 %
00917 %  The format of the ClipCacheNexus() method is:
00918 %
00919 %      MagickBooleanType ClipCacheNexus(Image *image,NexusInfo *nexus_info)
00920 %
00921 %  A description of each parameter follows:
00922 %
00923 %    o image: the image.
00924 %
00925 %    o nexus_info: the cache nexus to clip.
00926 %
00927 */
00928 static MagickBooleanType ClipCacheNexus(Image *image,
00929   NexusInfo *nexus_info)
00930 {
00931   CacheInfo
00932     *cache_info;
00933 
00934   MagickSizeType
00935     number_pixels;
00936 
00937   NexusInfo
00938     *clip_nexus,
00939     *image_nexus;
00940 
00941   register const PixelPacket
00942     *r;
00943 
00944   register IndexPacket
00945     *nexus_indexes,
00946     *indexes;
00947 
00948   register long
00949     i;
00950 
00951   register PixelPacket
00952     *p,
00953     *q;
00954 
00955   /*
00956     Apply clip mask.
00957   */
00958   if (image->debug != MagickFalse)
00959     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00960   if (image->clip_mask == (Image *) NULL)
00961     return(MagickFalse);
00962   cache_info=(CacheInfo *) image->cache;
00963   image_nexus=AcquireNexusInfo();
00964   clip_nexus=AcquireNexusInfo();
00965   if ((image_nexus == (NexusInfo *) NULL) || (clip_nexus == (NexusInfo *) NULL))
00966     ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
00967   p=GetCacheNexus(image,nexus_info->region.x,nexus_info->region.y,
00968     nexus_info->region.width,nexus_info->region.height,image_nexus,
00969     &image->exception);
00970   indexes=GetNexusIndexes(image->cache,image_nexus);
00971   q=nexus_info->pixels;
00972   nexus_indexes=nexus_info->indexes;
00973   r=AcquireCacheNexus(image->clip_mask,MaskVirtualPixelMethod,
00974     nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
00975     nexus_info->region.height,clip_nexus,&image->exception);
00976   number_pixels=(MagickSizeType) nexus_info->region.width*
00977     nexus_info->region.height;
00978   for (i=0; i < (long) number_pixels; i++)
00979   {
00980     if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
00981       break;
00982     if (PixelIntensityToQuantum(r) > ((Quantum) QuantumRange/2))
00983       {
00984         q->red=p->red;
00985         q->green=p->green;
00986         q->blue=p->blue;
00987         q->opacity=p->opacity;
00988         if ((cache_info->storage_class == PseudoClass) ||
00989             (cache_info->colorspace == CMYKColorspace))
00990           nexus_indexes[i]=indexes[i];
00991       }
00992     p++;
00993     q++;
00994     r++;