Powered by Pair ImageMagick logo
Image Magick
Main Page | Namespace List | Class Hierarchy | Alphabetical List | Data Structures | File List | Namespace Members | Data Fields | Globals | Related Pages

ImageMagick-6.1.1/magick/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 % ImageMagick Pixel Cache Methods % 00014 % % 00015 % Software Design % 00016 % John Cristy % 00017 % July 1999 % 00018 % % 00019 % % 00020 % Copyright 1999-2004 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/www/Copyright.html % 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/composite_private.h" 00049 #include "magick/error.h" 00050 #include "magick/error_private.h" 00051 #include "magick/list.h" 00052 #include "magick/log.h" 00053 #include "magick/magick.h" 00054 #include "magick/memory_.h" 00055 #include "magick/resource_.h" 00056 #include "magick/semaphore.h" 00057 #include "magick/string_.h" 00058 #include "magick/utility.h" 00059 #if defined(HasZLIB) 00060 #include "zlib.h" 00061 #endif 00062 00063 /* 00064 Define declarations. 00065 */ 00066 #define DefaultNumberCacheViews 6UL 00067 00068 /* 00069 Typedef declarations. 00070 */ 00071 struct _NexusInfo 00072 { 00073 MagickBooleanType 00074 available; 00075 00076 unsigned long 00077 columns, 00078 rows; 00079 00080 long 00081 x, 00082 y; 00083 00084 MagickSizeType 00085 length; 00086 00087 PixelPacket 00088 *staging, 00089 *pixels; 00090 00091 IndexPacket 00092 *indexes; 00093 }; 00094 00095 /* 00096 Forward declarations. 00097 */ 00098 #if defined(__cplusplus) || defined(c_plusplus) 00099 extern "C" { 00100 #endif 00101 00102 static const PixelPacket 00103 *AcquirePixelCache(const Image *,const long,const long,const unsigned long, 00104 const unsigned long,ExceptionInfo *); 00105 00106 static IndexPacket 00107 *GetIndexesFromCache(const Image *); 00108 00109 static MagickBooleanType 00110 SyncPixelCache(Image *); 00111 00112 static PixelPacket 00113 AcquireOnePixelFromCache(const Image *,const long,const long,ExceptionInfo *), 00114 GetOnePixelFromCache(Image *,const long,const long), 00115 *GetPixelCache(Image *,const long,const long,const unsigned long, 00116 const unsigned long), 00117 *GetPixelsFromCache(const Image *), 00118 *SetPixelCache(Image *,const long,const long,const unsigned long, 00119 const unsigned long); 00120 00121 static void 00122 DestroyPixelCache(Image *); 00123 00124 #if defined(__cplusplus) || defined(c_plusplus) 00125 } 00126 #endif 00127 00128 /* 00129 Forward declaration. 00130 */ 00131 static PixelPacket 00132 *SetNexus(const Image *,const RectangleInfo *,const unsigned long); 00133 00134 static MagickBooleanType 00135 ReadCacheIndexes(const Cache,const unsigned long), 00136 ReadCachePixels(const Cache,const unsigned long), 00137 WriteCacheIndexes(Cache,const unsigned long), 00138 WriteCachePixels(Cache,const unsigned long); 00139 00140 /* 00141 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00142 % % 00143 % % 00144 % % 00145 + A c q u i r e C a c h e N e x u s % 00146 % % 00147 % % 00148 % % 00149 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00150 % 00151 % AcquireCacheNexus() acquires pixels from the in-memory or disk pixel cache 00152 % as defined by the geometry parameters. A pointer to the pixels is 00153 % returned if the pixels are transferred, otherwise a NULL is returned. 00154 % 00155 % The format of the AcquireCacheNexus() method is: 00156 % 00157 % PixelPacket *AcquireCacheNexus(const Image *image,const long x, 00158 % const long y,const unsigned long columns,const unsigned long rows, 00159 % const unsigned long nexus,ExceptionInfo *exception) 00160 % 00161 % A description of each parameter follows: 00162 % 00163 % o image: The image. 00164 % 00165 % o x,y,columns,rows: These values define the perimeter of a region of 00166 % pixels. 00167 % 00168 % o nexus: specifies which cache nexus to acquire. 00169 % 00170 % o exception: Return any errors or warnings in this structure. 00171 % 00172 % 00173 */ 00174 00175 static inline MagickBooleanType IsNexusInCore(const Cache cache, 00176 const unsigned long nexus) 00177 { 00178 CacheInfo 00179 *cache_info; 00180 00181 MagickOffsetType 00182 offset; 00183 00184 register NexusInfo 00185 *nexus_info; 00186 00187 cache_info=(CacheInfo *) cache; 00188 nexus_info=cache_info->nexus_info+nexus; 00189 offset=(MagickOffsetType) nexus_info->y*cache_info->columns+nexus_info->x; 00190 return((MagickBooleanType) (nexus_info->pixels == (cache_info->pixels+offset))); 00191 } 00192 00193 MagickExport const PixelPacket *AcquireCacheNexus(const Image *image, 00194 const long x,const long y,const unsigned long columns, 00195 const unsigned long rows,const unsigned long nexus,ExceptionInfo *exception) 00196 { 00197 #define EdgeX(x) ((x) < 0 ? 0 : (x) >= (long) cache_info->columns ? \ 00198 (long) cache_info->columns-1 : (x)) 00199 #define EdgeY(y) ((y) < 0 ? 0 : (y) >= (long) cache_info->rows ? \ 00200 (long) cache_info->rows-1 : (y)) 00201 #define MirrorX(x) ((((x) >= 0) && (x) < (long) cache_info->columns) ? \ 00202 (x) : (long) cache_info->columns-TileX(x)) 00203 #define MirrorY(y) ((((y) >= 0) && (y) < (long) cache_info->rows) ? \ 00204 (y) : (long) cache_info->rows-TileY(y)) 00205 #define TileX(x) (((x) >= 0) ? ((x) % (long) cache_info->columns) : \ 00206 (long) cache_info->columns-(-(x) % (long) cache_info->columns)) 00207 #define TileY(y) (((y) >= 0) ? ((y) % (long) cache_info->rows) : \ 00208 (long) cache_info->rows-(-(y) % (long) cache_info->rows)) 00209 00210 CacheInfo 00211 *cache_info; 00212 00213 IndexPacket 00214 *indexes, 00215 *nexus_indexes; 00216 00217 MagickOffsetType 00218 offset; 00219 00220 MagickSizeType 00221 length, 00222 number_pixels; 00223 00224 PixelPacket 00225 *pixels; 00226 00227 RectangleInfo 00228 region; 00229 00230 register const PixelPacket 00231 *p; 00232 00233 register long 00234 u, 00235 v; 00236 00237 register PixelPacket 00238 *q; 00239 00240 unsigned long 00241 image_nexus; 00242 00243 /* 00244 Acquire pixels. 00245 */ 00246 assert(image != (const Image *) NULL); 00247 assert(image->signature == MagickSignature); 00248 if (image->debug != MagickFalse) 00249 (void) LogMagickEvent(TraceEvent,GetMagickModule(),image->filename); 00250 assert(image->cache != (Cache) NULL); 00251 cache_info=(CacheInfo *) image->cache; 00252 if (cache_info->type == UndefinedCache) 00253 { 00254 (void) ThrowMagickException(exception,GetMagickModule(),CacheError, 00255 "PixelCacheIsNotOpen",image->filename); 00256 return((const PixelPacket *) NULL); 00257 } 00258 region.x=x; 00259 region.y=y; 00260 region.width=columns; 00261 region.height=rows; 00262 pixels=SetNexus(image,&region,nexus); 00263 offset=(MagickOffsetType) region.y*cache_info->columns+region.x; 00264 length=(MagickSizeType) (region.height-1)*cache_info->columns+region.width-1; 00265 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows; 00266 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels)) 00267 if ((x >= 0) && ((unsigned long) (x+columns) <= cache_info->columns) && 00268 (y >= 0) && ((unsigned long) (y+rows) <= cache_info->rows)) 00269 { 00270 MagickBooleanType 00271 status; 00272 00273 /* 00274 Pixel request is inside cache extents. 00275 */ 00276 if (IsNexusInCore(cache_info,nexus) != MagickFalse) 00277 return(pixels); 00278 status=ReadCachePixels(cache_info,nexus); 00279 if ((cache_info->storage_class == PseudoClass) || 00280 (cache_info->colorspace == CMYKColorspace)) 00281 if (ReadCacheIndexes(cache_info,nexus) == MagickFalse) 00282 status=MagickFalse; 00283 if (status == MagickFalse) 00284 { 00285 (void) ThrowMagickException(exception,GetMagickModule(),CacheError, 00286 "UnableToReadPixelCache",image->filename,strerror(errno)); 00287 return((const PixelPacket *) NULL); 00288 } 00289 return(pixels); 00290 } 00291 /* 00292 Pixel request is outside cache extents. 00293 */ 00294 indexes=GetNexusIndexes(cache_info,nexus); 00295 image_nexus=GetNexus(cache_info); 00296 if (image_nexus == 0) 00297 { 00298 (void) ThrowMagickException(exception,GetMagickModule(),CacheError, 00299 "UnableToGetCacheNexus",image->filename); 00300 return((const PixelPacket *) NULL); 00301 } 00302 cache_info->virtual_pixel=image->background_color; 00303 q=pixels; 00304 for (v=0; v < (long) rows; v++) 00305 { 00306 for (u=0; u < (long) columns; u+=length) 00307 { 00308 length=(MagickSizeType) Min(cache_info->columns-(x+u),columns-u); 00309 if ((((x+u) < 0) || ((x+u) >= (long) cache_info->columns)) || 00310 (((y+v) < 0) || ((y+v) >= (long) cache_info->rows)) || (length == 0)) 00311 { 00312 /* 00313 Transfer a single pixel. 00314 */ 00315 length=(MagickSizeType) 1; 00316 switch (cache_info->virtual_pixel_method) 00317 { 00318 case ConstantVirtualPixelMethod: 00319 { 00320 (void) AcquireCacheNexus(image,EdgeX(x+u),EdgeY(y+v),1UL,1UL, 00321 image_nexus,exception); 00322 p=(&cache_info->virtual_pixel); 00323 break; 00324 } 00325 case EdgeVirtualPixelMethod: 00326 default: 00327 { 00328 p=AcquireCacheNexus(image,EdgeX(x+u),EdgeY(y+v),1UL,1UL, 00329 image_nexus,exception); 00330 break; 00331 } 00332 case MirrorVirtualPixelMethod: 00333 { 00334 p=AcquireCacheNexus(image,MirrorX(x+u),MirrorY(y+v),1UL,1UL, 00335 image_nexus,exception); 00336 break; 00337 } 00338 case TileVirtualPixelMethod: 00339 { 00340 p=AcquireCacheNexus(image,TileX(x+u),TileY(y+v),1UL,1UL, 00341 image_nexus,exception); 00342 break; 00343 } 00344 } 00345 if (p == (const PixelPacket *) NULL) 00346 break; 00347 *q++=(*p); 00348 if (indexes == (IndexPacket *) NULL) 00349 continue; 00350 nexus_indexes=GetNexusIndexes(cache_info,image_nexus); 00351 if (nexus_indexes == (IndexPacket *) NULL) 00352 continue; 00353 *indexes++=(*nexus_indexes); 00354 continue; 00355 } 00356 /* 00357 Transfer a run of pixels. 00358 */ 00359 p=AcquireCacheNexus(image,x+u,y+v,(unsigned long) length,1UL,image_nexus, 00360 exception); 00361 if (p == (const PixelPacket *) NULL) 00362 break; 00363 (void) CopyMagickMemory(q,p,(size_t) length*sizeof(*q)); 00364 q+=length; 00365 if (indexes == (IndexPacket *) NULL) 00366 continue; 00367 nexus_indexes=GetNexusIndexes(cache_info,image_nexus); 00368 if (nexus_indexes == (IndexPacket *) NULL) 00369 continue; 00370 (void) CopyMagickMemory(indexes,nexus_indexes,(size_t) length* 00371 sizeof(*indexes)); 00372 indexes+=length; 00373 } 00374 } 00375 DestroyCacheNexus(cache_info,image_nexus); 00376 return(pixels); 00377 } 00378 00379 /* 00380 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00381 % % 00382 % % 00383 % % 00384 % A c q u i r e I m a g e P i x e l s % 00385 % % 00386 % % 00387 % % 00388 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00389 % 00390 % AcquireImagePixels() acquires pixels from the in-memory or disk pixel cache 00391 % as defined by the geometry parameters. A pointer to the pixel is returned 00392 % if the pixels are transferred, otherwise a NULL is returned. If you plan 00393 % to modify the pixels, use GetImagePixels() instead. 00394 % 00395 % The format of the AcquireImagePixels() method is: 00396 % 00397 % const PixelPacket *AcquireImagePixels(const Image *image,const long x, 00398 % const long y,const unsigned long columns,const unsigned long rows, 00399 % ExceptionInfo *exception) 00400 % 00401 % A description of each parameter follows: 00402 % 00403 % o image: The image. 00404 % 00405 % o x,y,columns,rows: These values define the perimeter of a region of 00406 % pixels. 00407 % 00408 % o exception: Return any errors or warnings in this structure. 00409 % 00410 % 00411 */ 00412 MagickExport const PixelPacket *AcquireImagePixels(const Image *image, 00413 const long x,const long y,const unsigned long columns, 00414 const unsigned long rows,ExceptionInfo *exception) 00415 { 00416 CacheInfo 00417 *cache_info; 00418 00419 const PixelPacket 00420 *pixels; 00421 00422 assert(image != (const Image *) NULL); 00423 assert(image->signature == MagickSignature); 00424 if (image->debug != MagickFalse) 00425 (void) LogMagickEvent(TraceEvent,GetMagickModule(),image->filename); 00426 assert(image->cache != (Cache) NULL); 00427 cache_info=(CacheInfo *) image->cache; 00428 assert(cache_info->signature == MagickSignature); 00429 if (cache_info->methods.acquire_pixel_handler == (AcquirePixelHandler) NULL) 00430 return((const PixelPacket *) NULL); 00431 pixels=cache_info->methods. 00432 acquire_pixel_handler(image,x,y,columns,rows,exception); 00433 return(pixels); 00434 } 00435 00436 /* 00437 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00438 % % 00439 % % 00440 % % 00441 + A c q u i r e P i x e l C a c h e % 00442 % % 00443 % % 00444 % % 00445 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00446 % 00447 % AcquirePixelCache() acquires pixels from the in-memory or disk pixel 00448 % cache as defined by the geometry parameters. A pointer to the pixels 00449 % is returned if the pixels are transferred, otherwise a NULL is returned. 00450 % 00451 % The format of the AcquirePixelCache() method is: 00452 % 00453 % const PixelPacket *AcquirePixelCache(const Image *image,const long x, 00454 % const long y,const unsigned long columns,const unsigned long rows, 00455 % ExceptionInfo *exception) 00456 % 00457 % A description of each parameter follows: 00458 % 00459 % o image: The image. 00460 % 00461 % o x,y,columns,rows: These values define the perimeter of a region of 00462 % pixels. 00463 % 00464 % o exception: Return any errors or warnings in this structure. 00465 % 00466 % 00467 */ 00468 static const PixelPacket *AcquirePixelCache(const Image *image,const long x, 00469 const long y,const unsigned long columns,const unsigned long rows, 00470 ExceptionInfo *exception) 00471 { 00472 if (image->debug != MagickFalse) 00473 (void) LogMagickEvent(TraceEvent,GetMagickModule(),image->filename); 00474 return(AcquireCacheNexus(image,x,y,columns,rows,0,exception)); 00475 } 00476 00477 /* 00478 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00479 % % 00480 % % 00481 % % 00482 % A c q u i r e O n e P i x e l % 00483 % % 00484 % % 00485 % % 00486 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00487 % 00488 % AcquireOnePixel() returns a single pixel at the specified (x,y) location. 00489 % The image background color is returned if an error occurs. If you plan to 00490 % modify the pixel, use GetOnePixel() instead. 00491 % 00492 % The format of the AcquireOnePixel() method is: 00493 % 00494 % PixelPacket AcquireOnePixel(const Image image,const long x, 00495 % const long y,ExceptionInfo exception) 00496 % 00497 % A description of each parameter follows: 00498 % 00499 % o pixels: AcquireOnePixel() returns a pixel at the specified (x,y) 00500 % location. 00501 % 00502 % o image: The image. 00503 % 00504 % o x,y: These values define the location of the pixel to return. 00505 % 00506 % o exception: Return any errors or warnings in this structure. 00507 % 00508 % 00509 */ 00510 MagickExport PixelPacket AcquireOnePixel(const Image *image,const long x, 00511 const long y,ExceptionInfo *exception) 00512 { 00513 CacheInfo 00514 *cache_info; 00515 00516 PixelPacket 00517 pixel; 00518 00519 assert(image != (const Image *) NULL); 00520 assert(image->signature == MagickSignature); 00521 assert(image->cache != (Cache) NULL); 00522 cache_info=(CacheInfo *) image->cache; 00523 assert(cache_info->signature == MagickSignature); 00524 if (cache_info->methods.acquire_one_pixel_from_handler == 00525 (AcquireOnePixelFromHandler) NULL) 00526 return(image->background_color); 00527 pixel=cache_info->methods.acquire_one_pixel_from_handler(image,x,y,exception); 00528 return(pixel); 00529 } 00530 00531 /* 00532 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00533 % % 00534 % % 00535 % % 00536 + A c q u i r e O n e P i x e l F r o m C a c h e % 00537 % % 00538 % % 00539 % % 00540 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00541 % 00542 % AcquireOnePixelFromCache() returns a single pixel at the specified (x,y) 00543 % location. The image background color is returned if an error occurs. 00544 % 00545 % The format of the AcquireOnePixelFromCache() method is: 00546 % 00547 % PixelPacket *AcquireOnePixelFromCache(const Image image,const long x, 00548 % const long y,ExceptionInfo *exception) 00549 % 00550 % A description of each parameter follows: 00551 % 00552 % o pixels: AcquireOnePixelFromCache returns a pixel at the specified (x,y) 00553 % location. 00554 % 00555 % o image: The image. 00556 % 00557 % o x,y: These values define the location of the pixel to return. 00558 % 00559 % o exception: Return any errors or warnings in this structure. 00560 % 00561 % 00562 */ 00563 static PixelPacket AcquireOnePixelFromCache(const Image *image,const long x, 00564 const long y,ExceptionInfo *exception) 00565 { 00566 register const PixelPacket 00567 *pixel; 00568 00569 assert(image != (Image *) NULL); 00570 assert(image->signature == MagickSignature); 00571 pixel=AcquirePixelCache(image,x,y,1UL,1UL,exception); 00572 if (pixel != (PixelPacket *) NULL) 00573 return(*pixel); 00574 return(image->background_color); 00575 } 00576 00577 /* 00578 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00579 % % 00580 % % 00581 % % 00582 + C l i p C a c h e N e x u s % 00583 % % 00584 % % 00585 % % 00586 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00587 % 00588 % ClipCacheNexus() clips the image pixels of the in-memory or disk cache as 00589 % defined by the image clip mask. The method returns MagickTrue if the pixel 00590 % region is clipped, otherwise MagickFalse. 00591 % 00592 % The format of the ClipCacheNexus() method is: 00593 % 00594 % MagickBooleanType ClipCacheNexus(Image *image,const unsigned long nexus) 00595 % 00596 % A description of each parameter follows: 00597 % 00598 % o image: The image. 00599 % 00600 % o nexus: specifies which cache nexus to clip. 00601 % 00602 % 00603 */ 00604 static MagickBooleanType ClipCacheNexus(Image *image,const unsigned long nexus) 00605 { 00606 CacheInfo 00607 *cache_info; 00608 00609 long 00610 y; 00611 00612 MagickBooleanType 00613 status; 00614 00615 NexusInfo 00616 *nexus_info; 00617 00618 register const PixelPacket 00619 *r; 00620 00621 register IndexPacket 00622 *nexus_indexes, 00623 *indexes; 00624 00625 register long 00626 x; 00627 00628 register PixelPacket 00629 *p, 00630 *q; 00631 00632 unsigned long 00633 image_nexus, 00634 mask_nexus; 00635 00636 /* 00637 Apply clip mask. 00638 */ 00639 assert(image != (Image *) NULL); 00640 assert(image->signature == MagickSignature); 00641 if (image->debug != MagickFalse) 00642 (void) LogMagickEvent(TraceEvent,GetMagickModule(),image->filename); 00643 image_nexus=GetNexus(image->cache); 00644 mask_nexus=GetNexus(image->clip_mask->cache); 00645 if ((image_nexus == 0) || (mask_nexus == 0)) 00646 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename); 00647 cache_info=(CacheInfo *) image->cache; 00648 nexus_info=cache_info->nexus_info+nexus; 00649 p=GetCacheNexus(image,nexus_info->x,nexus_info->y,nexus_info->columns, 00650 nexus_info->rows,image_nexus); 00651 indexes=GetNexusIndexes(image->cache,image_nexus); 00652 q=nexus_info->pixels; 00653 nexus_indexes=nexus_info->indexes; 00654 r=AcquireCacheNexus(image->clip_mask,nexus_info->x,nexus_info->y, 00655 nexus_info->columns,nexus_info->rows,mask_nexus,&image->exception); 00656 if ((p != (PixelPacket *) NULL) && (r != (const PixelPacket *) NULL)) 00657 for (y=0; y < (long) nexus_info->rows; y++) 00658 { 00659 for (x=0; x < (long) nexus_info->columns; x++) 00660 { 00661 if (PixelIntensityToQuantum(r) == TransparentOpacity) 00662 { 00663 q->red=p->red; 00664 q->green=p->green; 00665 q->blue=p->blue; 00666 q->opacity=p->opacity; 00667 if ((cache_info->storage_class == PseudoClass) || 00668 (cache_info->colorspace == CMYKColorspace)) 00669 *nexus_indexes=(*indexes); 00670 } 00671 if ((cache_info->storage_class == PseudoClass) || 00672 (cache_info->colorspace == CMYKColorspace)) 00673 { 00674 indexes++; 00675 nexus_indexes++; 00676 } 00677 p++; 00678 q++; 00679 r++; 00680 } 00681 } 00682 DestroyCacheNexus(image->cache,image_nexus); 00683 DestroyCacheNexus(image->clip_mask->cache,mask_nexus); 00684 status=(MagickBooleanType) ((p != (PixelPacket *) NULL) && 00685 (q != (PixelPacket *) NULL)); 00686 return(status); 00687 } 00688 00689 /* 00690 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00691 % % 00692 % % 00693 % % 00694 + C l o n e C a c h e N e x u s % 00695 % % 00696 % % 00697 % % 00698 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00699 % 00700 % CloneCacheNexus() clones the cache nexus from one cache to another. 00701 % 00702 % The format of the CloneCacheNexus() method is: 00703 % 00704 % MagickBooleanType CloneCacheNexus(Cache cache,const Cache clone, 00705 % const unsigned long nexus) 00706 % 00707 % A description of each parameter follows: 00708 % 00709 % o cache: Specifies a pointer to a Cache structure. 00710 % 00711 % o clone: Specifies a pointer to a Cache structure. 00712 % 00713 % o nexus: specifies which cache nexus to acquire. 00714 % 00715 % 00716 */ 00717 static MagickBooleanType CloneCacheNexus(Cache cache,const Cache clone, 00718 const unsigned long nexus) 00719 { 00720 CacheInfo 00721 *cache_info, 00722 *clone_info; 00723 00724 MagickSizeType 00725 number_pixels; 00726 00727 register long 00728 id; 00729 00730 register NexusInfo 00731 *p, 00732 *q; 00733 00734 cache_info=(CacheInfo *) cache; 00735 clone_info=(CacheInfo *) clone; 00736 clone_info->number_views=cache_info->number_views; 00737 clone_info->nexus_info=(NexusInfo *) ResizeMagickMemory( 00738 clone_info->nexus_info,(size_t) clone_info->number_views* 00739 sizeof(*clone_info->nexus_info)); 00740 if (clone_info->nexus_info == (NexusInfo *) NULL) 00741 ThrowMagickFatalException(ResourceLimitFatalError, 00742 "MemoryAllocationFailed",strerror(errno)); 00743 for (id=0; id < (long) cache_info->number_views; id++) 00744 { 00745 p=cache_info->nexus_info+id; 00746 q=clone_info->nexus_info+id; 00747 q->available=p->available; 00748 q->columns=p->columns; 00749 q->rows=p->rows; 00750 q->x=p->x; 00751 q->y=p->y; 00752 q->length=p->length; 00753 q->staging=p->staging; 00754 q->pixels=p->pixels; 00755 q->indexes=p->indexes; 00756 if (p->staging != (PixelPacket *) NULL) 00757 { 00758 q->staging=(PixelPacket *) AcquireMagickMemory((size_t) p->length); 00759 if (q->staging == (PixelPacket *) NULL) 00760 ThrowMagickFatalException(ResourceLimitFatalError, 00761 "MemoryAllocationFailed",strerror(errno)); 00762 (void) CopyMagickMemory(q->staging,p->staging,(size_t) p->length); 00763 q->pixels=q->staging; 00764 q->indexes=(IndexPacket *) NULL; 00765 number_pixels=(MagickSizeType) 00766 Max(q->columns*q->rows,cache_info->columns); 00767 if ((clone_info->storage_class == PseudoClass) || 00768 (clone_info->colorspace == CMYKColorspace)) 00769 q->indexes=(IndexPacket *) (q->pixels+number_pixels); 00770 } 00771 } 00772 if (nexus != 0) 00773 DestroyCacheNexus(cache,nexus); 00774 return(MagickTrue); 00775 } 00776 00777 /* 00778 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00779 % % 00780 % % 00781 % % 00782 + C l o n e P i x e l C a c h e % 00783 % % 00784 % % 00785 % % 00786 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % 00787 % ClonePixelCache() clones the pixel cache pixels from one cache to another. 00788 % 00789 % The format of the ClonePixelCache() method is: 00790 % 00791 % MagickBooleanType ClonePixelCache(Image *image,const Image *clone_image, 00792 % const unsigned long nexus) 00793 % 00794 % A description of each parameter follows: 00795 % 00796 % o image: The image. 00797 % 00798 % o clone_image: The cloned image. 00799 % 00800 % o nexus: specifies which cache nexus to acquire. 00801 % 00802 % 00803 */ 00804 00805 static inline MagickOffsetType ReadCacheRegion(int file,unsigned char *buffer, 00806 MagickSizeType length,MagickOffsetType offset) 00807 { 00808 register MagickOffsetType 00809 i; 00810 00811 ssize_t 00812 count; 00813 00814 #if !defined(HAVE_PREAD) 00815 if ((MagickSeek(file,offset,SEEK_SET)) < 0) 00816 return((MagickOffsetType) -1); 00817 #endif 00818 count=0; 00819 for (i=0; i < (MagickOffsetType) length; i+=count) 00820 { 00821 #if !defined(HAVE_PREAD) 00822 count=read(file,buffer+i,(size_t) Min(length-i,(MagickSizeType) 00823 MagickMaxBufferSize)); 00824 #else 00825 count=pread(file,buffer+i,(size_t) Min(length-i,(MagickSizeType) 00826 MagickMaxBufferSize),offset+i); 00827 #endif 00828 if (count > 0) 00829 continue; 00830 count=0; 00831 if (errno != EINTR) 00832 return((MagickOffsetType) -1); 00833 } 00834 return(i); 00835 } 00836 00837 static inline MagickOffsetType WriteCacheRegion(int file, 00838 const unsigned char *buffer,MagickSizeType length,MagickOffsetType offset) 00839 { 00840 register MagickOffsetType 00841 i; 00842 00843 ssize_t 00844 count; 00845 00846 #if !defined(HAVE_PWRITE) 00847 if ((MagickSeek(file,offset,SEEK_SET)) < 0) 00848 return((MagickOffsetType) -1); 00849 #endif 00850 count=0; 00851 for (i=0; i < (MagickOffsetType) length; i+=count) 00852 { 00853 #if !defined(HAVE_PWRITE) 00854 count=write(file,buffer+i,(size_t) Min(length-i,(MagickSizeType) 00855 MagickMaxBufferSize)); 00856 #else 00857 count=pwrite(file,buffer+i,(size_t) Min(length-i,(MagickSizeType) 00858 MagickMaxBufferSize),offset+i); 00859 #endif 00860 if (count > 0) 00861 continue; 00862 count=0; 00863 if (errno != EINTR) 00864 return((MagickOffsetType) -1); 00865 } 00866 return(i); 00867 } 00868 00869 static MagickBooleanType ClonePixelCache(Image *image,Image *clone_image, 00870 const unsigned long nexus) 00871 { 00872 CacheInfo 00873 *cache_info, 00874 *clone_info; 00875 00876 int 00877 cache_file, 00878 clone_file; 00879 00880 MagickOffsetType 00881 count; 00882 00883 MagickSizeType 00884 length; 00885 00886 register long 00887 i; 00888 00889 size_t 00890 packet_size; 00891 00892 unsigned char 00893 *buffer; 00894 00895 /* 00896 Clone cache nexus. 00897 */ 00898 if (CloneCacheNexus(image->cache,clone_image->cache,nexus) == MagickFalse) 00899 return(MagickFalse); 00900 cache_info=(CacheInfo *) image->cache; 00901 clone_info=(CacheInfo *) clone_image->cache; 00902 if (cache_info->length != clone_info->length) 00903 { 00904 Image 00905 *clip_mask; 00906 00907 long 00908 y; 00909 00910 register const PixelPacket 00911 *p; 00912 00913 register IndexPacket 00914 *clone_indexes, 00915 *indexes; 00916 00917 register PixelPacket 00918 *q; 00919 00920 /* 00921 Unoptimized pixel cache clone. 00922 */ 00923 if (image->debug != MagickFalse) 00924 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"unoptimized"); 00925 clip_mask=clone_image->clip_mask; 00926 clone_image->clip_mask=(Image *) NULL; 00927 length=(MagickSizeType) Min(image->columns,clone_image->columns); 00928 for (y=0; y < (long) image->rows; y++) 00929 { 00930 p=AcquireImagePixels(image,0,y,image->columns,1UL,&image->exception); 00931 q=SetImagePixels(clone_image,0,y,image->columns,1UL); 00932 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL)) 00933 break; 00934 (void) CopyMagickMemory(q,p,(size_t) length*sizeof(*q)); 00935 indexes=GetIndexes(image); 00936 clone_indexes=GetIndexes(clone_image); 00937 if ((indexes != (IndexPacket *) NULL) && 00938 (clone_indexes != (IndexPacket *) NULL)) 00939 (void) CopyMagickMemory(clone_indexes,indexes,(size_t) length* 00940 sizeof(*clone_indexes)); 00941 if (SyncImagePixels(clone_image) == MagickFalse) 00942 break; 00943 } 00944 clone_image->clip_mask=clip_mask; 00945 return((MagickBooleanType) (y == (long) image->rows)); 00946 } 00947 /* 00948 Optimized pixel cache clone. 00949 */ 00950 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache)) 00951 { 00952 if (image->debug != MagickFalse) 00953 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory"); 00954 (void) CopyMagickMemory(clone_info->pixels,cache_info->pixels, 00955 (size_t) cache_info->length); 00956 return(MagickTrue); 00957 } 00958 cache_file=cache_info->file; 00959 if (cache_info->type == DiskCache) 00960 { 00961 if (cache_info->file == -1) 00962 { 00963 cache_file=open(cache_info->cache_filename,O_RDONLY | O_BINARY); 00964 if (cache_file == -1) 00965 { 00966 ThrowFileException(&image->exception,FileOpenError, 00967 "UnableToOpenFile",cache_info->cache_filename); 00968 return(MagickFalse); 00969 } 00970 } 00971 if (clone_info->type != DiskCache) 00972 { 00973 if (image->debug != MagickFalse) 00974 (void) LogMagickEvent(CacheEvent,GetMagickModule(), 00975 "disk => memory"); 00976 count=ReadCacheRegion(cache_file,(unsigned char *) clone_info->pixels, 00977 cache_info->length,cache_info->offset); 00978 if (cache_info->file == -1) 00979 (void) close(cache_file); 00980 if ((MagickSizeType) count != cache_info->length) 00981 { 00982 ThrowFileException(&image->exception,CacheError, 00983 "UnableToCloneCache",image->filename); 00984 return(MagickFalse); 00985 } 00986 return(MagickTrue); 00987 } 00988 } 00989 clone_file=clone_info->file; 00990 if (clone_info->type == DiskCache) 00991 { 00992 if (clone_info->file == -1) 00993 { 00994 clone_file=open(clone_info->cache_filename,O_WRONLY | O_BINARY | 00995 O_EXCL,S_MODE); 00996 if (clone_file == -1) 00997 clone_file=open(clone_info->cache_filename,O_WRONLY | O_BINARY, 00998 S_MODE); 00999 if (clone_file == -1) 01000 { 01001 if (cache_info->file == -1) 01002 (void) close(cache_file); 01003 ThrowFileException(&image->exception,FileOpenError, 01004 "UnableToOpenFile",cache_info->cache_filename); 01005 return(MagickFalse); 01006 } 01007 } 01008 if (cache_info->type != DiskCache) 01009 { 01010 if (image->debug != MagickFalse) 01011 (void) LogMagickEvent(CacheEvent,GetMagickModule(), 01012 "memory => disk"); 01013 count=WriteCacheRegion(clone_file,(unsigned char *) 01014 cache_info->pixels,clone_info->length,clone_info->offset); 01015 if (clone_info->file == -1) 01016 (void) close(clone_file); 01017 if ((MagickSizeType) count != clone_info->length) 01018 { 01019 ThrowFileException(&image->exception,CacheError, 01020 "UnableToCloneCache",image->filename); 01021 return(MagickFalse); 01022 } 01023 return(MagickTrue); 01024 } 01025 } 01026 if (image->debug != MagickFalse) 01027 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk"); 01028 packet_size=sizeof(PixelPacket); 01029 if ((cache_info->storage_class == PseudoClass) || 01030 (cache_info->colorspace == CMYKColorspace)) 01031 packet_size+=sizeof(IndexPacket); 01032 length=packet_size*cache_info->columns*sizeof(*buffer); 01033 buffer=(unsigned char *) AcquireMagickMemory((size_t) length); 01034 if (buffer == (unsigned char *) NULL) 01035 { 01036 if (cache_info->file == -1) 01037 (void) close(cache_file); 01038 if (clone_info->file == -1) 01039 (void) close(clone_file); 01040 ThrowBinaryException(ResourceLimitFatalError,"MemoryAllocationFailed", 01041 image->filename); 01042 } 01043 for (i=0; i < (long) cache_info->rows; i++) 01044 { 01045 count=ReadCacheRegion(cache_file,buffer,length,cache_info->offset+i*length); 01046 if ((MagickSizeType) count != length) 01047 break; 01048 count=WriteCacheRegion(clone_file,buffer,length,clone_info->offset+ 01049 i*length); 01050 if ((MagickSizeType) count != length) 01051 break; 01052 } 01053 if (cache_info->file == -1) 01054 (void) close(cache_file); 01055 if (clone_info->file == -1) 01056 (void) close(clone_file); 01057 buffer=(unsigned char *) RelinquishMagickMemory(buffer); 01058 if (i < (long) cache_info->rows) 01059 { 01060 ThrowFileException(&image->exception,CacheError,"UnableToCloneCache", 01061 image->filename); 01062 return(MagickFalse); 01063 } 01064 return(MagickTrue); 01065 } 01066 01067 /* 01068 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01069 % % 01070 % % 01071 % % 01072 + C l o n e P i x e l C a c h e M e t h o d s % 01073 % % 01074 % % 01075 % % 01076 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01077 % 01078 % ClonePixelCacheMethods() clones the pixel cache methods from one cache to 01079 % another. 01080 % 01081 % The format of the ClonePixelCacheMethods() method is: 01082 % 01083 % void ClonePixelCacheMethods(Cache clone,const Cache cache) 01084 % 01085 % A description of each parameter follows: 01086 % 01087 % o clone: Specifies a pointer to a Cache structure. 01088 % 01089 % o cache: Specifies a pointer to a Cache structure. 01090 % 01091 % 01092 */ 01093 MagickExport void ClonePixelCacheMethods(Cache clone,const Cache cache) 01094 { 01095 CacheInfo 01096 *cache_info, 01097 *clone_info; 01098 01099 assert(clone != (Cache) NULL); 01100 clone_info=(CacheInfo *) clone; 01101 assert(clone_info->signature == MagickSignature); 01102 if (clone_info->debug != MagickFalse) 01103 (void) LogMagickEvent(TraceEvent,GetMagickModule(),clone_info->filename); 01104 assert(cache != (Cache) NULL); 01105 cache_info=(CacheInfo *) cache; 01106 assert(cache_info->signature == MagickSignature); 01107 clone_info->methods=cache_info->methods; 01108 } 01109 01110 /* 01111 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01112 % % 01113 % % 01114 % % 01115 % D e s t r o y C a c h e I n f o % 01116 % % 01117 % % 01118 % % 01119 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01120 % 01121 % DestroyCacheInfo() deallocates memory associated with the pixel cache. 01122 % 01123 % The format of the DestroyCacheInfo() method is: 01124 % 01125 % Cache DestroyCacheInfo(Cache cache) 01126 % 01127 % A description of each parameter follows: 01128 % 01129 % o cache: Specifies a pointer to a Cache structure. 01130 % 01131 % 01132 */ 01133 01134 static inline void RelinquishCachePixels(CacheInfo *cache_info) 01135 { 01136 assert(cache_info != (CacheInfo *) NULL); 01137 assert(cache_info->length == (MagickSizeType) ((size_t) cache_info->length)); 01138 if (cache_info->mapped == MagickFalse) 01139 { 01140 cache_info->pixels=(PixelPacket *) 01141 RelinquishMagickMemory(cache_info->pixels); 01142 return; 01143 } 01144 (void) UnmapBlob(cache_info->pixels,(size_t) cache_info->length); 01145 cache_info->pixels=(PixelPacket *) NULL; 01146 } 01147 01148 MagickExport Cache DestroyCacheInfo(Cache cache) 01149 { 01150 char 01151 message[MaxTextExtent]; 01152 01153 CacheInfo 01154 *cache_info; 01155 01156 assert(cache != (Cache) NULL); 01157 cache_info=(CacheInfo *) cache; 01158 assert(cache_info->signature == MagickSignature); 01159 if (cache_info->debug != MagickFalse) 01160 (void) LogMagickEvent(TraceEvent,GetMagickModule(),cache_info->filename); 01161 cache_info->semaphore=AcquireSemaphoreInfo(cache_info->semaphore); 01162 cache_info->reference_count--; 01163 if (cache_info->reference_count > 0) 01164 { 01165 RelinquishSemaphoreInfo(cache_info->semaphore); 01166 return((Cache) NULL); 01167 } 01168 switch (cache_info->type) 01169 { 01170 default: 01171 { 01172 if (cache_info->pixels == (PixelPacket *) NULL) 01173 break; 01174 } 01175 case MemoryCache: 01176 { 01177 RelinquishCachePixels(cache_info); 01178 RelinquishMagickResource(MemoryResource,cache_info->length); 01179 break; 01180 } 01181 case MapCache: 01182 { 01183 (void) UnmapBlob(cache_info->pixels,(size_t) cache_info->length); 01184 RelinquishMagickResource(MapResource,cache_info->length); 01185 } 01186 case DiskCache: 01187 { 01188 if (cache_info->file != -1) 01189 (void) close(cache_info->file); 01190 cache_info->file=(-1); 01191 (void) RelinquishUniqueFileResource(cache_info->cache_filename); 01192 RelinquishMagickResource(DiskResource,cache_info->length); 01193 break; 01194 } 01195 } 01196 RelinquishMagickResource(AreaResource,cache_info->length); 01197 if (cache_info->type != UndefinedCache) 01198 { 01199 register long 01200 id; 01201 01202 for (id=0; id < (long) cache_info->number_views; id++) 01203 DestroyCacheNexus(cache,(unsigned long) id); 01204 cache_info->nexus_info=(NexusInfo *) 01205 RelinquishMagickMemory(cache_info->nexus_info); 01206 } 01207 (void) FormatMagickString(message,MaxTextExtent,"destroy %s", 01208 cache_info->filename); 01209 if (cache_info->debug != MagickFalse) 01210 (void) LogMagickEvent(CacheEvent,GetMagickModule(),message); 01211 RelinquishSemaphoreInfo(cache_info->semaphore); 01212 cache_info->semaphore=DestroySemaphoreInfo(cache_info->semaphore); 01213 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info); 01214 cache=(Cache) NULL; 01215 return(cache); 01216 } 01217 01218 /* 01219 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01220 % % 01221 % % 01222 % % 01223 + D e s t r o y C a c h e N e x u s % 01224 % % 01225 % % 01226 % % 01227 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01228 % 01229 % DestroyCacheNexus() destroys a cache nexus. 01230 % 01231 % The format of the DestroyCacheNexus() method is: 01232 % 01233 % void DestroyCacheNexus(Cache cache,const unsigned long nexus) 01234 % 01235 % A description of each parameter follows: 01236 % 01237 % o cache: Specifies a pointer to a Cache structure. 01238 % 01239 % o nexus: specifies which cache nexus to destroy. 01240 % 01241 % 01242 */ 01243 MagickExport void DestroyCacheNexus(Cache cache,const unsigned long nexus) 01244 { 01245 CacheInfo 01246 *cache_info; 01247 01248 register NexusInfo 01249 *nexus_info; 01250 01251 assert(cache != (Cache) NULL); 01252 cache_info=(CacheInfo *) cache; 01253 assert(cache_info->signature == MagickSignature); 01254 if (cache_info->debug != MagickFalse) 01255 (void) LogMagickEvent(TraceEvent,GetMagickModule(),cache_info->filename); 01256 nexus_info=cache_info->nexus_info+nexus; 01257 if (nexus_info->staging != (PixelPacket *) NULL) 01258 nexus_info->staging=(PixelPacket *) 01259 RelinquishMagickMemory(nexus_info->staging); 01260 (void) ResetMagickMemory(nexus_info,0,sizeof(*nexus_info)); 01261 nexus_info->available=MagickTrue; 01262 } 01263 01264 /* 01265 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01266 % % 01267 % % 01268 % % 01269 % D e s t r o y I m a g e P i x e l s % 01270 % % 01271 % % 01272 % % 01273 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01274 % 01275 % DestroyImagePixels() deallocates memory associated with the pixel cache. 01276 % 01277 % The format of the DestroyImagePixels() method is: 01278 % 01279 % void DestroyImagePixels(Image *image) 01280 % 01281 % A description of each parameter follows: 01282 <