|
MagickCore
6.7.5
|
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-2012 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 "MagickCore/studio.h" 00044 #include "MagickCore/blob.h" 00045 #include "MagickCore/blob-private.h" 00046 #include "MagickCore/cache.h" 00047 #include "MagickCore/cache-private.h" 00048 #include "MagickCore/color-private.h" 00049 #include "MagickCore/composite-private.h" 00050 #include "MagickCore/exception.h" 00051 #include "MagickCore/exception-private.h" 00052 #include "MagickCore/geometry.h" 00053 #include "MagickCore/list.h" 00054 #include "MagickCore/log.h" 00055 #include "MagickCore/magick.h" 00056 #include "MagickCore/memory_.h" 00057 #include "MagickCore/pixel.h" 00058 #include "MagickCore/pixel-accessor.h" 00059 #include "MagickCore/policy.h" 00060 #include "MagickCore/quantum.h" 00061 #include "MagickCore/random_.h" 00062 #include "MagickCore/resource_.h" 00063 #include "MagickCore/semaphore.h" 00064 #include "MagickCore/splay-tree.h" 00065 #include "MagickCore/string_.h" 00066 #include "MagickCore/string-private.h" 00067 #include "MagickCore/thread-private.h" 00068 #include "MagickCore/utility.h" 00069 #include "MagickCore/utility-private.h" 00070 #if defined(MAGICKCORE_ZLIB_DELEGATE) 00071 #include "zlib.h" 00072 #endif 00073 00074 /* 00075 Define declarations. 00076 */ 00077 #define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent) 00078 #define IsFileDescriptorLimitExceeded() (GetMagickResource(FileResource) > \ 00079 GetMagickResourceLimit(FileResource) ? MagickTrue : MagickFalse) 00080 00081 /* 00082 Typedef declarations. 00083 */ 00084 typedef struct _MagickModulo 00085 { 00086 ssize_t 00087 quotient, 00088 remainder; 00089 } MagickModulo; 00090 00091 struct _NexusInfo 00092 { 00093 MagickBooleanType 00094 mapped; 00095 00096 RectangleInfo 00097 region; 00098 00099 MagickSizeType 00100 length; 00101 00102 Quantum 00103 *cache, 00104 *pixels; 00105 00106 void 00107 *metacontent; 00108 00109 size_t 00110 signature; 00111 }; 00112 00113 /* 00114 Forward declarations. 00115 */ 00116 #if defined(__cplusplus) || defined(c_plusplus) 00117 extern "C" { 00118 #endif 00119 00120 static const Quantum 00121 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t, 00122 const ssize_t,const size_t,const size_t,ExceptionInfo *), 00123 *GetVirtualPixelsCache(const Image *); 00124 00125 static const void 00126 *GetVirtualMetacontentFromCache(const Image *); 00127 00128 static MagickBooleanType 00129 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t, 00130 Quantum *,ExceptionInfo *), 00131 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod, 00132 const ssize_t,const ssize_t,Quantum *,ExceptionInfo *), 00133 OpenPixelCache(Image *,const MapMode,ExceptionInfo *), 00134 ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *), 00135 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *), 00136 SyncAuthenticPixelsCache(Image *,ExceptionInfo *), 00137 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *), 00138 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *); 00139 00140 static Quantum 00141 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t, 00142 const size_t,ExceptionInfo *), 00143 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t, 00144 const size_t,ExceptionInfo *), 00145 *SetPixelCacheNexusPixels(const Image *,const RectangleInfo *,NexusInfo *, 00146 ExceptionInfo *); 00147 00148 #if defined(__cplusplus) || defined(c_plusplus) 00149 } 00150 #endif 00151 00152 /* 00153 Global declarations. 00154 */ 00155 static volatile MagickBooleanType 00156 instantiate_cache = MagickFalse; 00157 00158 static SemaphoreInfo 00159 *cache_semaphore = (SemaphoreInfo *) NULL; 00160 00161 /* 00162 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00163 % % 00164 % % 00165 % % 00166 + A c q u i r e P i x e l C a c h e % 00167 % % 00168 % % 00169 % % 00170 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00171 % 00172 % AcquirePixelCache() acquires a pixel cache. 00173 % 00174 % The format of the AcquirePixelCache() method is: 00175 % 00176 % Cache AcquirePixelCache(const size_t number_threads) 00177 % 00178 % A description of each parameter follows: 00179 % 00180 % o number_threads: the number of nexus threads. 00181 % 00182 */ 00183 MagickPrivate Cache AcquirePixelCache(const size_t number_threads) 00184 { 00185 CacheInfo 00186 *cache_info; 00187 00188 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info)); 00189 if (cache_info == (CacheInfo *) NULL) 00190 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 00191 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info)); 00192 cache_info->type=UndefinedCache; 00193 cache_info->mode=IOMode; 00194 cache_info->colorspace=RGBColorspace; 00195 cache_info->file=(-1); 00196 cache_info->id=GetMagickThreadId(); 00197 cache_info->number_threads=number_threads; 00198 if (number_threads == 0) 00199 cache_info->number_threads=GetOpenMPMaximumThreads(); 00200 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads); 00201 if (cache_info->nexus_info == (NexusInfo **) NULL) 00202 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 00203 cache_info->semaphore=AllocateSemaphoreInfo(); 00204 cache_info->reference_count=1; 00205 cache_info->disk_semaphore=AllocateSemaphoreInfo(); 00206 cache_info->debug=IsEventLogging(); 00207 cache_info->signature=MagickSignature; 00208 return((Cache ) cache_info); 00209 } 00210 00211 /* 00212 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00213 % % 00214 % % 00215 % % 00216 % A c q u i r e P i x e l C a c h e N e x u s % 00217 % % 00218 % % 00219 % % 00220 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00221 % 00222 % AcquirePixelCacheNexus() allocates the NexusInfo structure. 00223 % 00224 % The format of the AcquirePixelCacheNexus method is: 00225 % 00226 % NexusInfo **AcquirePixelCacheNexus(const size_t number_threads) 00227 % 00228 % A description of each parameter follows: 00229 % 00230 % o number_threads: the number of nexus threads. 00231 % 00232 */ 00233 MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads) 00234 { 00235 NexusInfo 00236 **nexus_info; 00237 00238 register ssize_t 00239 i; 00240 00241 nexus_info=(NexusInfo **) AcquireQuantumMemory(number_threads, 00242 sizeof(*nexus_info)); 00243 if (nexus_info == (NexusInfo **) NULL) 00244 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 00245 for (i=0; i < (ssize_t) number_threads; i++) 00246 { 00247 nexus_info[i]=(NexusInfo *) AcquireQuantumMemory(1,sizeof(**nexus_info)); 00248 if (nexus_info[i] == (NexusInfo *) NULL) 00249 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 00250 (void) ResetMagickMemory(nexus_info[i],0,sizeof(*nexus_info[i])); 00251 nexus_info[i]->signature=MagickSignature; 00252 } 00253 return(nexus_info); 00254 } 00255 00256 /* 00257 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00258 % % 00259 % % 00260 % % 00261 + A c q u i r e P i x e l C a c h e P i x e l s % 00262 % % 00263 % % 00264 % % 00265 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00266 % 00267 % AcquirePixelCachePixels() returns the pixels associated with the specified 00268 % image. 00269 % 00270 % The format of the AcquirePixelCachePixels() method is: 00271 % 00272 % const void *AcquirePixelCachePixels(const Image *image, 00273 % MagickSizeType *length,ExceptionInfo *exception) 00274 % 00275 % A description of each parameter follows: 00276 % 00277 % o image: the image. 00278 % 00279 % o length: the pixel cache length. 00280 % 00281 % o exception: return any errors or warnings in this structure. 00282 % 00283 */ 00284 MagickPrivate const void *AcquirePixelCachePixels(const Image *image, 00285 MagickSizeType *length,ExceptionInfo *exception) 00286 { 00287 CacheInfo 00288 *cache_info; 00289 00290 assert(image != (const Image *) NULL); 00291 assert(image->signature == MagickSignature); 00292 assert(exception != (ExceptionInfo *) NULL); 00293 assert(exception->signature == MagickSignature); 00294 assert(image->cache != (Cache) NULL); 00295 cache_info=(CacheInfo *) image->cache; 00296 assert(cache_info->signature == MagickSignature); 00297 *length=0; 00298 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache)) 00299 return((const void *) NULL); 00300 *length=cache_info->length; 00301 return((const void *) cache_info->pixels); 00302 } 00303 00304 /* 00305 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00306 % % 00307 % % 00308 % % 00309 + C a c h e C o m p o n e n t G e n e s i s % 00310 % % 00311 % % 00312 % % 00313 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00314 % 00315 % CacheComponentGenesis() instantiates the cache component. 00316 % 00317 % The format of the CacheComponentGenesis method is: 00318 % 00319 % MagickBooleanType CacheComponentGenesis(void) 00320 % 00321 */ 00322 MagickPrivate MagickBooleanType CacheComponentGenesis(void) 00323 { 00324 AcquireSemaphoreInfo(&cache_semaphore); 00325 return(MagickTrue); 00326 } 00327 00328 /* 00329 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00330 % % 00331 % % 00332 % % 00333 + C a c h e C o m p o n e n t T e r m i n u s % 00334 % % 00335 % % 00336 % % 00337 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00338 % 00339 % CacheComponentTerminus() destroys the cache component. 00340 % 00341 % The format of the CacheComponentTerminus() method is: 00342 % 00343 % CacheComponentTerminus(void) 00344 % 00345 */ 00346 MagickPrivate void CacheComponentTerminus(void) 00347 { 00348 if (cache_semaphore == (SemaphoreInfo *) NULL) 00349 AcquireSemaphoreInfo(&cache_semaphore); 00350 LockSemaphoreInfo(cache_semaphore); 00351 instantiate_cache=MagickFalse; 00352 UnlockSemaphoreInfo(cache_semaphore); 00353 DestroySemaphoreInfo(&cache_semaphore); 00354 } 00355 00356 /* 00357 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00358 % % 00359 % % 00360 % % 00361 + C l o n e P i x e l C a c h e % 00362 % % 00363 % % 00364 % % 00365 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00366 % 00367 % ClonePixelCache() clones a pixel cache. 00368 % 00369 % The format of the ClonePixelCache() method is: 00370 % 00371 % Cache ClonePixelCache(const Cache cache) 00372 % 00373 % A description of each parameter follows: 00374 % 00375 % o cache: the pixel cache. 00376 % 00377 */ 00378 MagickPrivate Cache ClonePixelCache(const Cache cache) 00379 { 00380 CacheInfo 00381 *clone_info; 00382 00383 const CacheInfo 00384 *cache_info; 00385 00386 assert(cache != NULL); 00387 cache_info=(const CacheInfo *) cache; 00388 assert(cache_info->signature == MagickSignature); 00389 if (cache_info->debug != MagickFalse) 00390 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 00391 cache_info->filename); 00392 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads); 00393 if (clone_info == (Cache) NULL) 00394 return((Cache) NULL); 00395 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method; 00396 return((Cache ) clone_info); 00397 } 00398 00399 /* 00400 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00401 % % 00402 % % 00403 % % 00404 + C l o n e P i x e l C a c h e P i x e l s % 00405 % % 00406 % % 00407 % % 00408 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % 00409 % ClonePixelCachePixels() clones the source pixel cache to the destination 00410 % cache. 00411 % 00412 % The format of the ClonePixelCachePixels() method is: 00413 % 00414 % MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info, 00415 % CacheInfo *source_info,ExceptionInfo *exception) 00416 % 00417 % A description of each parameter follows: 00418 % 00419 % o cache_info: the pixel cache. 00420 % 00421 % o source_info: the source pixel cache. 00422 % 00423 % o exception: return any errors or warnings in this structure. 00424 % 00425 */ 00426 00427 static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info) 00428 { 00429 int 00430 status; 00431 00432 status=(-1); 00433 LockSemaphoreInfo(cache_info->disk_semaphore); 00434 if (cache_info->file != -1) 00435 { 00436 status=close(cache_info->file); 00437 cache_info->file=(-1); 00438 RelinquishMagickResource(FileResource,1); 00439 } 00440 UnlockSemaphoreInfo(cache_info->disk_semaphore); 00441 return(status == -1 ? MagickFalse : MagickTrue); 00442 } 00443 00444 static inline MagickSizeType MagickMax(const MagickSizeType x, 00445 const MagickSizeType y) 00446 { 00447 if (x > y) 00448 return(x); 00449 return(y); 00450 } 00451 00452 static inline MagickSizeType MagickMin(const MagickSizeType x, 00453 const MagickSizeType y) 00454 { 00455 if (x < y) 00456 return(x); 00457 return(y); 00458 } 00459 00460 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info, 00461 const MapMode mode) 00462 { 00463 int 00464 file; 00465 00466 /* 00467 Open pixel cache on disk. 00468 */ 00469 LockSemaphoreInfo(cache_info->disk_semaphore); 00470 if (cache_info->file != -1) 00471 { 00472 UnlockSemaphoreInfo(cache_info->disk_semaphore); 00473 return(MagickTrue); /* cache already open */ 00474 } 00475 if (*cache_info->cache_filename == '\0') 00476 file=AcquireUniqueFileResource(cache_info->cache_filename); 00477 else 00478 switch (mode) 00479 { 00480 case ReadMode: 00481 { 00482 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0); 00483 break; 00484 } 00485 case WriteMode: 00486 { 00487 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT | 00488 O_BINARY | O_EXCL,S_MODE); 00489 if (file == -1) 00490 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE); 00491 break; 00492 } 00493 case IOMode: 00494 default: 00495 { 00496 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY | 00497 O_EXCL,S_MODE); 00498 if (file == -1) 00499 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE); 00500 break; 00501 } 00502 } 00503 if (file == -1) 00504 { 00505 UnlockSemaphoreInfo(cache_info->disk_semaphore); 00506 return(MagickFalse); 00507 } 00508 (void) AcquireMagickResource(FileResource,1); 00509 cache_info->file=file; 00510 cache_info->mode=mode; 00511 cache_info->timestamp=time(0); 00512 UnlockSemaphoreInfo(cache_info->disk_semaphore); 00513 return(MagickTrue); 00514 } 00515 00516 static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info, 00517 const MagickOffsetType offset,const MagickSizeType length, 00518 unsigned char *restrict buffer) 00519 { 00520 register MagickOffsetType 00521 i; 00522 00523 ssize_t 00524 count; 00525 00526 cache_info->timestamp=time(0); 00527 #if !defined(MAGICKCORE_HAVE_PREAD) 00528 LockSemaphoreInfo(cache_info->disk_semaphore); 00529 if (lseek(cache_info->file,offset,SEEK_SET) < 0) 00530 { 00531 UnlockSemaphoreInfo(cache_info->disk_semaphore); 00532 return((MagickOffsetType) -1); 00533 } 00534 #endif 00535 count=0; 00536 for (i=0; i < (MagickOffsetType) length; i+=count) 00537 { 00538 #if !defined(MAGICKCORE_HAVE_PREAD) 00539 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i, 00540 (MagickSizeType) SSIZE_MAX)); 00541 #else 00542 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i, 00543 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i)); 00544 #endif 00545 if (count > 0) 00546 continue; 00547 count=0; 00548 if (errno != EINTR) 00549 { 00550 i=(-1); 00551 break; 00552 } 00553 } 00554 #if !defined(MAGICKCORE_HAVE_PREAD) 00555 UnlockSemaphoreInfo(cache_info->disk_semaphore); 00556 #endif 00557 return(i); 00558 } 00559 00560 static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info, 00561 const MagickOffsetType offset,const MagickSizeType length, 00562 const unsigned char *restrict buffer) 00563 { 00564 register MagickOffsetType 00565 i; 00566 00567 ssize_t 00568 count; 00569 00570 cache_info->timestamp=time(0); 00571 #if !defined(MAGICKCORE_HAVE_PWRITE) 00572 LockSemaphoreInfo(cache_info->disk_semaphore); 00573 if (lseek(cache_info->file,offset,SEEK_SET) < 0) 00574 { 00575 UnlockSemaphoreInfo(cache_info->disk_semaphore); 00576 return((MagickOffsetType) -1); 00577 } 00578 #endif 00579 count=0; 00580 for (i=0; i < (MagickOffsetType) length; i+=count) 00581 { 00582 #if !defined(MAGICKCORE_HAVE_PWRITE) 00583 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i, 00584 (MagickSizeType) SSIZE_MAX)); 00585 #else 00586 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i, 00587 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i)); 00588 #endif 00589 if (count > 0) 00590 continue; 00591 count=0; 00592 if (errno != EINTR) 00593 { 00594 i=(-1); 00595 break; 00596 } 00597 } 00598 #if !defined(MAGICKCORE_HAVE_PWRITE) 00599 UnlockSemaphoreInfo(cache_info->disk_semaphore); 00600 #endif 00601 return(i); 00602 } 00603 00604 static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info, 00605 CacheInfo *cache_info,ExceptionInfo *exception) 00606 { 00607 MagickOffsetType 00608 count; 00609 00610 register MagickOffsetType 00611 i; 00612 00613 size_t 00614 length; 00615 00616 unsigned char 00617 *blob; 00618 00619 /* 00620 Clone pixel cache (both caches on disk). 00621 */ 00622 if (cache_info->debug != MagickFalse) 00623 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk"); 00624 blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent, 00625 sizeof(*blob)); 00626 if (blob == (unsigned char *) NULL) 00627 { 00628 (void) ThrowMagickException(exception,GetMagickModule(), 00629 ResourceLimitError,"MemoryAllocationFailed","`%s'", 00630 cache_info->filename); 00631 return(MagickFalse); 00632 } 00633 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse) 00634 { 00635 blob=(unsigned char *) RelinquishMagickMemory(blob); 00636 ThrowFileException(exception,FileOpenError,"UnableToOpenFile", 00637 cache_info->cache_filename); 00638 return(MagickFalse); 00639 } 00640 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse) 00641 { 00642 (void) ClosePixelCacheOnDisk(cache_info); 00643 blob=(unsigned char *) RelinquishMagickMemory(blob); 00644 ThrowFileException(exception,FileOpenError,"UnableToOpenFile", 00645 clone_info->cache_filename); 00646 return(MagickFalse); 00647 } 00648 count=0; 00649 for (i=0; i < (MagickOffsetType) cache_info->length; i+=count) 00650 { 00651 count=ReadPixelCacheRegion(cache_info,cache_info->offset+i, 00652 MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent), 00653 blob); 00654 if (count <= 0) 00655 { 00656 ThrowFileException(exception,CacheError,"UnableToReadPixelCache", 00657 cache_info->cache_filename); 00658 break; 00659 } 00660 length=(size_t) count; 00661 count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob); 00662 if ((MagickSizeType) count != length) 00663 { 00664 ThrowFileException(exception,CacheError,"UnableToWritePixelCache", 00665 clone_info->cache_filename); 00666 break; 00667 } 00668 } 00669 (void) ClosePixelCacheOnDisk(clone_info); 00670 (void) ClosePixelCacheOnDisk(cache_info); 00671 blob=(unsigned char *) RelinquishMagickMemory(blob); 00672 if (i < (MagickOffsetType) cache_info->length) 00673 return(MagickFalse); 00674 return(MagickTrue); 00675 } 00676 00677 static MagickBooleanType PixelCacheCloneOptimized(CacheInfo *clone_info, 00678 CacheInfo *cache_info,ExceptionInfo *exception) 00679 { 00680 MagickOffsetType 00681 count; 00682 00683 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache)) 00684 { 00685 /* 00686 Clone pixel cache (both caches in memory). 00687 */ 00688 if (cache_info->debug != MagickFalse) 00689 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory"); 00690 (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t) 00691 cache_info->length); 00692 return(MagickTrue); 00693 } 00694 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache)) 00695 { 00696 /* 00697 Clone pixel cache (one cache on disk, one in memory). 00698 */ 00699 if (cache_info->debug != MagickFalse) 00700 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory"); 00701 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse) 00702 { 00703 ThrowFileException(exception,FileOpenError,"UnableToOpenFile", 00704 cache_info->cache_filename); 00705 return(MagickFalse); 00706 } 00707 count=ReadPixelCacheRegion(cache_info,cache_info->offset, 00708 cache_info->length,(unsigned char *) clone_info->pixels); 00709 (void) ClosePixelCacheOnDisk(cache_info); 00710 if ((MagickSizeType) count != cache_info->length) 00711 { 00712 ThrowFileException(exception,CacheError,"UnableToReadPixelCache", 00713 cache_info->cache_filename); 00714 return(MagickFalse); 00715 } 00716 return(MagickTrue); 00717 } 00718 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache)) 00719 { 00720 /* 00721 Clone pixel cache (one cache on disk, one in memory). 00722 */ 00723 if (clone_info->debug != MagickFalse) 00724 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk"); 00725 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse) 00726 { 00727 ThrowFileException(exception,FileOpenError,"UnableToOpenFile", 00728 clone_info->cache_filename); 00729 return(MagickFalse); 00730 } 00731 count=WritePixelCacheRegion(clone_info,clone_info->offset, 00732 clone_info->length,(unsigned char *) cache_info->pixels); 00733 (void) ClosePixelCacheOnDisk(clone_info); 00734 if ((MagickSizeType) count != clone_info->length) 00735 { 00736 ThrowFileException(exception,CacheError,"UnableToWritePixelCache", 00737 clone_info->cache_filename); 00738 return(MagickFalse); 00739 } 00740 return(MagickTrue); 00741 } 00742 /* 00743 Clone pixel cache (both caches on disk). 00744 */ 00745 return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception)); 00746 } 00747 00748 static MagickBooleanType PixelCacheCloneUnoptimized(CacheInfo *clone_info, 00749 CacheInfo *cache_info,ExceptionInfo *exception) 00750 { 00751 MagickBooleanType 00752 status; 00753 00754 MagickOffsetType 00755 cache_offset, 00756 clone_offset, 00757 count; 00758 00759 register ssize_t 00760 x; 00761 00762 register unsigned char 00763 *p; 00764 00765 size_t 00766 length; 00767 00768 ssize_t 00769 y; 00770 00771 unsigned char 00772 *blob; 00773 00774 /* 00775 Clone pixel cache (unoptimized). 00776 */ 00777 if (cache_info->debug != MagickFalse) 00778 { 00779 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache)) 00780 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory"); 00781 else 00782 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache)) 00783 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory"); 00784 else 00785 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache)) 00786 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk"); 00787 else 00788 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk"); 00789 } 00790 length=(size_t) MagickMax(MagickMax(cache_info->number_channels, 00791 clone_info->number_channels)*sizeof(Quantum),MagickMax( 00792 cache_info->metacontent_extent,clone_info->metacontent_extent)); 00793 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob)); 00794 if (blob == (unsigned char *) NULL) 00795 { 00796 (void) ThrowMagickException(exception,GetMagickModule(), 00797 ResourceLimitError,"MemoryAllocationFailed","`%s'", 00798 cache_info->filename); 00799 return(MagickFalse); 00800 } 00801 (void) ResetMagickMemory(blob,0,length*sizeof(*blob)); 00802 cache_offset=0; 00803 clone_offset=0; 00804 if (cache_info->type == DiskCache) 00805 { 00806 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse) 00807 { 00808 blob=(unsigned char *) RelinquishMagickMemory(blob); 00809 ThrowFileException(exception,FileOpenError,"UnableToOpenFile", 00810 cache_info->cache_filename); 00811 return(MagickFalse); 00812 } 00813 cache_offset=cache_info->offset; 00814 } 00815 if (clone_info->type == DiskCache) 00816 { 00817 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse) 00818 { 00819 blob=(unsigned char *) RelinquishMagickMemory(blob); 00820 ThrowFileException(exception,FileOpenError,"UnableToOpenFile", 00821 clone_info->cache_filename); 00822 return(MagickFalse); 00823 } 00824 clone_offset=clone_info->offset; 00825 } 00826 /* 00827 Clone pixel channels. 00828 */ 00829 status=MagickTrue; 00830 p=blob; 00831 for (y=0; y < (ssize_t) cache_info->rows; y++) 00832 { 00833 for (x=0; x < (ssize_t) cache_info->columns; x++) 00834 { 00835 register ssize_t 00836 i; 00837 00838 /* 00839 Read a set of pixel channels. 00840 */ 00841 length=cache_info->number_channels*sizeof(Quantum); 00842 if (cache_info->type != DiskCache) 00843 p=(unsigned char *) cache_info->pixels+cache_offset; 00844 else 00845 { 00846 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p); 00847 if ((MagickSizeType) count != length) 00848 { 00849 status=MagickFalse; 00850 break; 00851 } 00852 } 00853 cache_offset+=length; 00854 if ((y < (ssize_t) clone_info->rows) && 00855 (x < (ssize_t) clone_info->columns)) 00856 for (i=0; i < (ssize_t) clone_info->number_channels; i++) 00857 { 00858 PixelChannel 00859 channel; 00860 00861 PixelTrait 00862 traits; 00863 00864 ssize_t 00865 offset; 00866 00867 /* 00868 Write a set of pixel channels. 00869 */ 00870 channel=clone_info->channel_map[i].channel; 00871 traits=cache_info->channel_map[channel].traits; 00872 if (traits == UndefinedPixelTrait) 00873 { 00874 clone_offset+=sizeof(Quantum); 00875 continue; 00876 } 00877 offset=cache_info->channel_map[channel].offset; 00878 if (clone_info->type != DiskCache) 00879 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,p+ 00880 offset*sizeof(Quantum),sizeof(Quantum)); 00881 else 00882 { 00883 count=WritePixelCacheRegion(clone_info,clone_offset, 00884 sizeof(Quantum),p+offset*sizeof(Quantum)); 00885 if ((MagickSizeType) count != sizeof(Quantum)) 00886 { 00887 status=MagickFalse; 00888 break; 00889 } 00890 } 00891 clone_offset+=sizeof(Quantum); 00892 } 00893 } 00894 length=clone_info->number_channels*sizeof(Quantum); 00895 (void) ResetMagickMemory(blob,0,length*sizeof(*blob)); 00896 for ( ; x < (ssize_t) clone_info->columns; x++) 00897 { 00898 /* 00899 Set remaining columns as undefined. 00900 */ 00901 if (clone_info->type != DiskCache) 00902 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob, 00903 length); 00904 else 00905 { 00906 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob); 00907 if ((MagickSizeType) count != length) 00908 { 00909 status=MagickFalse; 00910 break; 00911 } 00912 } 00913 clone_offset+=length; 00914 } 00915 } 00916 length=clone_info->number_channels*sizeof(Quantum); 00917 (void) ResetMagickMemory(blob,0,length*sizeof(*blob)); 00918 for ( ; y < (ssize_t) clone_info->rows; y++) 00919 { 00920 /* 00921 Set remaining rows as undefined. 00922 */ 00923 for (x=0; x < (ssize_t) clone_info->columns; x++) 00924 { 00925 if (clone_info->type != DiskCache) 00926 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob, 00927 length); 00928 else 00929 { 00930 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob); 00931 if ((MagickSizeType) count != length) 00932 { 00933 status=MagickFalse; 00934 break; 00935 } 00936 } 00937 clone_offset+=length; 00938 } 00939 } 00940 if ((cache_info->metacontent_extent != 0) || 00941 (clone_info->metacontent_extent != 0)) 00942 { 00943 /* 00944 Clone metacontent. 00945 */ 00946 for (y=0; y < (ssize_t) cache_info->rows; y++) 00947 { 00948 for (x=0; x < (ssize_t) cache_info->columns; x++) 00949 { 00950 /* 00951 Read a set of metacontent. 00952 */ 00953 length=cache_info->metacontent_extent; 00954 if (cache_info->type != DiskCache) 00955 p=(unsigned char *) cache_info->pixels+cache_offset; 00956 else 00957 { 00958 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p); 00959 if ((MagickSizeType) count != length) 00960 { 00961 status=MagickFalse; 00962 break; 00963 } 00964 } 00965 cache_offset+=length; 00966 if ((y < (ssize_t) clone_info->rows) && 00967 (x < (ssize_t) clone_info->columns)) 00968 { 00969 /* 00970 Write a set of metacontent. 00971 */ 00972 length=clone_info->metacontent_extent; 00973 if (clone_info->type != DiskCache) 00974 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset, 00975 p,length); 00976 else 00977 { 00978 count=WritePixelCacheRegion(clone_info,clone_offset,length,p); 00979 if ((MagickSizeType) count != length) 00980 { 00981 status=MagickFalse; 00982 break; 00983 } 00984 } 00985 clone_offset+=length; 00986 } 00987 } 00988 length=clone_info->metacontent_extent; 00989 (void) ResetMagickMemory(blob,0,length*sizeof(*blob)); 00990 for ( ; x < (ssize_t) clone_info->columns; x++) 00991 { 00992 /* 00993 Set remaining columns as undefined. 00994 */ 00995 if (clone_info->type != DiskCache) 00996 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset, 00997 blob,length); 00998 else 00999 { 01000 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob); 01001 if ((MagickSizeType) count != length) 01002 { 01003 status=MagickFalse; 01004 break; 01005 } 01006 } 01007 clone_offset+=length; 01008 } 01009 } 01010 length=clone_info->metacontent_extent; 01011 (void) ResetMagickMemory(blob,0,length*sizeof(*blob)); 01012 for ( ; y < (ssize_t) clone_info->rows; y++) 01013 { 01014 /* 01015 Set remaining rows as undefined. 01016 */ 01017 for (x=0; x < (ssize_t) clone_info->columns; x++) 01018 { 01019 if (clone_info->type != DiskCache) 01020 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset, 01021 blob,length); 01022 else 01023 { 01024 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob); 01025 if ((MagickSizeType) count != length) 01026 { 01027 status=MagickFalse; 01028 break; 01029 } 01030 } 01031 clone_offset+=length; 01032 } 01033 } 01034 } 01035 if (clone_info->type == DiskCache) 01036 (void) ClosePixelCacheOnDisk(clone_info); 01037 if (cache_info->type == DiskCache) 01038 (void) ClosePixelCacheOnDisk(cache_info); 01039 blob=(unsigned char *) RelinquishMagickMemory(blob); 01040 return(status); 01041 } 01042 01043 static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info, 01044 CacheInfo *cache_info,ExceptionInfo *exception) 01045 { 01046 PixelChannelMap 01047 *p, 01048 *q; 01049 01050 if (cache_info->type == PingCache) 01051 return(MagickTrue); 01052 p=cache_info->channel_map; 01053 q=clone_info->channel_map; 01054 if ((cache_info->columns == clone_info->columns) && 01055 (cache_info->rows == clone_info->rows) && 01056 (cache_info->number_channels == clone_info->number_channels) && 01057 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) && 01058 (cache_info->metacontent_extent == clone_info->metacontent_extent)) 01059 return(PixelCacheCloneOptimized(clone_info,cache_info,exception)); 01060 return(PixelCacheCloneUnoptimized(clone_info,cache_info,exception)); 01061 } 01062 01063 /* 01064 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01065 % % 01066 % % 01067 % % 01068 + C l o n e P i x e l C a c h e M e t h o d s % 01069 % % 01070 % % 01071 % % 01072 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01073 % 01074 % ClonePixelCacheMethods() clones the pixel cache methods from one cache to 01075 % another. 01076 % 01077 % The format of the ClonePixelCacheMethods() method is: 01078 % 01079 % void ClonePixelCacheMethods(Cache clone,const Cache cache) 01080 % 01081 % A description of each parameter follows: 01082 % 01083 % o clone: Specifies a pointer to a Cache structure. 01084 % 01085 % o cache: the pixel cache. 01086 % 01087 */ 01088 MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache) 01089 { 01090 CacheInfo 01091 *cache_info, 01092 *source_info; 01093 01094 assert(clone != (Cache) NULL); 01095 source_info=(CacheInfo *) clone; 01096 assert(source_info->signature == MagickSignature); 01097 if (source_info->debug != MagickFalse) 01098 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 01099 source_info->filename); 01100 assert(cache != (Cache) NULL); 01101 cache_info=(CacheInfo *) cache; 01102 assert(cache_info->signature == MagickSignature); 01103 source_info->methods=cache_info->methods; 01104 } 01105 01106 /* 01107 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01108 % % 01109 % % 01110 % % 01111 + D e s t r o y I m a g e P i x e l C a c h e % 01112 % % 01113 % % 01114 % % 01115 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01116 % 01117 % DestroyImagePixelCache() deallocates memory associated with the pixel cache. 01118 % 01119 % The format of the DestroyImagePixelCache() method is: 01120 % 01121 % void DestroyImagePixelCache(Image *image) 01122 % 01123 % A description of each parameter follows: 01124 % 01125 % o image: the image. 01126 % 01127 */ 01128 static void DestroyImagePixelCache(Image *image) 01129 { 01130 assert(image != (Image *) NULL); 01131 assert(image->signature == MagickSignature); 01132 if (image->debug != MagickFalse) 01133 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 01134 if (image->cache == (void *) NULL) 01135 return; 01136 image->cache=DestroyPixelCache(image->cache); 01137 } 01138 01139 /* 01140 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01141 % % 01142 % % 01143 % % 01144 + D e s t r o y I m a g e P i x e l s % 01145 % % 01146 % % 01147 % % 01148 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01149 % 01150 % DestroyImagePixels() deallocates memory associated with the pixel cache. 01151 % 01152 % The format of the DestroyImagePixels() method is: 01153 % 01154 % void DestroyImagePixels(Image *image) 01155 % 01156 % A description of each parameter follows: 01157 % 01158 % o image: the image. 01159 % 01160 */ 01161 MagickExport void DestroyImagePixels(Image *image) 01162 { 01163 CacheInfo 01164 *cache_info; 01165 01166 assert(image != (const Image *) NULL); 01167 assert(image->signature == MagickSignature); 01168 if (image->debug != MagickFalse) 01169 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 01170 assert(image->cache != (Cache) NULL); 01171 cache_info=(CacheInfo *) image->cache; 01172 assert(cache_info->signature == MagickSignature); 01173 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL) 01174 { 01175 cache_info->methods.destroy_pixel_handler(image); 01176 return; 01177 } 01178 image->cache=DestroyPixelCache(image->cache); 01179 } 01180 01181 /* 01182 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01183 % % 01184 % % 01185 % % 01186 + D e s t r o y P i x e l C a c h e % 01187 % % 01188 % % 01189 % % 01190 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01191 % 01192 % DestroyPixelCache() deallocates memory associated with the pixel cache. 01193 % 01194 % The format of the DestroyPixelCache() method is: 01195 % 01196 % Cache DestroyPixelCache(Cache cache) 01197 % 01198 % A description of each parameter follows: 01199 % 01200 % o cache: the pixel cache. 01201 % 01202 */ 01203 01204 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info) 01205 { 01206 switch (cache_info->type) 01207 { 01208 case MemoryCache: 01209 { 01210 if (cache_info->mapped == MagickFalse) 01211 cache_info->pixels=(Quantum *) RelinquishMagickMemory( 01212 cache_info->pixels); 01213 else 01214 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels, 01215 (size_t) cache_info->length); 01216 RelinquishMagickResource(MemoryResource,cache_info->length); 01217 break; 01218 } 01219 case MapCache: 01220 { 01221 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t) 01222 cache_info->length); 01223 RelinquishMagickResource(MapResource,cache_info->length); 01224 } 01225 case DiskCache: 01226 { 01227 if (cache_info->file != -1) 01228 (void) ClosePixelCacheOnDisk(cache_info); 01229 RelinquishMagickResource(DiskResource,cache_info->length); 01230 break; 01231 } 01232 default: 01233 break; 01234 } 01235 cache_info->type=UndefinedCache; 01236 cache_info->mapped=MagickFalse; 01237 cache_info->metacontent=(void *) NULL; 01238 } 01239 01240 MagickPrivate Cache DestroyPixelCache(Cache cache) 01241 { 01242 CacheInfo 01243 *cache_info; 01244 01245 assert(cache != (Cache) NULL); 01246 cache_info=(CacheInfo *) cache; 01247 assert(cache_info->signature == MagickSignature); 01248 if (cache_info->debug != MagickFalse) 01249 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 01250 cache_info->filename); 01251 LockSemaphoreInfo(cache_info->semaphore); 01252 cache_info->reference_count--; 01253 if (cache_info->reference_count != 0) 01254 { 01255 UnlockSemaphoreInfo(cache_info->semaphore); 01256 return((Cache) NULL); 01257 } 01258 UnlockSemaphoreInfo(cache_info->semaphore); 01259 if (cache_info->debug != MagickFalse) 01260 { 01261 char 01262 message[MaxTextExtent]; 01263 01264 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s", 01265 cache_info->filename); 01266 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message); 01267 } 01268 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) && 01269 (cache_info->type != DiskCache))) 01270 RelinquishPixelCachePixels(cache_info); 01271 else 01272 { 01273 RelinquishPixelCachePixels(cache_info); 01274 (void) RelinquishUniqueFileResource(cache_info->cache_filename); 01275 } 01276 *cache_info->cache_filename='\0'; 01277 if (cache_info->nexus_info != (NexusInfo **) NULL) 01278 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info, 01279 cache_info->number_threads); 01280 if (cache_info->random_info != (RandomInfo *) NULL) 01281 cache_info->random_info=DestroyRandomInfo(cache_info->random_info); 01282 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL) 01283 DestroySemaphoreInfo(&cache_info->disk_semaphore); 01284 if (cache_info->semaphore != (SemaphoreInfo *) NULL) 01285 DestroySemaphoreInfo(&cache_info->semaphore); 01286 cache_info->signature=(~MagickSignature); 01287 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info); 01288 cache=(Cache) NULL; 01289 return(cache); 01290 } 01291 01292 /* 01293 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01294 % % 01295 % % 01296 % % 01297 + D e s t r o y P i x e l C a c h e N e x u s % 01298 % % 01299 % % 01300 % % 01301 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01302 % 01303 % DestroyPixelCacheNexus() destroys a pixel cache nexus. 01304 % 01305 % The format of the DestroyPixelCacheNexus() method is: 01306 % 01307 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info, 01308 % const size_t number_threads) 01309 % 01310 % A description of each parameter follows: 01311 % 01312 % o nexus_info: the nexus to destroy. 01313 % 01314 % o number_threads: the number of nexus threads. 01315 % 01316 */ 01317 01318 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info) 01319 { 01320 if (nexus_info->mapped == MagickFalse) 01321 (void) RelinquishAlignedMemory(nexus_info->cache); 01322 else 01323 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length); 01324 nexus_info->cache=(Quantum *) NULL; 01325 nexus_info->pixels=(Quantum *) NULL; 01326 nexus_info->metacontent=(void *) NULL; 01327 nexus_info->length=0; 01328 nexus_info->mapped=MagickFalse; 01329 } 01330 01331 MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info, 01332 const size_t number_threads) 01333 { 01334 register ssize_t 01335 i; 01336 01337 assert(nexus_info != (NexusInfo **) NULL); 01338 for (i=0; i < (ssize_t) number_threads; i++) 01339 { 01340 if (nexus_info[i]->cache != (Quantum *) NULL) 01341 RelinquishCacheNexusPixels(nexus_info[i]); 01342 nexus_info[i]->signature=(~MagickSignature); 01343 nexus_info[i]=(NexusInfo *) RelinquishMagickMemory(nexus_info[i]); 01344 } 01345 nexus_info=(NexusInfo **) RelinquishMagickMemory(nexus_info); 01346 return(nexus_info); 01347 } 01348 01349 /* 01350 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01351 % % 01352 % % 01353 % % 01354 % G e t A u t h e n t i c M e t a c o n t e n t % 01355 % % 01356 % % 01357 % % 01358 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01359 % 01360 % GetAuthenticMetacontent() returns the authentic metacontent corresponding 01361 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is 01362 % returned if the associated pixels are not available. 01363 % 01364 % The format of the GetAuthenticMetacontent() method is: 01365 % 01366 % void *GetAuthenticMetacontent(const Image *image) 01367 % 01368 % A description of each parameter follows: 01369 % 01370 % o image: the image. 01371 % 01372 */ 01373 MagickExport void *GetAuthenticMetacontent(const Image *image) 01374 { 01375 CacheInfo 01376 *cache_info; 01377 01378 const int 01379 id = GetOpenMPThreadId(); 01380 01381 void 01382 *metacontent; 01383 01384 assert(image != (const Image *) NULL); 01385 assert(image->signature == MagickSignature); 01386 assert(image->cache != (Cache) NULL); 01387 cache_info=(CacheInfo *) image->cache; 01388 assert(cache_info->signature == MagickSignature); 01389 if (cache_info->methods.get_authentic_metacontent_from_handler != 01390 (GetAuthenticMetacontentFromHandler) NULL) 01391 { 01392 metacontent=cache_info->methods. 01393 get_authentic_metacontent_from_handler(image); 01394 return(metacontent); 01395 } 01396 assert(id < (int) cache_info->number_threads); 01397 metacontent=GetPixelCacheNexusMetacontent(cache_info, 01398 cache_info->nexus_info[id]); 01399 return(metacontent); 01400 } 01401 01402 /* 01403 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01404 % % 01405 % % 01406 % % 01407 + G e t A u t h e n t i c M e t a c o n t e n t F r o m C a c h e % 01408 % % 01409 % % 01410 % % 01411 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01412 % 01413 % GetAuthenticMetacontentFromCache() returns the meta-content corresponding 01414 % with the last call to QueueAuthenticPixelsCache() or 01415 % GetAuthenticPixelsCache(). 01416 % 01417 % The format of the GetAuthenticMetacontentFromCache() method is: 01418 % 01419 % void *GetAuthenticMetacontentFromCache(const Image *image) 01420 % 01421 % A description of each parameter follows: 01422 % 01423 % o image: the image. 01424 % 01425 */ 01426 static void *GetAuthenticMetacontentFromCache(const Image *image) 01427 { 01428 CacheInfo 01429 *cache_info; 01430 01431 const int 01432 id = GetOpenMPThreadId(); 01433 01434 void 01435 *metacontent; 01436 01437 assert(image != (const Image *) NULL); 01438 assert(image->signature == MagickSignature); 01439 assert(image->cache != (Cache) NULL); 01440 cache_info=(CacheInfo *) image->cache; 01441 assert(cache_info->signature == MagickSignature); 01442 assert(id < (int) cache_info->number_threads); 01443 metacontent=GetPixelCacheNexusMetacontent(image->cache, 01444 cache_info->nexus_info[id]); 01445 return(metacontent); 01446 } 01447 01448 /* 01449 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01450 % % 01451 % % 01452 % % 01453 + G e t A u t h e n t i c P i x e l C a c h e N e x u s % 01454 % % 01455 % % 01456 % % 01457 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01458 % 01459 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or 01460 % disk pixel cache as defined by the geometry parameters. A pointer to the 01461 % pixels is returned if the pixels are transferred, otherwise a NULL is 01462 % returned. 01463 % 01464 % The format of the GetAuthenticPixelCacheNexus() method is: 01465 % 01466 % Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x, 01467 % const ssize_t y,const size_t columns,const size_t rows, 01468 % NexusInfo *nexus_info,ExceptionInfo *exception) 01469 % 01470 % A description of each parameter follows: 01471 % 01472 % o image: the image. 01473 % 01474 % o x,y,columns,rows: These values define the perimeter of a region of 01475 % pixels. 01476 % 01477 % o nexus_info: the cache nexus to return. 01478 % 01479 % o exception: return any errors or warnings in this structure. 01480 % 01481 */ 01482 01483 static inline MagickBooleanType IsPixelAuthentic(const CacheInfo *cache_info, 01484 NexusInfo *nexus_info) 01485 { 01486 MagickBooleanType 01487 status; 01488 01489 MagickOffsetType 01490 offset; 01491 01492 if (cache_info->type == PingCache) 01493 return(MagickTrue); 01494 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+ 01495 nexus_info->region.x; 01496 status=nexus_info->pixels == (cache_info->pixels+offset* 01497 cache_info->number_channels) ? MagickTrue : MagickFalse; 01498 return(status); 01499 } 01500 01501 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image, 01502 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows, 01503 NexusInfo *nexus_info,ExceptionInfo *exception) 01504 { 01505 CacheInfo 01506 *cache_info; 01507 01508 Quantum 01509 *q; 01510 01511 /* 01512 Transfer pixels from the cache. 01513 */ 01514 assert(image != (Image *) NULL); 01515 assert(image->signature == MagickSignature); 01516 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,nexus_info, 01517 exception); 01518 if (q == (Quantum *) NULL) 01519 return((Quantum *) NULL); 01520 cache_info=(CacheInfo *) image->cache; 01521 assert(cache_info->signature == MagickSignature); 01522 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse) 01523 return(q); 01524 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse) 01525 return((Quantum *) NULL); 01526 if (cache_info->metacontent_extent != 0) 01527 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse) 01528 return((Quantum *) NULL); 01529 return(q); 01530 } 01531 01532 /* 01533 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01534 % % 01535 % % 01536 % % 01537 + G e t A u t h e n t i c P i x e l s F r o m C a c h e % 01538 % % 01539 % % 01540 % % 01541 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01542 % 01543 % GetAuthenticPixelsFromCache() returns the pixels associated with the last 01544 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods. 01545 % 01546 % The format of the GetAuthenticPixelsFromCache() method is: 01547 % 01548 % Quantum *GetAuthenticPixelsFromCache(const Image image) 01549 % 01550 % A description of each parameter follows: 01551 % 01552 % o image: the image. 01553 % 01554 */ 01555 static Quantum *GetAuthenticPixelsFromCache(const Image *image) 01556 { 01557 CacheInfo 01558 *cache_info; 01559 01560 const int 01561 id = GetOpenMPThreadId(); 01562 01563 assert(image != (const Image *) NULL); 01564 assert(image->signature == MagickSignature); 01565 assert(image->cache != (Cache) NULL); 01566 cache_info=(CacheInfo *) image->cache; 01567 assert(cache_info->signature == MagickSignature); 01568 assert(id < (int) cache_info->number_threads); 01569 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id])); 01570 } 01571 01572 /* 01573 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01574 % % 01575 % % 01576 % % 01577 % G e t A u t h e n t i c P i x e l Q u e u e % 01578 % % 01579 % % 01580 % % 01581 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01582 % 01583 % GetAuthenticPixelQueue() returns the authentic pixels associated 01584 % corresponding with the last call to QueueAuthenticPixels() or 01585 % GetAuthenticPixels(). 01586 % 01587 % The format of the GetAuthenticPixelQueue() method is: 01588 % 01589 % Quantum *GetAuthenticPixelQueue(const Image image) 01590 % 01591 % A description of each parameter follows: 01592 % 01593 % o image: the image. 01594 % 01595 */ 01596 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image) 01597 { 01598 CacheInfo 01599 *cache_info; 01600 01601 const int 01602 id = GetOpenMPThreadId(); 01603 01604 assert(image != (const Image *) NULL); 01605 assert(image->signature == MagickSignature); 01606 assert(image->cache != (Cache) NULL); 01607 cache_info=(CacheInfo *) image->cache; 01608 assert(cache_info->signature == MagickSignature); 01609 if (cache_info->methods.get_authentic_pixels_from_handler != 01610 (GetAuthenticPixelsFromHandler) NULL) 01611 return(cache_info->methods.get_authentic_pixels_from_handler(image)); 01612 assert(id < (int) cache_info->number_threads); 01613 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id])); 01614 } 01615 01616 /* 01617 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01618 % % 01619 % % 01620 % % 01621 % G e t A u t h e n t i c P i x e l s % 01622 % % 01623 % % 01624 % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01625 % 01626 % GetAuthenticPixels() obtains a pixel region for read/write access. If the 01627 % region is successfully accessed, a pointer to a Quantum array 01628 % representing the region is returned, otherwise NULL is returned. 01629 % 01630 % The returned pointer may point to a temporary working copy of the pixels 01631 % or it may point to the original pixels in memory. Performance is maximized 01632 % if the selected region is part of one row, or one or more full rows, since 01633 % then there is opportunity to access the pixels in-place (without a copy) 01634 % if the image is in memory, or in a memory-mapped file. The returned pointer 01635 % must *never* be deallocated by the user. 01636 % 01637 % Pixels accessed via the returned pointer represent a simple array of type 01638 % Quantum. If the image has corresponding metacontent,call 01639 % GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the 01640 % meta-content corresponding to the region. Once the Quantum array has 01641 % been updated, the changes must be saved back to the underlying image using 01642 % SyncAuthenticPixels() or they may be lost. 01643 % 01644 % The format of the GetAuthenticPixels() method is: 01645 % 01646 % Quantum *GetAuthenticPixels(Image *image,const ssize_t x, 01647 % const ssize_t y,const size_t columns,const size_t rows, 01648 % ExceptionInfo *exception) 01649 % 01650 % A description of each parameter follows: 01651 % 01652 % o image: the image. 01653 % 01654 % o x,y,columns,rows: These values define the perimeter of a region of 01655 % pixels. 01656 % 01657 % o exception: return any errors or warnings in this structure. 01658 % 01659 */ 01660 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x, 01661 const ssize_t y,const size_t columns,const size_t rows, 01662 ExceptionInfo *exception) 01663 { 01664 CacheInfo 01665 *cache_info; 01666 01667 const int 01668 id = GetOpenMPThreadId(); 01669 01670 Quantum 01671 *q; 01672 01673 assert(image != (Image *) NULL); 01674 assert(image->signature == MagickSignature); 01675 assert(image->cache != (Cache) NULL); 01676 cache_info=(CacheInfo *) image->cache; 01677 assert(cache_info->signature == MagickSignature); 01678 if (cache_info->methods.get_authentic_pixels_handler != 01679 (GetAuthenticPixelsHandler) NULL) 01680 { 01681 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows, 01682 exception); 01683 return(q); 01684 } 01685 assert(id < (int) cache_info->number_threads); 01686 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows, 01687 cache_info->nexus_info[id],exception); 01688 return(q); 01689 } 01690 01691 /* 01692 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01693 % % 01694 % % 01695 % % 01696 + G e t A u t h e n t i c P i x e l s C a c h e % 01697 % % 01698 % % 01699 % % 01700 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01701 % 01702 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache 01703 % as defined by the geometry parameters. A pointer to the pixels is returned 01704 % if the pixels are transferred, otherwise a NULL is returned. 01705 % 01706 % The format of the GetAuthenticPixelsCache() method is: 01707 % 01708 % Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x, 01709 % const ssize_t y,const size_t columns,const size_t rows, 01710 % ExceptionInfo *exception) 01711 % 01712 % A description of each parameter follows: 01713 % 01714 % o image: the image. 01715 % 01716 % o x,y,columns,rows: These values define the perimeter of a region of 01717 % pixels. 01718 % 01719 % o exception: return any errors or warnings in this structure. 01720 % 01721 */ 01722 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x, 01723 const ssize_t y,const size_t columns,const size_t rows, 01724 ExceptionInfo *exception) 01725 { 01726 CacheInfo 01727 *cache_info; 01728 01729 const int 01730 id = GetOpenMPThreadId(); 01731 01732 Quantum 01733 *q; 01734 01735 assert(image != (const Image *) NULL); 01736 assert(image->signature == MagickSignature); 01737 assert(image->cache != (Cache) NULL); 01738 cache_info=(CacheInfo *) image->cache; 01739 if (cache_info == (Cache) NULL) 01740 return((Quantum *) NULL); 01741 assert(cache_info->signature == MagickSignature); 01742 assert(id < (int) cache_info->number_threads); 01743 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows, 01744 cache_info->nexus_info[id],exception); 01745 return(q); 01746 } 01747 01748 /* 01749 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01750 % % 01751 % % 01752 % % 01753 + G e t I m a g e E x t e n t % 01754 % % 01755 % % 01756 % % 01757 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01758 % 01759 % GetImageExtent() returns the extent of the pixels associated corresponding 01760 % with the last call to QueueAuthenticPixels() or GetAuthenticPixels(). 01761 % 01762 % The format of the GetImageExtent() method is: 01763 % 01764 % MagickSizeType GetImageExtent(const Image *image) 01765 % 01766 % A description of each parameter follows: 01767 % 01768 % o image: the image. 01769 % 01770 */ 01771 MagickExport MagickSizeType GetImageExtent(const Image *image) 01772 { 01773 CacheInfo 01774 *cache_info; 01775 01776 const int 01777 id = GetOpenMPThreadId(); 01778 01779 assert(image != (Image *) NULL); 01780 assert(image->signature == MagickSignature); 01781 if (image->debug != MagickFalse) 01782 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 01783 assert(image->cache != (Cache) NULL); 01784 cache_info=(CacheInfo *) image->cache; 01785 assert(cache_info->signature == MagickSignature); 01786 assert(id < (int) cache_info->number_threads); 01787 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id])); 01788 } 01789 01790 /* 01791 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01792 % % 01793 % % 01794 % % 01795 + G e t I m a g e P i x e l C a c h e % 01796 % % 01797 % % 01798 % % 01799 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01800 % 01801 % GetImagePixelCache() ensures that there is only a single reference to the 01802 % pixel cache to be modified, updating the provided cache pointer to point to 01803 % a clone of the original pixel cache if necessary. 01804 % 01805 % The format of the GetImagePixelCache method is: 01806 % 01807 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone, 01808 % ExceptionInfo *exception) 01809 % 01810 % A description of each parameter follows: 01811 % 01812 % o image: the image. 01813 % 01814 % o clone: any value other than MagickFalse clones the cache pixels. 01815 % 01816 % o exception: return any errors or warnings in this structure. 01817 % 01818 */ 01819 01820 static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image) 01821 { 01822 CacheInfo 01823 *cache_info; 01824 01825 PixelChannelMap 01826 *p, 01827 *q; 01828 01829 /* 01830 Does the image match the pixel cache morphology? 01831 */ 01832 cache_info=(CacheInfo *) image->cache; 01833 p=image->channel_map; 01834 q=cache_info->channel_map; 01835 if ((image->storage_class != cache_info->storage_class) || 01836 (image->colorspace != cache_info->colorspace) || 01837 (image->matte != cache_info->matte) || 01838 (image->mask != cache_info->mask) || 01839 (image->columns != cache_info->columns) || 01840 (image->rows != cache_info->rows) || 01841 (image->number_channels != cache_info->number_channels) || 01842 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) || 01843 (image->metacontent_extent != cache_info->metacontent_extent) || 01844 (cache_info->nexus_info == (NexusInfo **) NULL) || 01845 (cache_info->number_threads < GetOpenMPMaximumThreads())) 01846 return(MagickFalse); 01847 return(MagickTrue); 01848 } 01849 01850 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone, 01851 ExceptionInfo *exception) 01852 { 01853 CacheInfo 01854 *cache_info; 01855 01856 MagickBooleanType 01857 destroy, 01858 status; 01859 01860 static MagickSizeType 01861 cpu_throttle = 0, 01862 cycles = 0, 01863 time_limit = 0; 01864 01865 static time_t 01866 cache_timestamp = 0; 01867 01868 status=MagickTrue; 01869 LockSemaphoreInfo(image->semaphore); 01870 if (cpu_throttle == 0) 01871 { 01872 char 01873 *limit; 01874 01875 /* 01876 Set CPU throttle in milleseconds. 01877 */ 01878 cpu_throttle=MagickResourceInfinity; 01879 limit=GetEnvironmentValue("MAGICK_THROTTLE"); 01880 if (limit == (char *) NULL) 01881 limit=GetPolicyValue("throttle"); 01882 if (limit != (char *) NULL) 01883 { 01884 cpu_throttle=(MagickSizeType) StringToInteger(limit); 01885 limit=DestroyString(limit); 01886 } 01887 } 01888 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0)) 01889 MagickDelay(cpu_throttle); 01890 if (time_limit == 0) 01891 { 01892 /* 01893 Set the exire time in seconds. 01894 */ 01895 time_limit=GetMagickResourceLimit(TimeResource); 01896 cache_timestamp=time((time_t *) NULL); 01897 } 01898 if ((time_limit != MagickResourceInfinity) && 01899 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit)) 01900 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded"); 01901 assert(image->cache != (Cache) NULL); 01902 cache_info=(CacheInfo *) image->cache; 01903 destroy=MagickFalse; 01904 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode)) 01905 { 01906 LockSemaphoreInfo(cache_info->semaphore); 01907 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode)) 01908 { 01909 Image 01910 clone_image; 01911 01912 CacheInfo 01913 *clone_info; 01914 01915 /* 01916 Clone pixel cache. 01917 */ 01918 clone_image=(*image); 01919 clone_image.semaphore=AllocateSemaphoreInfo(); 01920 clone_image.reference_count=1; 01921 clone_image.cache=ClonePixelCache(cache_info); 01922 clone_info=(CacheInfo *) clone_image.cache; 01923 status=OpenPixelCache(&clone_image,IOMode,exception); 01924 if (status != MagickFalse) 01925 { 01926 if (clone != MagickFalse) 01927 status=ClonePixelCachePixels(clone_info,cache_info,exception); 01928 if (status != MagickFalse) 01929 { 01930 if (cache_info->mode == ReadMode) 01931 cache_info->nexus_info=(NexusInfo **) NULL; 01932 destroy=MagickTrue; 01933 image->cache=clone_image.cache; 01934 } 01935 } 01936 DestroySemaphoreInfo(&clone_image.semaphore); 01937 } 01938 UnlockSemaphoreInfo(cache_info->semaphore); 01939 } 01940 if (destroy != MagickFalse) 01941 cache_info=(CacheInfo *) DestroyPixelCache(cache_info); 01942 if (status != MagickFalse) 01943 { 01944 /* 01945 Ensure the image matches the pixel cache morphology. 01946 */ 01947 image->taint=MagickTrue; 01948 image->type=UndefinedType; 01949 if (ValidatePixelCacheMorphology(image) == MagickFalse) 01950 { 01951 status=OpenPixelCache(image,IOMode,exception); 01952 cache_info=(CacheInfo *) image->cache; 01953 if (cache_info->type == DiskCache) 01954 (void) ClosePixelCacheOnDisk(cache_info); 01955 } 01956 } 01957 UnlockSemaphoreInfo(image->semaphore); 01958 if (status == MagickFalse) 01959 return((Cache) NULL); 01960 return(image->cache); 01961 } 01962 01963 /* 01964 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01965 % % 01966 % % 01967 % % 01968 % G e t O n e A u t h e n t i c P i x e l % 01969 % % 01970 % % 01971 % % 01972 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01973 % 01974 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y) 01975 % location. The image background color is returned if an error occurs. 01976 % 01977 % The format of the GetOneAuthenticPixel() method is: 01978 % 01979 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x, 01980 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception) 01981 % 01982 % A description of each parameter follows: 01983 % 01984 % o image: the image. 01985 % 01986 % o x,y: These values define the location of the pixel to return. 01987 % 01988 % o pixel: return a pixel at the specified (x,y) location. 01989 % 01990 % o exception: return any errors or warnings in this structure. 01991 % 01992 */ 01993 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image, 01994 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception) 01995 { 01996 CacheInfo 01997 *cache_info; 01998 01999 register Quantum 02000 *q; 02001 02002 register ssize_t 02003 i; 02004 02005 assert(image != (Image *) NULL); 02006 assert(image->signature == MagickSignature); 02007 assert(image->cache != (Cache) NULL); 02008 cache_info=(CacheInfo *) image->cache; 02009 assert(cache_info->signature == MagickSignature); 02010 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel)); 02011 if (cache_info->methods.get_one_authentic_pixel_from_handler != 02012 (GetOneAuthenticPixelFromHandler) NULL) 02013 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y, 02014 pixel,exception)); 02015 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception); 02016 if (q == (Quantum *) NULL) 02017 { 02018 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red); 02019 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green); 02020 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue); 02021 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black); 02022 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha); 02023 return(MagickFalse); 02024 } 02025 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 02026 { 02027 PixelChannel 02028 channel; 02029 02030 channel=GetPixelChannelMapChannel(image,i); 02031 pixel[channel]=q[i]; 02032 } 02033 return(MagickTrue); 02034 } 02035 02036 /* 02037 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02038 % % 02039 % % 02040 % % 02041 + G e t O n e A u t h e n t i c P i x e l F r o m C a c h e % 02042 % % 02043 % % 02044 % % 02045 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02046 % 02047 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y) 02048 % location. The image background color is returned if an error occurs. 02049 % 02050 % The format of the GetOneAuthenticPixelFromCache() method is: 02051 % 02052 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image, 02053 % const ssize_t x,const ssize_t y,Quantum *pixel, 02054 % ExceptionInfo *exception) 02055 % 02056 % A description of each parameter follows: 02057 % 02058 % o image: the image. 02059 % 02060 % o x,y: These values define the location of the pixel to return. 02061 % 02062 % o pixel: return a pixel at the specified (x,y) location. 02063 % 02064 % o exception: return any errors or warnings in this structure. 02065 % 02066 */ 02067 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image, 02068 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception) 02069 { 02070 CacheInfo 02071 *cache_info; 02072 02073 const int 02074 id = GetOpenMPThreadId(); 02075 02076 register Quantum 02077 *q; 02078 02079 register ssize_t 02080 i; 02081 02082 assert(image != (const Image *) NULL); 02083 assert(image->signature == MagickSignature); 02084 assert(image->cache != (Cache) NULL); 02085 cache_info=(CacheInfo *) image->cache; 02086 assert(cache_info->signature == MagickSignature); 02087 assert(id < (int) cache_info->number_threads); 02088 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel)); 02089 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id], 02090 exception); 02091 if (q == (Quantum *) NULL) 02092 { 02093 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red); 02094 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green); 02095 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue); 02096 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black); 02097 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha); 02098 return(MagickFalse); 02099 } 02100 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 02101 { 02102 PixelChannel 02103 channel; 02104 02105 channel=GetPixelChannelMapChannel(image,i); 02106 pixel[channel]=q[i]; 02107 } 02108 return(MagickTrue); 02109 } 02110 02111 /* 02112 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02113 % % 02114 % % 02115 % % 02116 % G e t O n e V i r t u a l P i x e l % 02117 % % 02118 % % 02119 % % 02120 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02121 % 02122 % GetOneVirtualPixel() returns a single virtual pixel at the specified 02123 % (x,y) location. The image background color is returned if an error occurs. 02124 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead. 02125 % 02126 % The format of the GetOneVirtualPixel() method is: 02127 % 02128 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x, 02129 % const ssize_t y,Quantum *pixel,ExceptionInfo exception) 02130 % 02131 % A description of each parameter follows: 02132 % 02133 % o image: the image. 02134 % 02135 % o x,y: These values define the location of the pixel to return. 02136 % 02137 % o pixel: return a pixel at the specified (x,y) location. 02138 % 02139 % o exception: return any errors or warnings in this structure. 02140 % 02141 */ 02142 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image, 02143 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception) 02144 { 02145 CacheInfo 02146 *cache_info; 02147 02148 const int 02149 id = GetOpenMPThreadId(); 02150 02151 const Quantum 02152 *p; 02153 02154 register ssize_t 02155 i; 02156 02157 assert(image != (const Image *) NULL); 02158 assert(image->signature == MagickSignature); 02159 assert(image->cache != (Cache) NULL); 02160 cache_info=(CacheInfo *) image->cache; 02161 assert(cache_info->signature == MagickSignature); 02162 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel)); 02163 if (cache_info->methods.get_one_virtual_pixel_from_handler != 02164 (GetOneVirtualPixelFromHandler) NULL) 02165 return(cache_info->methods.get_one_virtual_pixel_from_handler(image, 02166 GetPixelCacheVirtualMethod(image),x,y,pixel,exception)); 02167 assert(id < (int) cache_info->number_threads); 02168 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y, 02169 1UL,1UL,cache_info->nexus_info[id],exception); 02170 if (p == (const Quantum *) NULL) 02171 { 02172 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red); 02173 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green); 02174 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue); 02175 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black); 02176 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha); 02177 return(MagickFalse); 02178 } 02179 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 02180 { 02181 PixelChannel 02182 channel; 02183 02184 channel=GetPixelChannelMapChannel(image,i); 02185 pixel[channel]=p[i]; 02186 } 02187 return(MagickTrue); 02188 } 02189 02190 /* 02191 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02192 % % 02193 % % 02194 % % 02195 + G e t O n e V i r t u a l P i x e l F r o m C a c h e % 02196 % % 02197 % % 02198 % % 02199 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02200 % 02201 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the 02202 % specified (x,y) location. The image background color is returned if an 02203 % error occurs. 02204 % 02205 % The format of the GetOneVirtualPixelFromCache() method is: 02206 % 02207 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image, 02208 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y, 02209 % Quantum *pixel,ExceptionInfo *exception) 02210 % 02211 % A description of each parameter follows: 02212 % 02213 % o image: the image. 02214 % 02215 % o virtual_pixel_method: the virtual pixel method. 02216 % 02217 % o x,y: These values define the location of the pixel to return. 02218 % 02219 % o pixel: return a pixel at the specified (x,y) location. 02220 % 02221 % o exception: return any errors or warnings in this structure. 02222 % 02223 */ 02224 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image, 02225 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y, 02226 Quantum *pixel,ExceptionInfo *exception) 02227 { 02228 CacheInfo 02229 *cache_info; 02230 02231 const int 02232 id = GetOpenMPThreadId(); 02233 02234 const Quantum 02235 *p; 02236 02237 register ssize_t 02238 i; 02239 02240 assert(image != (const Image *) NULL); 02241 assert(image->signature == MagickSignature); 02242 assert(image->cache != (Cache) NULL); 02243 cache_info=(CacheInfo *) image->cache; 02244 assert(cache_info->signature == MagickSignature); 02245 assert(id < (int) cache_info->number_threads); 02246 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel)); 02247 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL, 02248 cache_info->nexus_info[id],exception); 02249 if (p == (const Quantum *) NULL) 02250 { 02251 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red); 02252 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green); 02253 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue); 02254 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black); 02255 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha); 02256 return(MagickFalse); 02257 } 02258 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 02259 { 02260 PixelChannel 02261 channel; 02262 02263 channel=GetPixelChannelMapChannel(image,i); 02264 pixel[channel]=p[i]; 02265 } 02266 return(MagickTrue); 02267 } 02268 02269 /* 02270 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02271 % % 02272 % % 02273 % % 02274 % G e t O n e V i r t u a l P i x e l I n f o % 02275 % % 02276 % % 02277 % % 02278 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02279 % 02280 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y) 02281 % location. The image background color is returned if an error occurs. If 02282 % you plan to modify the pixel, use GetOneAuthenticPixel() instead. 02283 % 02284 % The format of the GetOneVirtualPixelInfo() method is: 02285 % 02286 % MagickBooleanType GetOneVirtualPixelInfo(const Image image, 02287 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x, 02288 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception) 02289 % 02290 % A description of each parameter follows: 02291 % 02292 % o image: the image. 02293 % 02294 % o virtual_pixel_method: the virtual pixel method. 02295 % 02296 % o x,y: these values define the location of the pixel to return. 02297 % 02298 % o pixel: return a pixel at the specified (x,y) location. 02299 % 02300 % o exception: return any errors or warnings in this structure. 02301 % 02302 */ 02303 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image, 02304 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y, 02305 PixelInfo *pixel,ExceptionInfo *exception) 02306 { 02307 CacheInfo 02308 *cache_info; 02309 02310 const int 02311 id = GetOpenMPThreadId(); 02312 02313 register const Quantum 02314 *p; 02315 02316 assert(image != (const Image *) NULL); 02317 assert(image->signature == MagickSignature); 02318 assert(image->cache != (Cache) NULL); 02319 cache_info=(CacheInfo *) image->cache; 02320 assert(cache_info->signature == MagickSignature); 02321 assert(id < (int) cache_info->number_threads); 02322 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL, 02323 cache_info->nexus_info[id],exception); 02324 GetPixelInfo(image,pixel); 02325 if (p == (const Quantum *) NULL) 02326 return(MagickFalse); 02327 GetPixelInfoPixel(image,p,pixel); 02328 return(MagickTrue); 02329 } 02330 02331 /* 02332 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02333 % % 02334 % % 02335 % % 02336 + G e t P i x e l C a c h e C o l o r s p a c e % 02337 % % 02338 % % 02339 % % 02340 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02341 % 02342 % GetPixelCacheColorspace() returns the class type of the pixel cache. 02343 % 02344 % The format of the GetPixelCacheColorspace() method is: 02345 % 02346 % Colorspace GetPixelCacheColorspace(Cache cache) 02347 % 02348 % A description of each parameter follows: 02349 % 02350 % o cache: the pixel cache. 02351 % 02352 */ 02353 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache) 02354 { 02355 CacheInfo 02356 *cache_info; 02357 02358 assert(cache != (Cache) NULL); 02359 cache_info=(CacheInfo *) cache; 02360 assert(cache_info->signature == MagickSignature); 02361 if (cache_info->debug != MagickFalse) 02362 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 02363 cache_info->filename); 02364 return(cache_info->colorspace); 02365 } 02366 02367 /* 02368 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02369 % % 02370 % % 02371 % % 02372 + G e t P i x e l C a c h e M e t h o d s % 02373 % % 02374 % % 02375 % % 02376 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02377 % 02378 % GetPixelCacheMethods() initializes the CacheMethods structure. 02379 % 02380 % The format of the GetPixelCacheMethods() method is: 02381 % 02382 % void GetPixelCacheMethods(CacheMethods *cache_methods) 02383 % 02384 % A description of each parameter follows: 02385 % 02386 % o cache_methods: Specifies a pointer to a CacheMethods structure. 02387 % 02388 */ 02389 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods) 02390 { 02391 assert(cache_methods != (CacheMethods *) NULL); 02392 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods)); 02393 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache; 02394 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache; 02395 cache_methods->get_virtual_metacontent_from_handler= 02396 GetVirtualMetacontentFromCache; 02397 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache; 02398 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache; 02399 cache_methods->get_authentic_metacontent_from_handler= 02400 GetAuthenticMetacontentFromCache; 02401 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache; 02402 cache_methods->get_one_authentic_pixel_from_handler= 02403 GetOneAuthenticPixelFromCache; 02404 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache; 02405 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache; 02406 cache_methods->destroy_pixel_handler=DestroyImagePixelCache; 02407 } 02408 02409 /* 02410 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02411 % % 02412 % % 02413 % % 02414 + G e t P i x e l C a c h e N e x u s E x t e n t % 02415 % % 02416 % % 02417 % % 02418 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02419 % 02420 % GetPixelCacheNexusExtent() returns the extent of the pixels associated 02421 % corresponding with the last call to SetPixelCacheNexusPixels() or 02422 % GetPixelCacheNexusPixels(). 02423 % 02424 % The format of the GetPixelCacheNexusExtent() method is: 02425 % 02426 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache, 02427 % NexusInfo *nexus_info) 02428 % 02429 % A description of each parameter follows: 02430 % 02431 % o nexus_info: the nexus info. 02432 % 02433 */ 02434 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache, 02435 NexusInfo *nexus_info) 02436 { 02437 CacheInfo 02438 *cache_info; 02439 02440 MagickSizeType 02441 extent; 02442 02443 assert(cache != NULL); 02444 cache_info=(CacheInfo *) cache; 02445 assert(cache_info->signature == MagickSignature); 02446 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height; 02447 if (extent == 0) 02448 return((MagickSizeType) cache_info->columns*cache_info->rows); 02449 return(extent); 02450 } 02451 02452 /* 02453 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02454 % % 02455 % % 02456 % % 02457 + G e t P i x e l C a c h e N e x u s M e t a c o n t e n t % 02458 % % 02459 % % 02460 % % 02461 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02462 % 02463 % GetPixelCacheNexusMetacontent() returns the meta-content for the specified 02464 % cache nexus. 02465 % 02466 % The format of the GetPixelCacheNexusMetacontent() method is: 02467 % 02468 % void *GetPixelCacheNexusMetacontent(const Cache cache, 02469 % NexusInfo *nexus_info) 02470 % 02471 % A description of each parameter follows: 02472 % 02473 % o cache: the pixel cache. 02474 % 02475 % o nexus_info: the cache nexus to return the meta-content. 02476 % 02477 */ 02478 MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache, 02479 NexusInfo *nexus_info) 02480 { 02481 CacheInfo 02482 *cache_info; 02483 02484 assert(cache != NULL); 02485 cache_info=(CacheInfo *) cache; 02486 assert(cache_info->signature == MagickSignature); 02487 if (cache_info->storage_class == UndefinedClass) 02488 return((void *) NULL); 02489 return(nexus_info->metacontent); 02490 } 02491 02492 /* 02493 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02494 % % 02495 % % 02496 % % 02497 + G e t P i x e l C a c h e N e x u s P i x e l s % 02498 % % 02499 % % 02500 % % 02501 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02502 % 02503 % GetPixelCacheNexusPixels() returns the pixels associated with the specified 02504 % cache nexus. 02505 % 02506 % The format of the GetPixelCacheNexusPixels() method is: 02507 % 02508 % Quantum *GetPixelCacheNexusPixels(const Cache cache, 02509 % NexusInfo *nexus_info) 02510 % 02511 % A description of each parameter follows: 02512 % 02513 % o cache: the pixel cache. 02514 % 02515 % o nexus_info: the cache nexus to return the pixels. 02516 % 02517 */ 02518 MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache, 02519 NexusInfo *nexus_info) 02520 { 02521 CacheInfo 02522 *cache_info; 02523 02524 assert(cache != NULL); 02525 cache_info=(CacheInfo *) cache; 02526 assert(cache_info->signature == MagickSignature); 02527 if (cache_info->storage_class == UndefinedClass) 02528 return((Quantum *) NULL); 02529 return(nexus_info->pixels); 02530 } 02531 02532 /* 02533 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02534 % % 02535 % % 02536 % % 02537 + G e t P i x e l C a c h e P i x e l s % 02538 % % 02539 % % 02540 % % 02541 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02542 % 02543 % GetPixelCachePixels() returns the pixels associated with the specified image. 02544 % 02545 % The format of the GetPixelCachePixels() method is: 02546 % 02547 % void *GetPixelCachePixels(Image *image,MagickSizeType *length, 02548 % ExceptionInfo *exception) 02549 % 02550 % A description of each parameter follows: 02551 % 02552 % o image: the image. 02553 % 02554 % o length: the pixel cache length. 02555 % 02556 % o exception: return any errors or warnings in this structure. 02557 % 02558 */ 02559 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length, 02560 ExceptionInfo *exception) 02561 { 02562 CacheInfo 02563 *cache_info; 02564 02565 assert(image != (const Image *) NULL); 02566 assert(image->signature == MagickSignature); 02567 assert(image->cache != (Cache) NULL); 02568 assert(length != (MagickSizeType *) NULL); 02569 assert(exception != (ExceptionInfo *) NULL); 02570 assert(exception->signature == MagickSignature); 02571 cache_info=(CacheInfo *) image->cache; 02572 assert(cache_info->signature == MagickSignature); 02573 *length=0; 02574 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache)) 02575 return((void *) NULL); 02576 *length=cache_info->length; 02577 return((void *) cache_info->pixels); 02578 } 02579 02580 /* 02581 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02582 % % 02583 % % 02584 % % 02585 + G e t P i x e l C a c h e S t o r a g e C l a s s % 02586 % % 02587 % % 02588 % % 02589 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02590 % 02591 % GetPixelCacheStorageClass() returns the class type of the pixel cache. 02592 % 02593 % The format of the GetPixelCacheStorageClass() method is: 02594 % 02595 % ClassType GetPixelCacheStorageClass(Cache cache) 02596 % 02597 % A description of each parameter follows: 02598 % 02599 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass. 02600 % 02601 % o cache: the pixel cache. 02602 % 02603 */ 02604 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache) 02605 { 02606 CacheInfo 02607 *cache_info; 02608 02609 assert(cache != (Cache) NULL); 02610 cache_info=(CacheInfo *) cache; 02611 assert(cache_info->signature == MagickSignature); 02612 if (cache_info->debug != MagickFalse) 02613 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 02614 cache_info->filename); 02615 return(cache_info->storage_class); 02616 } 02617 02618 /* 02619 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02620 % % 02621 % % 02622 % % 02623 + G e t P i x e l C a c h e T i l e S i z e % 02624 % % 02625 % % 02626 % % 02627 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02628 % 02629 % GetPixelCacheTileSize() returns the pixel cache tile size. 02630 % 02631 % The format of the GetPixelCacheTileSize() method is: 02632 % 02633 % void GetPixelCacheTileSize(const Image *image,size_t *width, 02634 % size_t *height) 02635 % 02636 % A description of each parameter follows: 02637 % 02638 % o image: the image. 02639 % 02640 % o width: the optimize cache tile width in pixels. 02641 % 02642 % o height: the optimize cache tile height in pixels. 02643 % 02644 */ 02645 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width, 02646 size_t *height) 02647 { 02648 CacheInfo 02649 *cache_info; 02650 02651 assert(image != (Image *) NULL); 02652 assert(image->signature == MagickSignature); 02653 if (image->debug != MagickFalse) 02654 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 02655 cache_info=(CacheInfo *) image->cache; 02656 assert(cache_info->signature == MagickSignature); 02657 *width=2048UL/(cache_info->number_channels*sizeof(Quantum)); 02658 if (GetPixelCacheType(image) == DiskCache) 02659 *width=8192UL/(cache_info->number_channels*sizeof(Quantum)); 02660 *height=(*width); 02661 } 02662 02663 /* 02664 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02665 % % 02666 % % 02667 % % 02668 + G e t P i x e l C a c h e T y p e % 02669 % % 02670 % % 02671 % % 02672 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02673 % 02674 % GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.). 02675 % 02676 % The format of the GetPixelCacheType() method is: 02677 % 02678 % CacheType GetPixelCacheType(const Image *image) 02679 % 02680 % A description of each parameter follows: 02681 % 02682 % o image: the image. 02683 % 02684 */ 02685 MagickPrivate CacheType GetPixelCacheType(const Image *image) 02686 { 02687 CacheInfo 02688 *cache_info; 02689 02690 assert(image != (Image *) NULL); 02691 assert(image->signature == MagickSignature); 02692 assert(image->cache != (Cache) NULL); 02693 cache_info=(CacheInfo *) image->cache; 02694 assert(cache_info->signature == MagickSignature); 02695 return(cache_info->type); 02696 } 02697 02698 /* 02699 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02700 % % 02701 % % 02702 % % 02703 + G e t P i x e l C a c h e V i r t u a l M e t h o d % 02704 % % 02705 % % 02706 % % 02707 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02708 % 02709 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the 02710 % pixel cache. A virtual pixel is any pixel access that is outside the 02711 % boundaries of the image cache. 02712 % 02713 % The format of the GetPixelCacheVirtualMethod() method is: 02714 % 02715 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image) 02716 % 02717 % A description of each parameter follows: 02718 % 02719 % o image: the image. 02720 % 02721 */ 02722 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image) 02723 { 02724 CacheInfo 02725 *cache_info; 02726 02727 assert(image != (Image *) NULL); 02728 assert(image->signature == MagickSignature); 02729 assert(image->cache != (Cache) NULL); 02730 cache_info=(CacheInfo *) image->cache; 02731 assert(cache_info->signature == MagickSignature); 02732 return(cache_info->virtual_pixel_method); 02733 } 02734 02735 /* 02736 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02737 % % 02738 % % 02739 % % 02740 + G e t V i r t u a l M e t a c o n t e n t F r o m C a c h e % 02741 % % 02742 % % 02743 % % 02744 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02745 % 02746 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with 02747 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache(). 02748 % 02749 % The format of the GetVirtualMetacontentFromCache() method is: 02750 % 02751 % void *GetVirtualMetacontentFromCache(const Image *image) 02752 % 02753 % A description of each parameter follows: 02754 % 02755 % o image: the image. 02756 % 02757 */ 02758 static const void *GetVirtualMetacontentFromCache(const Image *image) 02759 { 02760 CacheInfo 02761 *cache_info; 02762 02763 const int 02764 id = GetOpenMPThreadId(); 02765 02766 const void 02767 *metacontent; 02768 02769 assert(image != (const Image *) NULL); 02770 assert(image->signature == MagickSignature); 02771 assert(image->cache != (Cache) NULL); 02772 cache_info=(CacheInfo *) image->cache; 02773 assert(cache_info->signature == MagickSignature); 02774 assert(id < (int) cache_info->number_threads); 02775 metacontent=GetVirtualMetacontentFromNexus(cache_info, 02776 cache_info->nexus_info[id]); 02777 return(metacontent); 02778 } 02779 02780 /* 02781 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02782 % % 02783 % % 02784 % % 02785 + G e t V i r t u a l M e t a c o n t e n t F r o m N e x u s % 02786 % % 02787 % % 02788 % % 02789 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02790 % 02791 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified 02792 % cache nexus. 02793 % 02794 % The format of the GetVirtualMetacontentFromNexus() method is: 02795 % 02796 % const void *GetVirtualMetacontentFromNexus(const Cache cache, 02797 % NexusInfo *nexus_info) 02798 % 02799 % A description of each parameter follows: 02800 % 02801 % o cache: the pixel cache. 02802 % 02803 % o nexus_info: the cache nexus to return the meta-content. 02804 % 02805 */ 02806 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache, 02807 NexusInfo *nexus_info) 02808 { 02809 CacheInfo 02810 *cache_info; 02811 02812 assert(cache != (Cache) NULL); 02813 cache_info=(CacheInfo *) cache; 02814 assert(cache_info->signature == MagickSignature); 02815 if (cache_info->storage_class == UndefinedClass) 02816 return((void *) NULL); 02817 return(nexus_info->metacontent); 02818 } 02819 02820 /* 02821 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02822 % % 02823 % % 02824 % % 02825 % G e t V i r t u a l M e t a c o n t e n t % 02826 % % 02827 % % 02828 % % 02829 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02830 % 02831 % GetVirtualMetacontent() returns the virtual metacontent corresponding with 02832 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is 02833 % returned if the meta-content are not available. 02834 % 02835 % The format of the GetVirtualMetacontent() method is: 02836 % 02837 % const void *GetVirtualMetacontent(const Image *image) 02838 % 02839 % A description of each parameter follows: 02840 % 02841 % o image: the image. 02842 % 02843 */ 02844 MagickExport const void *GetVirtualMetacontent(const Image *image) 02845 { 02846 CacheInfo 02847 *cache_info; 02848 02849 const int 02850 id = GetOpenMPThreadId(); 02851 02852 const void 02853 *metacontent; 02854 02855 assert(image != (const Image *) NULL); 02856 assert(image->signature == MagickSignature); 02857 assert(image->cache != (Cache) NULL); 02858 cache_info=(CacheInfo *) image->cache; 02859 assert(cache_info->signature == MagickSignature); 02860 if (cache_info->methods.get_virtual_metacontent_from_handler != 02861 (GetVirtualMetacontentFromHandler) NULL) 02862 { 02863 metacontent=cache_info->methods. 02864 get_virtual_metacontent_from_handler(image); 02865 return(metacontent); 02866 } 02867 assert(id < (int) cache_info->number_threads); 02868 metacontent=GetVirtualMetacontentFromNexus(cache_info, 02869 cache_info->nexus_info[id]); 02870 return(metacontent); 02871 } 02872 02873 /* 02874 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02875 % % 02876 % % 02877 % % 02878 + G e t V i r t u a l P i x e l s F r o m N e x u s % 02879 % % 02880 % % 02881 % % 02882 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02883 % 02884 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk 02885 % pixel cache as defined by the geometry parameters. A pointer to the pixels 02886 % is returned if the pixels are transferred, otherwise a NULL is returned. 02887 % 02888 % The format of the GetVirtualPixelsFromNexus() method is: 02889 % 02890 % Quantum *GetVirtualPixelsFromNexus(const Image *image, 02891 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y, 02892 % const size_t columns,const size_t rows,NexusInfo *nexus_info, 02893 % ExceptionInfo *exception) 02894 % 02895 % A description of each parameter follows: 02896 % 02897 % o image: the image. 02898 % 02899 % o virtual_pixel_method: the virtual pixel method. 02900 % 02901 % o x,y,columns,rows: These values define the perimeter of a region of 02902 % pixels. 02903 % 02904 % o nexus_info: the cache nexus to acquire. 02905 % 02906 % o exception: return any errors or warnings in this structure. 02907 % 02908 */ 02909 02910 static ssize_t 02911 DitherMatrix[64] = 02912 { 02913 0, 48, 12, 60, 3, 51, 15, 63, 02914 32, 16, 44, 28, 35, 19, 47, 31, 02915 8, 56, 4, 52, 11, 59, 7, 55, 02916 40, 24, 36, 20, 43, 27, 39, 23, 02917 2, 50, 14, 62, 1, 49, 13, 61, 02918 34, 18, 46, 30, 33, 17, 45, 29, 02919 10, 58, 6, 54, 9, 57, 5, 53, 02920 42, 26, 38, 22, 41, 25, 37, 21 02921 }; 02922 02923 static inline ssize_t DitherX(const ssize_t x,const size_t columns) 02924 { 02925 ssize_t 02926 index; 02927 02928 index=x+DitherMatrix[x & 0x07]-32L; 02929 if (index < 0L) 02930 return(0L); 02931 if (index >= (ssize_t) columns) 02932 return((ssize_t) columns-1L); 02933 return(index); 02934 } 02935 02936 static inline ssize_t DitherY(const ssize_t y,const size_t rows) 02937 { 02938 ssize_t 02939 index; 02940 02941 index=y+DitherMatrix[y & 0x07]-32L; 02942 if (index < 0L) 02943 return(0L); 02944 if (index >= (ssize_t) rows) 02945 return((ssize_t) rows-1L); 02946 return(index); 02947 } 02948 02949 static inline ssize_t EdgeX(const ssize_t x,const size_t columns) 02950 { 02951 if (x < 0L) 02952 return(0L); 02953 if (x >= (ssize_t) columns) 02954 return((ssize_t) (columns-1)); 02955 return(x); 02956 } 02957 02958 static inline ssize_t EdgeY(const ssize_t y,const size_t rows) 02959 { 02960 if (y < 0L) 02961 return(0L); 02962 if (y >= (ssize_t) rows) 02963 return((ssize_t) (rows-1)); 02964 return(y); 02965 } 02966 02967 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns) 02968 { 02969 return((ssize_t) (columns*GetPseudoRandomValue(random_info))); 02970 } 02971 02972 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows) 02973 { 02974 return((ssize_t) (rows*GetPseudoRandomValue(random_info))); 02975 } 02976 02977 static inline MagickModulo VirtualPixelModulo(const ssize_t offset, 02978 const size_t extent) 02979 { 02980 MagickModulo 02981 modulo; 02982 02983 /* 02984 Compute the remainder of dividing offset by extent. It returns not only 02985 the quotient (tile the offset falls in) but also the positive remainer 02986 within that tile such that 0 <= remainder < extent. This method is 02987 essentially a ldiv() using a floored modulo division rather than the 02988 normal default truncated modulo division. 02989 */ 02990 modulo.quotient=offset/(ssize_t) extent; 02991 if (offset < 0L) 02992 modulo.quotient--; 02993 modulo.remainder=offset-modulo.quotient*(ssize_t) extent; 02994 return(modulo); 02995 } 02996 02997 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image, 02998 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y, 02999 const size_t columns,const size_t rows,NexusInfo *nexus_info, 03000 ExceptionInfo *exception) 03001 { 03002 CacheInfo 03003 *cache_info; 03004 03005 MagickOffsetType 03006 offset; 03007 03008 MagickSizeType 03009 length, 03010 number_pixels; 03011 03012 NexusInfo 03013 **virtual_nexus; 03014 03015 Quantum 03016 *pixels, 03017 virtual_pixel[CompositePixelChannel]; 03018 03019 RectangleInfo 03020 region; 03021 03022 register const Quantum 03023 *restrict p; 03024 03025 register const void 03026 *restrict r; 03027 03028 register Quantum 03029 *restrict q; 03030 03031 register ssize_t 03032 i, 03033 u; 03034 03035 register unsigned char 03036 *restrict s; 03037 03038 ssize_t 03039 v; 03040 03041 void 03042 *virtual_metacontent; 03043 03044 /* 03045 Acquire pixels. 03046 */ 03047 assert(image != (const Image *) NULL); 03048 assert(image->signature == MagickSignature); 03049 assert(image->cache != (Cache) NULL); 03050 cache_info=(CacheInfo *) image->cache; 03051 assert(cache_info->signature == MagickSignature); 03052 if (cache_info->type == UndefinedCache) 03053 return((const Quantum *) NULL); 03054 region.x=x; 03055 region.y=y; 03056 region.width=columns; 03057 region.height=rows; 03058 pixels=SetPixelCacheNexusPixels(image,®ion,nexus_info,exception); 03059 if (pixels == (Quantum *) NULL) 03060 return((const Quantum *) NULL); 03061 q=pixels; 03062 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+ 03063 nexus_info->region.x; 03064 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+ 03065 nexus_info->region.width-1L; 03066 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows; 03067 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels)) 03068 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) && 03069 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows)) 03070 { 03071 MagickBooleanType 03072 status; 03073 03074 /* 03075 Pixel request is inside cache extents. 03076 */ 03077 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse) 03078 return(q); 03079 status=ReadPixelCachePixels(cache_info,nexus_info,exception); 03080 if (status == MagickFalse) 03081 return((const Quantum *) NULL); 03082 if (cache_info->metacontent_extent != 0) 03083 { 03084 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception); 03085 if (status == MagickFalse) 03086 return((const Quantum *) NULL); 03087 } 03088 return(q); 03089 } 03090 /* 03091 Pixel request is outside cache extents. 03092 */ 03093 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info); 03094 virtual_nexus=AcquirePixelCacheNexus(1); 03095 if (virtual_nexus == (NexusInfo **) NULL) 03096 { 03097 if (virtual_nexus != (NexusInfo **) NULL) 03098 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1); 03099 (void) ThrowMagickException(exception,GetMagickModule(),CacheError, 03100 "UnableToGetCacheNexus","`%s'",image->filename); 03101 return((const Quantum *) NULL); 03102 } 03103 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels* 03104 sizeof(*virtual_pixel)); 03105 virtual_metacontent=(void *) NULL; 03106 switch (virtual_pixel_method) 03107 { 03108 case BackgroundVirtualPixelMethod: 03109 case BlackVirtualPixelMethod: 03110 case GrayVirtualPixelMethod: 03111 case TransparentVirtualPixelMethod: 03112 case MaskVirtualPixelMethod: 03113 case WhiteVirtualPixelMethod: 03114 case EdgeVirtualPixelMethod: 03115 case CheckerTileVirtualPixelMethod: 03116 case HorizontalTileVirtualPixelMethod: 03117 case VerticalTileVirtualPixelMethod: 03118 { 03119 if (cache_info->metacontent_extent != 0) 03120 { 03121 /* 03122 Acquire a metacontent buffer. 03123 */ 03124 virtual_metacontent=(void *) AcquireQuantumMemory(1, 03125 cache_info->metacontent_extent); 03126 if (virtual_metacontent == (void *) NULL) 03127 { 03128 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1); 03129 (void) ThrowMagickException(exception,GetMagickModule(), 03130 CacheError,"UnableToGetCacheNexus","`%s'",image->filename); 03131 return((const Quantum *) NULL); 03132 } 03133 (void) ResetMagickMemory(virtual_metacontent,0, 03134 cache_info->metacontent_extent); 03135 } 03136 switch (virtual_pixel_method) 03137 { 03138 case BlackVirtualPixelMethod: 03139 { 03140 for (i=0; i < (ssize_t) cache_info->number_channels; i++) 03141 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel); 03142 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel); 03143 break; 03144 } 03145 case GrayVirtualPixelMethod: 03146 { 03147 for (i=0; i < (ssize_t) cache_info->number_channels; i++) 03148 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2, 03149 virtual_pixel); 03150 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel); 03151 break; 03152 } 03153 case TransparentVirtualPixelMethod: 03154 { 03155 for (i=0; i < (ssize_t) cache_info->number_channels; i++) 03156 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel); 03157 SetPixelAlpha(image,TransparentAlpha,virtual_pixel); 03158 break; 03159 } 03160 case MaskVirtualPixelMethod: 03161 case WhiteVirtualPixelMethod: 03162 { 03163 for (i=0; i < (ssize_t) cache_info->number_channels; i++) 03164 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel); 03165 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel); 03166 break; 03167 } 03168 default: 03169 { 03170 SetPixelRed(image,ClampToQuantum(image->background_color.red), 03171 virtual_pixel); 03172 SetPixelGreen(image,ClampToQuantum(image->background_color.green), 03173 virtual_pixel); 03174 SetPixelBlue(image,ClampToQuantum(image->background_color.blue), 03175 virtual_pixel); 03176 if (image->colorspace == CMYKColorspace) 03177 SetPixelBlack(image,ClampToQuantum(image->background_color.black), 03178 virtual_pixel); 03179 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha), 03180 virtual_pixel); 03181 break; 03182 } 03183 } 03184 break; 03185 } 03186 default: 03187 break; 03188 } 03189 for (v=0; v < (ssize_t) rows; v++) 03190 { 03191 for (u=0; u < (ssize_t) columns; u+=length) 03192 { 03193 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u); 03194 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) || 03195 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) || 03196 (length == 0)) 03197 { 03198 MagickModulo 03199 x_modulo, 03200 y_modulo; 03201 03202 /* 03203 Transfer a single pixel. 03204 */ 03205 length=(MagickSizeType) 1; 03206 switch (virtual_pixel_method) 03207 { 03208 default: 03209 { 03210 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method, 03211 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows), 03212 1UL,1UL,*virtual_nexus,exception); 03213 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus); 03214 break; 03215 } 03216 case RandomVirtualPixelMethod: 03217 { 03218 if (cache_info->random_info == (RandomInfo *) NULL) 03219 cache_info->random_info=AcquireRandomInfo(); 03220 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method, 03221 RandomX(cache_info->random_info,cache_info->columns), 03222 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL, 03223 *virtual_nexus,exception); 03224 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus); 03225 break; 03226 } 03227 case DitherVirtualPixelMethod: 03228 { 03229 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method, 03230 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows), 03231 1UL,1UL,*virtual_nexus,exception); 03232 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus); 03233 break; 03234 } 03235 case TileVirtualPixelMethod: 03236 { 03237 x_modulo=VirtualPixelModulo(x+u,cache_info->columns); 03238 y_modulo=VirtualPixelModulo(y+v,cache_info->rows); 03239 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method, 03240 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus, 03241 exception); 03242 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus); 03243 break; 03244 } 03245 case MirrorVirtualPixelMethod: 03246 { 03247 x_modulo=VirtualPixelModulo(x+u,cache_info->columns); 03248 if ((x_modulo.quotient & 0x01) == 1L) 03249 x_modulo.remainder=(ssize_t) cache_info->columns- 03250 x_modulo.remainder-1L; 03251 y_modulo=VirtualPixelModulo(y+v,cache_info->rows); 03252 if ((y_modulo.quotient & 0x01) == 1L) 03253 y_modulo.remainder=(ssize_t) cache_info->rows- 03254 y_modulo.remainder-1L; 03255 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method, 03256 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus, 03257 exception); 03258 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus); 03259 break; 03260 } 03261 case HorizontalTileEdgeVirtualPixelMethod: 03262 { 03263 x_modulo=VirtualPixelModulo(x+u,cache_info->columns); 03264 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method, 03265 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL, 03266 *virtual_nexus,exception); 03267 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus); 03268 break; 03269 } 03270 case VerticalTileEdgeVirtualPixelMethod: 03271 { 03272 y_modulo=VirtualPixelModulo(y+v,cache_info->rows); 03273 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method, 03274 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL, 03275 *virtual_nexus,exception); 03276 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus); 03277 break; 03278 } 03279 case BackgroundVirtualPixelMethod: 03280 case BlackVirtualPixelMethod: 03281 case GrayVirtualPixelMethod: 03282 case TransparentVirtualPixelMethod: 03283 case MaskVirtualPixelMethod: 03284 case WhiteVirtualPixelMethod: 03285 { 03286 p=virtual_pixel; 03287 r=virtual_metacontent; 03288 break; 03289 } 03290 case EdgeVirtualPixelMethod: 03291 case CheckerTileVirtualPixelMethod: 03292 { 03293 x_modulo=VirtualPixelModulo(x+u,cache_info->columns); 03294 y_modulo=VirtualPixelModulo(y+v,cache_info->rows); 03295 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L) 03296 { 03297 p=virtual_pixel; 03298 r=virtual_metacontent; 03299 break; 03300 } 03301 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method, 03302 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus, 03303 exception); 03304 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus); 03305 break; 03306 } 03307 case HorizontalTileVirtualPixelMethod: 03308 { 03309 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) 03310 { 03311 p=virtual_pixel; 03312 r=virtual_metacontent; 03313 break; 03314 } 03315 x_modulo=VirtualPixelModulo(x+u,cache_info->columns); 03316 y_modulo=VirtualPixelModulo(y+v,cache_info->rows); 03317 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method, 03318 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus, 03319 exception); 03320 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus); 03321 break; 03322 } 03323 case VerticalTileVirtualPixelMethod: 03324 { 03325 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) 03326 { 03327 p=virtual_pixel; 03328 r=virtual_metacontent; 03329 break; 03330 } 03331 x_modulo=VirtualPixelModulo(x+u,cache_info->columns); 03332 y_modulo=VirtualPixelModulo(y+v,cache_info->rows); 03333 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method, 03334 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus, 03335 exception); 03336 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus); 03337 break; 03338 } 03339 } 03340 if (p == (const Quantum *) NULL) 03341 break; 03342 (void) memcpy(q,p,(size_t) length*cache_info->number_channels* 03343 sizeof(*p)); 03344 q+=cache_info->number_channels; 03345 if ((s != (void *) NULL) && (r != (const void *) NULL)) 03346 { 03347 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent); 03348 s+=cache_info->metacontent_extent; 03349 } 03350 continue; 03351 } 03352 /* 03353 Transfer a run of pixels. 03354 */ 03355 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t) 03356 length,1UL,*virtual_nexus,exception); 03357 if (p == (const Quantum *) NULL) 03358 break; 03359 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus); 03360 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p)); 03361 q+=length*cache_info->number_channels; 03362 if ((r != (void *) NULL) && (s != (const void *) NULL)) 03363 { 03364 (void) memcpy(s,r,(size_t) length); 03365 s+=length*cache_info->metacontent_extent; 03366 } 03367 } 03368 } 03369 /* 03370 Free resources. 03371 */ 03372 if (virtual_metacontent != (void *) NULL) 03373 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent); 03374 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1); 03375 return(pixels); 03376 } 03377 03378 /* 03379 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 03380 % % 03381 % % 03382 % % 03383 + G e t V i r t u a l P i x e l C a c h e % 03384 % % 03385 % % 03386 % % 03387 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 03388 % 03389 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel 03390 % cache as defined by the geometry parameters. A pointer to the pixels 03391 % is returned if the pixels are transferred, otherwise a NULL is returned. 03392 % 03393 % The format of the GetVirtualPixelCache() method is: 03394 % 03395 % const Quantum *GetVirtualPixelCache(const Image *image, 03396 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x, 03397 % const ssize_t y,const size_t columns,const size_t rows, 03398 % ExceptionInfo *exception) 03399 % 03400 % A description of each parameter follows: 03401 % 03402 % o image: the image. 03403 % 03404 % o virtual_pixel_method: the virtual pixel method. 03405 % 03406 % o x,y,columns,rows: These values define the perimeter of a region of 03407 % pixels. 03408 % 03409 % o exception: return any errors or warnings in this structure. 03410 % 03411 */ 03412 static const Quantum *GetVirtualPixelCache(const Image *image, 03413 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y, 03414 const size_t columns,const size_t rows,ExceptionInfo *exception) 03415 { 03416 CacheInfo 03417 *cache_info; 03418 03419 const int 03420 id = GetOpenMPThreadId(); 03421 03422 const Quantum 03423 *p; 03424 03425 assert(image != (const Image *) NULL); 03426 assert(image->signature == MagickSignature); 03427 assert(image->cache != (Cache) NULL); 03428 cache_info=(CacheInfo *) image->cache; 03429 assert(cache_info->signature == MagickSignature); 03430 assert(id < (int) cache_info->number_threads); 03431 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows, 03432 cache_info->nexus_info[id],exception); 03433 return(p); 03434 } 03435 03436 /* 03437 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 03438 % % 03439 % % 03440 % % 03441 % G e t V i r t u a l P i x e l Q u e u e % 03442 % % 03443 % % 03444 % % 03445 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 03446 % 03447 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding 03448 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). 03449 % 03450 % The format of the GetVirtualPixelQueue() method is: 03451 % 03452 % const Quantum *GetVirtualPixelQueue(const Image image) 03453 % 03454 % A description of each parameter follows: 03455 % 03456 % o image: the image. 03457 % 03458 */ 03459 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image) 03460 { 03461 CacheInfo 03462 *cache_info; 03463 03464 const int 03465 id = GetOpenMPThreadId(); 03466 03467 assert(image != (const Image *) NULL); 03468 assert(image->signature == MagickSignature); 03469 assert(image->cache != (Cache) NULL); 03470 cache_info=(CacheInfo *) image->cache; 03471 assert(cache_info->signature == MagickSignature); 03472 if (cache_info->methods.get_virtual_pixels_handler != 03473 (GetVirtualPixelsHandler) NULL) 03474 return(cache_info->methods.get_virtual_pixels_handler(image)); 03475 assert(id < (int) cache_info->number_threads); 03476 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id])); 03477 } 03478 03479 /* 03480 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 03481 % % 03482 % % 03483 % % 03484 % G e t V i r t u a l P i x e l s % 03485 % % 03486 % % 03487 % % 03488 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 03489 % 03490 % GetVirtualPixels() returns an immutable pixel region. If the 03491 % region is successfully accessed, a pointer to it is returned, otherwise 03492 % NULL is returned. The returned pointer may point to a temporary working 03493 % copy of the pixels or it may point to the original pixels in memory. 03494 % Performance is maximized if the selected region is part of one row, or one 03495 % or more full rows, since there is opportunity to access the pixels in-place 03496 % (without a copy) if the image is in memory, or in a memory-mapped file. The 03497 % returned pointer must *never* be deallocated by the user. 03498 % 03499 % Pixels accessed via the returned pointer represent a simple array of type 03500 % Quantum. If the image type is CMYK or the storage class is PseudoClass, 03501 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to 03502 % access the meta-content (of type void) corresponding to the the 03503 % region. 03504 % 03505 % If you plan to modify the pixels, use GetAuthenticPixels() instead. 03506 % 03507 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread- 03508 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or 03509 % GetCacheViewAuthenticPixels() instead. 03510 % 03511 % The format of the GetVirtualPixels() method is: 03512 % 03513 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x, 03514 % const ssize_t y,const size_t columns,const size_t rows, 03515 % ExceptionInfo *exception) 03516 % 03517 % A description of each parameter follows: 03518 % 03519 % o image: the image. 03520 % 03521 % o x,y,columns,rows: These values define the perimeter of a region of 03522 % pixels. 03523 % 03524 % o exception: return any errors or warnings in this structure. 03525 % 03526 */ 03527 MagickExport const Quantum *GetVirtualPixels(const Image *image, 03528 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows, 03529 ExceptionInfo *exception) 03530 { 03531 CacheInfo 03532 *cache_info; 03533 03534 const int 03535 id = GetOpenMPThreadId(); 03536 03537 const Quantum 03538 *p; 03539 03540 assert(image != (const Image *) NULL); 03541 assert(image->signature == MagickSignature); 03542 assert(image->cache != (Cache) NULL); 03543 cache_info=(CacheInfo *) image->cache; 03544 assert(cache_info->signature == MagickSignature); 03545 if (cache_info->methods.get_virtual_pixel_handler != 03546 (GetVirtualPixelHandler) NULL) 03547 return(cache_info->methods.get_virtual_pixel_handler(image, 03548 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception)); 03549 assert(id < (int) cache_info->number_threads); 03550 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y, 03551 columns,rows,cache_info->nexus_info[id],exception); 03552 return(p); 03553 } 03554 03555 /* 03556 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 03557 % % 03558 % % 03559 % % 03560 + G e t V i r t u a l P i x e l s F r o m C a c h e % 03561 % % 03562 % % 03563 % % 03564 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 03565 % 03566 % GetVirtualPixelsCache() returns the pixels associated corresponding with the 03567 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache(). 03568 % 03569 % The format of the GetVirtualPixelsCache() method is: 03570 % 03571 % Quantum *GetVirtualPixelsCache(const Image *image) 03572 % 03573 % A description of each parameter follows: 03574 % 03575 % o image: the image. 03576 % 03577 */ 03578 static const Quantum *GetVirtualPixelsCache(const Image *image) 03579 { 03580 CacheInfo 03581 *cache_info; 03582 03583 const int 03584 id = GetOpenMPThreadId(); 03585 03586 assert(image != (const Image *) NULL); 03587 assert(image->signature == MagickSignature); 03588 assert(image->cache != (Cache) NULL); 03589 cache_info=(CacheInfo *) image->cache; 03590 assert(cache_info->signature == MagickSignature); 03591 assert(id < (int) cache_info->number_threads); 03592 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id])); 03593 } 03594 03595 /* 03596 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 03597 % % 03598 % % 03599 % % 03600 + G e t V i r t u a l P i x e l s N e x u s % 03601 % % 03602 % % 03603 % % 03604 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 03605 % 03606 % GetVirtualPixelsNexus() returns the pixels associated with the specified 03607 % cache nexus. 03608 % 03609 % The format of the GetVirtualPixelsNexus() method is: 03610 % 03611 % const Quantum *GetVirtualPixelsNexus(const Cache cache, 03612 % NexusInfo *nexus_info) 03613 % 03614 % A description of each parameter follows: 03615 % 03616 % o cache: the pixel cache. 03617 % 03618 % o nexus_info: the cache nexus to return the colormap pixels. 03619 % 03620 */ 03621 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache, 03622 NexusInfo *nexus_info) 03623 { 03624 CacheInfo 03625 *cache_info; 03626 03627 assert(cache != (Cache) NULL); 03628 cache_info=(CacheInfo *) cache; 03629 assert(cache_info->signature == MagickSignature); 03630 if (cache_info->storage_class == UndefinedClass) 03631 return((Quantum *) NULL); 03632 return((const Quantum *) nexus_info->pixels); 03633 } 03634 03635 /* 03636 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 03637 % % 03638 % % 03639 % % 03640 + O p e n P i x e l C a c h e % 03641 % % 03642 % % 03643 % % 03644 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 03645 % 03646 % OpenPixelCache() allocates the pixel cache. This includes defining the cache 03647 % dimensions, allocating space for the image pixels and optionally the 03648 % metacontent, and memory mapping the cache if it is disk based. The cache 03649 % nexus array is initialized as well. 03650 % 03651 % The format of the OpenPixelCache() method is: 03652 % 03653 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode, 03654 % ExceptionInfo *exception) 03655 % 03656 % A description of each parameter follows: 03657 % 03658 % o image: the image. 03659 % 03660 % o mode: ReadMode, WriteMode, or IOMode. 03661 % 03662 % o exception: return any errors or warnings in this structure. 03663 % 03664 */ 03665 03666 static inline void AllocatePixelCachePixels(CacheInfo *cache_info) 03667 { 03668 cache_info->mapped=MagickFalse; 03669 cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t) 03670 cache_info->length); 03671 if (cache_info->pixels == (Quantum *) NULL) 03672 { 03673 cache_info->mapped=MagickTrue; 03674 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t) 03675 cache_info->length); 03676 } 03677 } 03678 03679 static MagickBooleanType ExtendCache(Image *image,MagickSizeType length) 03680 { 03681 CacheInfo 03682 *cache_info; 03683 03684 MagickOffsetType 03685 count, 03686 extent, 03687 offset; 03688 03689 cache_info=(CacheInfo *) image->cache; 03690 if (image->debug != MagickFalse) 03691 { 03692 char 03693 format[MaxTextExtent], 03694 message[MaxTextExtent]; 03695 03696 (void) FormatMagickSize(length,MagickFalse,format); 03697 (void) FormatLocaleString(message,MaxTextExtent, 03698 "extend %s (%s[%d], disk, %s)",cache_info->filename, 03699 cache_info->cache_filename,cache_info->file,format); 03700 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message); 03701 } 03702 if (length != (MagickSizeType) ((MagickOffsetType) length)) 03703 return(MagickFalse); 03704 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END); 03705 if (extent < 0) 03706 return(MagickFalse); 03707 if ((MagickSizeType) extent >= length) 03708 return(MagickTrue); 03709 offset=(MagickOffsetType) length-1; 03710 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) ""); 03711 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse); 03712 } 03713 03714 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode, 03715 ExceptionInfo *exception) 03716 { 03717 CacheInfo 03718 *cache_info, 03719 source_info; 03720 03721 char 03722 format[MaxTextExtent], 03723 message[MaxTextExtent]; 03724 03725 MagickBooleanType 03726 status; 03727 03728 MagickSizeType 03729 length, 03730 number_pixels; 03731 03732 PixelChannelMap 03733 *p, 03734 *q; 03735 03736 size_t 03737 columns, 03738 packet_size; 03739 03740 assert(image != (const Image *) NULL); 03741 assert(image->signature == MagickSignature); 03742 assert(image->cache != (Cache) NULL); 03743 if (image->debug != MagickFalse) 03744 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 03745 if ((image->columns == 0) || (image->rows == 0)) 03746 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename); 03747 cache_info=(CacheInfo *) image->cache; 03748 assert(cache_info->signature == MagickSignature); 03749 source_info=(*cache_info); 03750 source_info.file=(-1); 03751 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]", 03752 image->filename,(double) GetImageIndexInList(image)); 03753 cache_info->storage_class=image->storage_class; 03754 cache_info->colorspace=image->colorspace; 03755 cache_info->matte=image->matte; 03756 cache_info->mask=image->mask; 03757 cache_info->rows=image->rows; 03758 cache_info->columns=image->columns; 03759 InitializePixelChannelMap(image); 03760 cache_info->number_channels=GetPixelChannels(image); 03761 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels* 03762 sizeof(*image->channel_map)); 03763 cache_info->metacontent_extent=image->metacontent_extent; 03764 cache_info->mode=mode; 03765 if (image->ping != MagickFalse) 03766 { 03767 cache_info->type=PingCache; 03768 cache_info->pixels=(Quantum *) NULL; 03769 cache_info->metacontent=(void *) NULL; 03770 cache_info->length=0; 03771 return(MagickTrue); 03772 } 03773 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows; 03774 packet_size=cache_info->number_channels*sizeof(Quantum); 03775 if (image->metacontent_extent != 0) 03776 packet_size+=cache_info->metacontent_extent; 03777 length=number_pixels*packet_size; 03778 columns=(size_t) (length/cache_info->rows/packet_size); 03779 if (cache_info->columns != columns) 03780 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed", 03781 image->filename); 03782 cache_info->length=length; 03783 p=cache_info->channel_map; 03784 q=source_info.channel_map; 03785 if ((cache_info->type != UndefinedCache) && 03786 (cache_info->columns <= source_info.columns) && 03787 (cache_info->rows <= source_info.rows) && 03788 (cache_info->number_channels <= source_info.number_channels) && 03789 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) && 03790 (cache_info->metacontent_extent <= source_info.metacontent_extent)) 03791 { 03792 /* 03793 Inline pixel cache clone optimization. 03794 */ 03795 if ((cache_info->columns == source_info.columns) && 03796 (cache_info->rows == source_info.rows) && 03797 (cache_info->number_channels == source_info.number_channels) && 03798 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) && 03799 (cache_info->metacontent_extent == source_info.metacontent_extent)) 03800 return(MagickTrue); 03801 return(ClonePixelCachePixels(cache_info,&source_info,exception)); 03802 } 03803 status=AcquireMagickResource(AreaResource,cache_info->length); 03804 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+ 03805 cache_info->metacontent_extent); 03806 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length))) 03807 { 03808 status=AcquireMagickResource(MemoryResource,cache_info->length); 03809 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) || 03810 (cache_info->type == MemoryCache)) 03811 { 03812 AllocatePixelCachePixels(cache_info); 03813 if (cache_info->pixels == (Quantum *) NULL) 03814 cache_info->pixels=source_info.pixels; 03815 else 03816 { 03817 /* 03818 Create memory pixel cache. 03819 */ 03820 status=MagickTrue; 03821 if (image->debug != MagickFalse) 03822 { 03823 (void) FormatMagickSize(cache_info->length,MagickTrue,format); 03824 (void) FormatLocaleString(message,MaxTextExtent, 03825 "open %s (%s memory, %.20gx%.20gx%.20g %s)", 03826 cache_info->filename,cache_info->mapped != MagickFalse ? 03827 "anonymous" : "heap",(double) cache_info->columns,(double) 03828 cache_info->rows,(double) cache_info->number_channels, 03829 format); 03830 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s", 03831 message); 03832 } 03833 cache_info->type=MemoryCache; 03834 cache_info->metacontent=(void *) NULL; 03835 if (cache_info->metacontent_extent != 0) 03836 cache_info->metacontent=(void *) (cache_info->pixels+ 03837 number_pixels*cache_info->number_channels); 03838 if ((source_info.storage_class != UndefinedClass) && 03839 (mode != ReadMode)) 03840 { 03841 status=ClonePixelCachePixels(cache_info,&source_info, 03842 exception); 03843 RelinquishPixelCachePixels(&source_info); 03844 } 03845 return(status); 03846 } 03847 } 03848 RelinquishMagickResource(MemoryResource,cache_info->length); 03849 } 03850 /* 03851 Create pixel cache on disk. 03852 */ 03853 status=AcquireMagickResource(DiskResource,cache_info->length); 03854 if (status == MagickFalse) 03855 { 03856 (void) ThrowMagickException(exception,GetMagickModule(),CacheError, 03857 "CacheResourcesExhausted","`%s'",image->filename); 03858 return(MagickFalse); 03859 } 03860 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode)) 03861 { 03862 (void) ClosePixelCacheOnDisk(cache_info); 03863 *cache_info->cache_filename='\0'; 03864 } 03865 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse) 03866 { 03867 RelinquishMagickResource(DiskResource,cache_info->length); 03868 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache", 03869 image->filename); 03870 return(MagickFalse); 03871 } 03872 status=ExtendCache(image,(MagickSizeType) cache_info->offset+ 03873 cache_info->length); 03874 if (status == MagickFalse) 03875 { 03876 ThrowFileException(exception,CacheError,"UnableToExtendCache", 03877 image->filename); 03878 return(MagickFalse); 03879 } 03880 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+ 03881 cache_info->metacontent_extent); 03882 if (length != (MagickSizeType) ((size_t) length)) 03883 cache_info->type=DiskCache; 03884 else 03885 { 03886 status=AcquireMagickResource(MapResource,cache_info->length); 03887 if ((status == MagickFalse) && (cache_info->type != MapCache) && 03888 (cache_info->type != MemoryCache)) 03889 cache_info->type=DiskCache; 03890 else 03891 { 03892 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode, 03893 cache_info->offset,(size_t) cache_info->length); 03894 if (cache_info->pixels == (Quantum *) NULL) 03895 { 03896 cache_info->type=DiskCache; 03897 cache_info->pixels=source_info.pixels; 03898 } 03899 else 03900 { 03901 /* 03902 Create file-backed memory-mapped pixel cache. 03903 */ 03904 status=MagickTrue; 03905 (void) ClosePixelCacheOnDisk(cache_info); 03906 cache_info->type=MapCache; 03907 cache_info->mapped=MagickTrue; 03908 cache_info->metacontent=(void *) NULL; 03909 if (cache_info->metacontent_extent != 0) 03910 cache_info->metacontent=(void *) (cache_info->pixels+ 03911 number_pixels*cache_info->number_channels); 03912 if ((source_info.storage_class != UndefinedClass) && 03913 (mode != ReadMode)) 03914 { 03915 status=ClonePixelCachePixels(cache_info,&source_info, 03916 exception); 03917 RelinquishPixelCachePixels(&source_info); 03918 } 03919 if (image->debug != MagickFalse