1/* 2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3% % 4% % 5% % 6% CCCC AAA CCCC H H EEEEE % 7% C A A C H H E % 8% C AAAAA C HHHHH EEE % 9% C A A C H H E % 10% CCCC A A CCCC H H EEEEE % 11% % 12% % 13% MagickCore Pixel Cache Methods % 14% % 15% Software Design % 16% Cristy % 17% July 1999 % 18% % 19% % 20% Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization % 21% dedicated to making software imaging solutions freely available. % 22% % 23% You may not use this file except in compliance with the License. You may % 24% obtain a copy of the License at % 25% % 26% http://www.imagemagick.org/script/license.php % 27% % 28% Unless required by applicable law or agreed to in writing, software % 29% distributed under the License is distributed on an "AS IS" BASIS, % 30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 31% See the License for the specific language governing permissions and % 32% limitations under the License. % 33% % 34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 35% 36% 37% 38*/ 39 40/* 41 Include declarations. 42*/ 43#include "MagickCore/studio.h" 44#include "MagickCore/blob.h" 45#include "MagickCore/blob-private.h" 46#include "MagickCore/cache.h" 47#include "MagickCore/cache-private.h" 48#include "MagickCore/color-private.h" 49#include "MagickCore/colorspace-private.h" 50#include "MagickCore/composite-private.h" 51#include "MagickCore/distribute-cache-private.h" 52#include "MagickCore/exception.h" 53#include "MagickCore/exception-private.h" 54#include "MagickCore/geometry.h" 55#include "MagickCore/list.h" 56#include "MagickCore/log.h" 57#include "MagickCore/magick.h" 58#include "MagickCore/memory_.h" 59#include "MagickCore/memory-private.h" 60#include "MagickCore/nt-base-private.h" 61#include "MagickCore/option.h" 62#include "MagickCore/pixel.h" 63#include "MagickCore/pixel-accessor.h" 64#include "MagickCore/policy.h" 65#include "MagickCore/quantum.h" 66#include "MagickCore/random_.h" 67#include "MagickCore/registry.h" 68#include "MagickCore/resource_.h" 69#include "MagickCore/semaphore.h" 70#include "MagickCore/splay-tree.h" 71#include "MagickCore/string_.h" 72#include "MagickCore/string-private.h" 73#include "MagickCore/thread-private.h" 74#include "MagickCore/utility.h" 75#include "MagickCore/utility-private.h" 76#if defined(MAGICKCORE_ZLIB_DELEGATE) 77#include "zlib.h" 78#endif 79 80/* 81 Define declarations. 82*/ 83#define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent) 84#define IsFileDescriptorLimitExceeded() (GetMagickResource(FileResource) > \ 85 GetMagickResourceLimit(FileResource) ? MagickTrue : MagickFalse) 86 87/* 88 Typedef declarations. 89*/ 90typedef struct _MagickModulo 91{ 92 ssize_t 93 quotient, 94 remainder; 95} MagickModulo; 96 97/* 98 Forward declarations. 99*/ 100#if defined(__cplusplus) || defined(c_plusplus) 101extern "C" { 102#endif 103 104static Cache 105 GetImagePixelCache(Image *,const MagickBooleanType,ExceptionInfo *) 106 magick_hot_spot; 107 108static const Quantum 109 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t, 110 const ssize_t,const size_t,const size_t,ExceptionInfo *), 111 *GetVirtualPixelsCache(const Image *); 112 113static const void 114 *GetVirtualMetacontentFromCache(const Image *); 115 116static MagickBooleanType 117 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,Quantum *, 118 ExceptionInfo *), 119 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod, 120 const ssize_t,const ssize_t,Quantum *,ExceptionInfo *), 121 OpenPixelCache(Image *,const MapMode,ExceptionInfo *), 122 OpenPixelCacheOnDisk(CacheInfo *,const MapMode), 123 ReadPixelCachePixels(CacheInfo *magick_restrict,NexusInfo *magick_restrict, 124 ExceptionInfo *), 125 ReadPixelCacheMetacontent(CacheInfo *magick_restrict, 126 NexusInfo *magick_restrict,ExceptionInfo *), 127 SyncAuthenticPixelsCache(Image *,ExceptionInfo *), 128 WritePixelCachePixels(CacheInfo *magick_restrict,NexusInfo *magick_restrict, 129 ExceptionInfo *), 130 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *magick_restrict, 131 ExceptionInfo *); 132 133static Quantum 134 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t, 135 const size_t,ExceptionInfo *), 136 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t, 137 const size_t,ExceptionInfo *), 138 *SetPixelCacheNexusPixels(const CacheInfo *,const MapMode, 139 const RectangleInfo *,NexusInfo *,ExceptionInfo *) magick_hot_spot; 140 141#if defined(MAGICKCORE_OPENCL_SUPPORT) 142static void 143 CopyOpenCLBuffer(CacheInfo *magick_restrict); 144#endif 145 146#if defined(__cplusplus) || defined(c_plusplus) 147} 148#endif 149 150/* 151 Global declarations. 152*/ 153static volatile MagickBooleanType 154 instantiate_cache = MagickFalse; 155 156static SemaphoreInfo 157 *cache_semaphore = (SemaphoreInfo *) NULL; 158 159static time_t 160 cache_epoch = 0; 161 162/* 163%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 164% % 165% % 166% % 167+ A c q u i r e P i x e l C a c h e % 168% % 169% % 170% % 171%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 172% 173% AcquirePixelCache() acquires a pixel cache. 174% 175% The format of the AcquirePixelCache() method is: 176% 177% Cache AcquirePixelCache(const size_t number_threads) 178% 179% A description of each parameter follows: 180% 181% o number_threads: the number of nexus threads. 182% 183*/ 184MagickPrivate Cache AcquirePixelCache(const size_t number_threads) 185{ 186 CacheInfo 187 *magick_restrict cache_info; 188 189 char 190 *synchronize; 191 192 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info)); 193 if (cache_info == (CacheInfo *) NULL) 194 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 195 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info)); 196 cache_info->type=UndefinedCache; 197 cache_info->mode=IOMode; 198 cache_info->colorspace=sRGBColorspace; 199 cache_info->file=(-1); 200 cache_info->id=GetMagickThreadId(); 201 cache_info->number_threads=number_threads; 202 if (GetOpenMPMaximumThreads() > cache_info->number_threads) 203 cache_info->number_threads=GetOpenMPMaximumThreads(); 204 if (GetMagickResourceLimit(ThreadResource) > cache_info->number_threads) 205 cache_info->number_threads=(size_t) GetMagickResourceLimit(ThreadResource); 206 if (cache_info->number_threads == 0) 207 cache_info->number_threads=1; 208 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads); 209 if (cache_info->nexus_info == (NexusInfo **) NULL) 210 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 211 synchronize=GetEnvironmentValue("MAGICK_SYNCHRONIZE"); 212 if (synchronize != (const char *) NULL) 213 { 214 cache_info->synchronize=IsStringTrue(synchronize); 215 synchronize=DestroyString(synchronize); 216 } 217 cache_info->semaphore=AcquireSemaphoreInfo(); 218 cache_info->reference_count=1; 219 cache_info->file_semaphore=AcquireSemaphoreInfo(); 220 cache_info->debug=IsEventLogging(); 221 cache_info->signature=MagickCoreSignature; 222 return((Cache ) cache_info); 223} 224 225/* 226%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 227% % 228% % 229% % 230% A c q u i r e P i x e l C a c h e N e x u s % 231% % 232% % 233% % 234%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 235% 236% AcquirePixelCacheNexus() allocates the NexusInfo structure. 237% 238% The format of the AcquirePixelCacheNexus method is: 239% 240% NexusInfo **AcquirePixelCacheNexus(const size_t number_threads) 241% 242% A description of each parameter follows: 243% 244% o number_threads: the number of nexus threads. 245% 246*/ 247MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads) 248{ 249 NexusInfo 250 **magick_restrict nexus_info; 251 252 register ssize_t 253 i; 254 255 nexus_info=(NexusInfo **) MagickAssumeAligned(AcquireAlignedMemory( 256 number_threads,sizeof(*nexus_info))); 257 if (nexus_info == (NexusInfo **) NULL) 258 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 259 nexus_info[0]=(NexusInfo *) AcquireQuantumMemory(number_threads, 260 sizeof(**nexus_info)); 261 if (nexus_info[0] == (NexusInfo *) NULL) 262 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 263 (void) ResetMagickMemory(nexus_info[0],0,number_threads*sizeof(**nexus_info)); 264 for (i=0; i < (ssize_t) number_threads; i++) 265 { 266 nexus_info[i]=(&nexus_info[0][i]); 267 nexus_info[i]->signature=MagickCoreSignature; 268 } 269 return(nexus_info); 270} 271 272/* 273%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 274% % 275% % 276% % 277+ A c q u i r e P i x e l C a c h e P i x e l s % 278% % 279% % 280% % 281%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 282% 283% AcquirePixelCachePixels() returns the pixels associated with the specified 284% image. 285% 286% The format of the AcquirePixelCachePixels() method is: 287% 288% const void *AcquirePixelCachePixels(const Image *image, 289% MagickSizeType *length,ExceptionInfo *exception) 290% 291% A description of each parameter follows: 292% 293% o image: the image. 294% 295% o length: the pixel cache length. 296% 297% o exception: return any errors or warnings in this structure. 298% 299*/ 300MagickPrivate const void *AcquirePixelCachePixels(const Image *image, 301 MagickSizeType *length,ExceptionInfo *exception) 302{ 303 CacheInfo 304 *magick_restrict cache_info; 305 306 assert(image != (const Image *) NULL); 307 assert(image->signature == MagickCoreSignature); 308 assert(exception != (ExceptionInfo *) NULL); 309 assert(exception->signature == MagickCoreSignature); 310 assert(image->cache != (Cache) NULL); 311 cache_info=(CacheInfo *) image->cache; 312 assert(cache_info->signature == MagickCoreSignature); 313 *length=0; 314 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache)) 315 return((const void *) NULL); 316 *length=cache_info->length; 317 return((const void *) cache_info->pixels); 318} 319 320/* 321%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 322% % 323% % 324% % 325+ C a c h e C o m p o n e n t G e n e s i s % 326% % 327% % 328% % 329%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 330% 331% CacheComponentGenesis() instantiates the cache component. 332% 333% The format of the CacheComponentGenesis method is: 334% 335% MagickBooleanType CacheComponentGenesis(void) 336% 337*/ 338MagickPrivate MagickBooleanType CacheComponentGenesis(void) 339{ 340 if (cache_semaphore == (SemaphoreInfo *) NULL) 341 cache_semaphore=AcquireSemaphoreInfo(); 342 return(MagickTrue); 343} 344 345/* 346%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 347% % 348% % 349% % 350+ C a c h e C o m p o n e n t T e r m i n u s % 351% % 352% % 353% % 354%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 355% 356% CacheComponentTerminus() destroys the cache component. 357% 358% The format of the CacheComponentTerminus() method is: 359% 360% CacheComponentTerminus(void) 361% 362*/ 363MagickPrivate void CacheComponentTerminus(void) 364{ 365 if (cache_semaphore == (SemaphoreInfo *) NULL) 366 ActivateSemaphoreInfo(&cache_semaphore); 367 LockSemaphoreInfo(cache_semaphore); 368 instantiate_cache=MagickFalse; 369 UnlockSemaphoreInfo(cache_semaphore); 370 RelinquishSemaphoreInfo(&cache_semaphore); 371} 372 373/* 374%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 375% % 376% % 377% % 378+ C l o n e P i x e l C a c h e % 379% % 380% % 381% % 382%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 383% 384% ClonePixelCache() clones a pixel cache. 385% 386% The format of the ClonePixelCache() method is: 387% 388% Cache ClonePixelCache(const Cache cache) 389% 390% A description of each parameter follows: 391% 392% o cache: the pixel cache. 393% 394*/ 395MagickPrivate Cache ClonePixelCache(const Cache cache) 396{ 397 CacheInfo 398 *magick_restrict clone_info; 399 400 const CacheInfo 401 *magick_restrict cache_info; 402 403 assert(cache != NULL); 404 cache_info=(const CacheInfo *) cache; 405 assert(cache_info->signature == MagickCoreSignature); 406 if (cache_info->debug != MagickFalse) 407 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 408 cache_info->filename); 409 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads); 410 if (clone_info == (Cache) NULL) 411 return((Cache) NULL); 412 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method; 413 return((Cache ) clone_info); 414} 415 416/* 417%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 418% % 419% % 420% % 421+ C l o n e P i x e l C a c h e M e t h o d s % 422% % 423% % 424% % 425%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 426% 427% ClonePixelCacheMethods() clones the pixel cache methods from one cache to 428% another. 429% 430% The format of the ClonePixelCacheMethods() method is: 431% 432% void ClonePixelCacheMethods(Cache clone,const Cache cache) 433% 434% A description of each parameter follows: 435% 436% o clone: Specifies a pointer to a Cache structure. 437% 438% o cache: the pixel cache. 439% 440*/ 441MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache) 442{ 443 CacheInfo 444 *magick_restrict cache_info, 445 *magick_restrict source_info; 446 447 assert(clone != (Cache) NULL); 448 source_info=(CacheInfo *) clone; 449 assert(source_info->signature == MagickCoreSignature); 450 if (source_info->debug != MagickFalse) 451 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 452 source_info->filename); 453 assert(cache != (Cache) NULL); 454 cache_info=(CacheInfo *) cache; 455 assert(cache_info->signature == MagickCoreSignature); 456 source_info->methods=cache_info->methods; 457} 458 459/* 460%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 461% % 462% % 463% % 464+ C l o n e P i x e l C a c h e R e p o s i t o r y % 465% % 466% % 467% % 468%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 469% ClonePixelCacheRepository() clones the source pixel cache to the destination 470% cache. 471% 472% The format of the ClonePixelCacheRepository() method is: 473% 474% MagickBooleanType ClonePixelCacheRepository(CacheInfo *cache_info, 475% CacheInfo *source_info,ExceptionInfo *exception) 476% 477% A description of each parameter follows: 478% 479% o cache_info: the pixel cache. 480% 481% o source_info: the source pixel cache. 482% 483% o exception: return any errors or warnings in this structure. 484% 485*/ 486 487static MagickBooleanType ClonePixelCacheOnDisk( 488 CacheInfo *magick_restrict cache_info,CacheInfo *magick_restrict clone_info) 489{ 490 MagickSizeType 491 extent; 492 493 size_t 494 quantum; 495 496 ssize_t 497 count; 498 499 struct stat 500 file_stats; 501 502 unsigned char 503 *buffer; 504 505 /* 506 Clone pixel cache on disk with identifcal morphology. 507 */ 508 if ((OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse) || 509 (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)) 510 return(MagickFalse); 511 quantum=(size_t) MagickMaxBufferExtent; 512 if ((fstat(cache_info->file,&file_stats) == 0) && (file_stats.st_size > 0)) 513 quantum=(size_t) MagickMin(file_stats.st_size,MagickMaxBufferExtent); 514 buffer=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*buffer)); 515 if (buffer == (unsigned char *) NULL) 516 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 517 extent=0; 518 while ((count=read(cache_info->file,buffer,quantum)) > 0) 519 { 520 ssize_t 521 number_bytes; 522 523 number_bytes=write(clone_info->file,buffer,(size_t) count); 524 if (number_bytes != count) 525 break; 526 extent+=number_bytes; 527 } 528 buffer=(unsigned char *) RelinquishMagickMemory(buffer); 529 if (extent != cache_info->length) 530 return(MagickFalse); 531 return(MagickTrue); 532} 533 534static MagickBooleanType ClonePixelCacheRepository( 535 CacheInfo *magick_restrict clone_info,CacheInfo *magick_restrict cache_info, 536 ExceptionInfo *exception) 537{ 538#define MaxCacheThreads 2 539#define cache_threads(source,destination) \ 540 num_threads(((source)->type == DiskCache) || \ 541 ((destination)->type == DiskCache) || (((source)->rows) < \ 542 (16*GetMagickResourceLimit(ThreadResource))) ? 1 : \ 543 GetMagickResourceLimit(ThreadResource) < MaxCacheThreads ? \ 544 GetMagickResourceLimit(ThreadResource) : MaxCacheThreads) 545 546 MagickBooleanType 547 optimize, 548 status; 549 550 NexusInfo 551 **magick_restrict cache_nexus, 552 **magick_restrict clone_nexus; 553 554 size_t 555 length; 556 557 ssize_t 558 y; 559 560 assert(cache_info != (CacheInfo *) NULL); 561 assert(clone_info != (CacheInfo *) NULL); 562 assert(exception != (ExceptionInfo *) NULL); 563 if (cache_info->type == PingCache) 564 return(MagickTrue); 565 length=cache_info->number_channels*sizeof(*cache_info->channel_map); 566 if ((cache_info->columns == clone_info->columns) && 567 (cache_info->rows == clone_info->rows) && 568 (cache_info->number_channels == clone_info->number_channels) && 569 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) && 570 (cache_info->metacontent_extent == clone_info->metacontent_extent)) 571 { 572 /* 573 Identical pixel cache morphology. 574 */ 575 if (((cache_info->type == MemoryCache) || 576 (cache_info->type == MapCache)) && 577 ((clone_info->type == MemoryCache) || 578 (clone_info->type == MapCache))) 579 { 580 (void) memcpy(clone_info->pixels,cache_info->pixels, 581 cache_info->columns*cache_info->number_channels*cache_info->rows* 582 sizeof(*cache_info->pixels)); 583 if ((cache_info->metacontent_extent != 0) && 584 (clone_info->metacontent_extent != 0)) 585 (void) memcpy(clone_info->metacontent,cache_info->metacontent, 586 cache_info->columns*cache_info->rows* 587 clone_info->metacontent_extent*sizeof(unsigned char)); 588 return(MagickTrue); 589 } 590 if ((cache_info->type == DiskCache) && (clone_info->type == DiskCache)) 591 return(ClonePixelCacheOnDisk(cache_info,clone_info)); 592 } 593 /* 594 Mismatched pixel cache morphology. 595 */ 596 cache_nexus=AcquirePixelCacheNexus(MaxCacheThreads); 597 clone_nexus=AcquirePixelCacheNexus(MaxCacheThreads); 598 if ((cache_nexus == (NexusInfo **) NULL) || 599 (clone_nexus == (NexusInfo **) NULL)) 600 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 601 length=cache_info->number_channels*sizeof(*cache_info->channel_map); 602 optimize=(cache_info->number_channels == clone_info->number_channels) && 603 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) ? 604 MagickTrue : MagickFalse; 605 length=(size_t) MagickMin(cache_info->columns*cache_info->number_channels, 606 clone_info->columns*clone_info->number_channels); 607 status=MagickTrue; 608#if defined(MAGICKCORE_OPENMP_SUPPORT) 609 #pragma omp parallel for schedule(static,4) shared(status) \ 610 cache_threads(cache_info,clone_info) 611#endif 612 for (y=0; y < (ssize_t) cache_info->rows; y++) 613 { 614 const int 615 id = GetOpenMPThreadId(); 616 617 Quantum 618 *pixels; 619 620 RectangleInfo 621 region; 622 623 register ssize_t 624 x; 625 626 if (status == MagickFalse) 627 continue; 628 if (y >= (ssize_t) clone_info->rows) 629 continue; 630 region.width=cache_info->columns; 631 region.height=1; 632 region.x=0; 633 region.y=y; 634 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion, 635 cache_nexus[id],exception); 636 if (pixels == (Quantum *) NULL) 637 continue; 638 status=ReadPixelCachePixels(cache_info,cache_nexus[id],exception); 639 if (status == MagickFalse) 640 continue; 641 region.width=clone_info->columns; 642 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,®ion, 643 clone_nexus[id],exception); 644 if (pixels == (Quantum *) NULL) 645 continue; 646 (void) ResetMagickMemory(clone_nexus[id]->pixels,0,(size_t) 647 clone_nexus[id]->length); 648 if (optimize != MagickFalse) 649 (void) memcpy(clone_nexus[id]->pixels,cache_nexus[id]->pixels,length* 650 sizeof(Quantum)); 651 else 652 { 653 register const Quantum 654 *magick_restrict p; 655 656 register Quantum 657 *magick_restrict q; 658 659 /* 660 Mismatched pixel channel map. 661 */ 662 p=cache_nexus[id]->pixels; 663 q=clone_nexus[id]->pixels; 664 for (x=0; x < (ssize_t) cache_info->columns; x++) 665 { 666 register ssize_t 667 i; 668 669 if (x == (ssize_t) clone_info->columns) 670 break; 671 for (i=0; i < (ssize_t) clone_info->number_channels; i++) 672 { 673 PixelChannel 674 channel; 675 676 PixelTrait 677 traits; 678 679 channel=clone_info->channel_map[i].channel; 680 traits=cache_info->channel_map[channel].traits; 681 if (traits != UndefinedPixelTrait) 682 *q=*(p+cache_info->channel_map[channel].offset); 683 q++; 684 } 685 p+=cache_info->number_channels; 686 } 687 } 688 status=WritePixelCachePixels(clone_info,clone_nexus[id],exception); 689 } 690 if ((cache_info->metacontent_extent != 0) && 691 (clone_info->metacontent_extent != 0)) 692 { 693 /* 694 Clone metacontent. 695 */ 696 length=(size_t) MagickMin(cache_info->metacontent_extent, 697 clone_info->metacontent_extent); 698#if defined(MAGICKCORE_OPENMP_SUPPORT) 699 #pragma omp parallel for schedule(static,4) shared(status) \ 700 cache_threads(cache_info,clone_info) 701#endif 702 for (y=0; y < (ssize_t) cache_info->rows; y++) 703 { 704 const int 705 id = GetOpenMPThreadId(); 706 707 Quantum 708 *pixels; 709 710 RectangleInfo 711 region; 712 713 if (status == MagickFalse) 714 continue; 715 if (y >= (ssize_t) clone_info->rows) 716 continue; 717 region.width=cache_info->columns; 718 region.height=1; 719 region.x=0; 720 region.y=y; 721 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion, 722 cache_nexus[id],exception); 723 if (pixels == (Quantum *) NULL) 724 continue; 725 status=ReadPixelCacheMetacontent(cache_info,cache_nexus[id],exception); 726 if (status == MagickFalse) 727 continue; 728 region.width=clone_info->columns; 729 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,®ion, 730 clone_nexus[id],exception); 731 if (pixels == (Quantum *) NULL) 732 continue; 733 if ((clone_nexus[id]->metacontent != (void *) NULL) && 734 (cache_nexus[id]->metacontent != (void *) NULL)) 735 (void) memcpy(clone_nexus[id]->metacontent, 736 cache_nexus[id]->metacontent,length*sizeof(unsigned char)); 737 status=WritePixelCacheMetacontent(clone_info,clone_nexus[id],exception); 738 } 739 } 740 cache_nexus=DestroyPixelCacheNexus(cache_nexus,MaxCacheThreads); 741 clone_nexus=DestroyPixelCacheNexus(clone_nexus,MaxCacheThreads); 742 if (cache_info->debug != MagickFalse) 743 { 744 char 745 message[MagickPathExtent]; 746 747 (void) FormatLocaleString(message,MagickPathExtent,"%s => %s", 748 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) cache_info->type), 749 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) clone_info->type)); 750 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message); 751 } 752 return(status); 753} 754 755/* 756%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 757% % 758% % 759% % 760+ D e s t r o y I m a g e P i x e l C a c h e % 761% % 762% % 763% % 764%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 765% 766% DestroyImagePixelCache() deallocates memory associated with the pixel cache. 767% 768% The format of the DestroyImagePixelCache() method is: 769% 770% void DestroyImagePixelCache(Image *image) 771% 772% A description of each parameter follows: 773% 774% o image: the image. 775% 776*/ 777static void DestroyImagePixelCache(Image *image) 778{ 779 assert(image != (Image *) NULL); 780 assert(image->signature == MagickCoreSignature); 781 if (image->debug != MagickFalse) 782 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 783 if (image->cache == (void *) NULL) 784 return; 785 image->cache=DestroyPixelCache(image->cache); 786} 787 788/* 789%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 790% % 791% % 792% % 793+ D e s t r o y I m a g e P i x e l s % 794% % 795% % 796% % 797%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 798% 799% DestroyImagePixels() deallocates memory associated with the pixel cache. 800% 801% The format of the DestroyImagePixels() method is: 802% 803% void DestroyImagePixels(Image *image) 804% 805% A description of each parameter follows: 806% 807% o image: the image. 808% 809*/ 810MagickExport void DestroyImagePixels(Image *image) 811{ 812 CacheInfo 813 *magick_restrict cache_info; 814 815 assert(image != (const Image *) NULL); 816 assert(image->signature == MagickCoreSignature); 817 if (image->debug != MagickFalse) 818 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 819 assert(image->cache != (Cache) NULL); 820 cache_info=(CacheInfo *) image->cache; 821 assert(cache_info->signature == MagickCoreSignature); 822 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL) 823 { 824 cache_info->methods.destroy_pixel_handler(image); 825 return; 826 } 827 image->cache=DestroyPixelCache(image->cache); 828} 829 830/* 831%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 832% % 833% % 834% % 835+ D e s t r o y P i x e l C a c h e % 836% % 837% % 838% % 839%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 840% 841% DestroyPixelCache() deallocates memory associated with the pixel cache. 842% 843% The format of the DestroyPixelCache() method is: 844% 845% Cache DestroyPixelCache(Cache cache) 846% 847% A description of each parameter follows: 848% 849% o cache: the pixel cache. 850% 851*/ 852 853static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info) 854{ 855 int 856 status; 857 858 status=(-1); 859 if (cache_info->file != -1) 860 { 861 status=close(cache_info->file); 862 cache_info->file=(-1); 863 RelinquishMagickResource(FileResource,1); 864 } 865 return(status == -1 ? MagickFalse : MagickTrue); 866} 867 868static inline void RelinquishPixelCachePixels(CacheInfo *cache_info) 869{ 870 switch (cache_info->type) 871 { 872 case MemoryCache: 873 { 874#if defined(MAGICKCORE_OPENCL_SUPPORT) 875 if (cache_info->opencl != (MagickCLCacheInfo) NULL) 876 { 877 cache_info->opencl=RelinquishMagickCLCacheInfo(cache_info->opencl, 878 MagickTrue); 879 cache_info->pixels=(Quantum *) NULL; 880 break; 881 } 882#endif 883 if (cache_info->mapped == MagickFalse) 884 cache_info->pixels=RelinquishAlignedMemory(cache_info->pixels); 885 else 886 (void) UnmapBlob(cache_info->pixels,(size_t) cache_info->length); 887 RelinquishMagickResource(MemoryResource,cache_info->length); 888 break; 889 } 890 case MapCache: 891 { 892 (void) UnmapBlob(cache_info->pixels,(size_t) cache_info->length); 893 cache_info->pixels=(Quantum *) NULL; 894 if (cache_info->mode != ReadMode) 895 (void) RelinquishUniqueFileResource(cache_info->cache_filename); 896 *cache_info->cache_filename='\0'; 897 RelinquishMagickResource(MapResource,cache_info->length); 898 } 899 case DiskCache: 900 { 901 if (cache_info->file != -1) 902 (void) ClosePixelCacheOnDisk(cache_info); 903 if (cache_info->mode != ReadMode) 904 (void) RelinquishUniqueFileResource(cache_info->cache_filename); 905 *cache_info->cache_filename='\0'; 906 RelinquishMagickResource(DiskResource,cache_info->length); 907 break; 908 } 909 case DistributedCache: 910 { 911 *cache_info->cache_filename='\0'; 912 (void) RelinquishDistributePixelCache((DistributeCacheInfo *) 913 cache_info->server_info); 914 break; 915 } 916 default: 917 break; 918 } 919 cache_info->type=UndefinedCache; 920 cache_info->mapped=MagickFalse; 921 cache_info->metacontent=(void *) NULL; 922} 923 924MagickPrivate Cache DestroyPixelCache(Cache cache) 925{ 926 CacheInfo 927 *magick_restrict cache_info; 928 929 assert(cache != (Cache) NULL); 930 cache_info=(CacheInfo *) cache; 931 assert(cache_info->signature == MagickCoreSignature); 932 if (cache_info->debug != MagickFalse) 933 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 934 cache_info->filename); 935 LockSemaphoreInfo(cache_info->semaphore); 936 cache_info->reference_count--; 937 if (cache_info->reference_count != 0) 938 { 939 UnlockSemaphoreInfo(cache_info->semaphore); 940 return((Cache) NULL); 941 } 942 UnlockSemaphoreInfo(cache_info->semaphore); 943 if (cache_info->debug != MagickFalse) 944 { 945 char 946 message[MagickPathExtent]; 947 948 (void) FormatLocaleString(message,MagickPathExtent,"destroy %s", 949 cache_info->filename); 950 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message); 951 } 952 RelinquishPixelCachePixels(cache_info); 953 if (cache_info->server_info != (DistributeCacheInfo *) NULL) 954 cache_info->server_info=DestroyDistributeCacheInfo((DistributeCacheInfo *) 955 cache_info->server_info); 956 if (cache_info->nexus_info != (NexusInfo **) NULL) 957 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info, 958 cache_info->number_threads); 959 if (cache_info->random_info != (RandomInfo *) NULL) 960 cache_info->random_info=DestroyRandomInfo(cache_info->random_info); 961 if (cache_info->file_semaphore != (SemaphoreInfo *) NULL) 962 RelinquishSemaphoreInfo(&cache_info->file_semaphore); 963 if (cache_info->semaphore != (SemaphoreInfo *) NULL) 964 RelinquishSemaphoreInfo(&cache_info->semaphore); 965 cache_info->signature=(~MagickCoreSignature); 966 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info); 967 cache=(Cache) NULL; 968 return(cache); 969} 970 971/* 972%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 973% % 974% % 975% % 976+ D e s t r o y P i x e l C a c h e N e x u s % 977% % 978% % 979% % 980%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 981% 982% DestroyPixelCacheNexus() destroys a pixel cache nexus. 983% 984% The format of the DestroyPixelCacheNexus() method is: 985% 986% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info, 987% const size_t number_threads) 988% 989% A description of each parameter follows: 990% 991% o nexus_info: the nexus to destroy. 992% 993% o number_threads: the number of nexus threads. 994% 995*/ 996 997static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info) 998{ 999 if (nexus_info->mapped == MagickFalse) 1000 (void) RelinquishAlignedMemory(nexus_info->cache); 1001 else 1002 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length); 1003 nexus_info->cache=(Quantum *) NULL; 1004 nexus_info->pixels=(Quantum *) NULL; 1005 nexus_info->metacontent=(void *) NULL; 1006 nexus_info->length=0; 1007 nexus_info->mapped=MagickFalse; 1008} 1009 1010MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info, 1011 const size_t number_threads) 1012{ 1013 register ssize_t 1014 i; 1015 1016 assert(nexus_info != (NexusInfo **) NULL); 1017 for (i=0; i < (ssize_t) number_threads; i++) 1018 { 1019 if (nexus_info[i]->cache != (Quantum *) NULL) 1020 RelinquishCacheNexusPixels(nexus_info[i]); 1021 nexus_info[i]->signature=(~MagickCoreSignature); 1022 } 1023 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]); 1024 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info); 1025 return(nexus_info); 1026} 1027 1028/* 1029%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1030% % 1031% % 1032% % 1033% G e t A u t h e n t i c M e t a c o n t e n t % 1034% % 1035% % 1036% % 1037%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1038% 1039% GetAuthenticMetacontent() returns the authentic metacontent corresponding 1040% with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is 1041% returned if the associated pixels are not available. 1042% 1043% The format of the GetAuthenticMetacontent() method is: 1044% 1045% void *GetAuthenticMetacontent(const Image *image) 1046% 1047% A description of each parameter follows: 1048% 1049% o image: the image. 1050% 1051*/ 1052MagickExport void *GetAuthenticMetacontent(const Image *image) 1053{ 1054 CacheInfo 1055 *magick_restrict cache_info; 1056 1057 const int 1058 id = GetOpenMPThreadId(); 1059 1060 assert(image != (const Image *) NULL); 1061 assert(image->signature == MagickCoreSignature); 1062 assert(image->cache != (Cache) NULL); 1063 cache_info=(CacheInfo *) image->cache; 1064 assert(cache_info->signature == MagickCoreSignature); 1065 if (cache_info->methods.get_authentic_metacontent_from_handler != 1066 (GetAuthenticMetacontentFromHandler) NULL) 1067 { 1068 void 1069 *metacontent; 1070 1071 metacontent=cache_info->methods. 1072 get_authentic_metacontent_from_handler(image); 1073 return(metacontent); 1074 } 1075 assert(id < (int) cache_info->number_threads); 1076 return(cache_info->nexus_info[id]->metacontent); 1077} 1078 1079/* 1080%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1081% % 1082% % 1083% % 1084+ 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 % 1085% % 1086% % 1087% % 1088%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1089% 1090% GetAuthenticMetacontentFromCache() returns the meta-content corresponding 1091% with the last call to QueueAuthenticPixelsCache() or 1092% GetAuthenticPixelsCache(). 1093% 1094% The format of the GetAuthenticMetacontentFromCache() method is: 1095% 1096% void *GetAuthenticMetacontentFromCache(const Image *image) 1097% 1098% A description of each parameter follows: 1099% 1100% o image: the image. 1101% 1102*/ 1103static void *GetAuthenticMetacontentFromCache(const Image *image) 1104{ 1105 CacheInfo 1106 *magick_restrict cache_info; 1107 1108 const int 1109 id = GetOpenMPThreadId(); 1110 1111 assert(image != (const Image *) NULL); 1112 assert(image->signature == MagickCoreSignature); 1113 assert(image->cache != (Cache) NULL); 1114 cache_info=(CacheInfo *) image->cache; 1115 assert(cache_info->signature == MagickCoreSignature); 1116 assert(id < (int) cache_info->number_threads); 1117 return(cache_info->nexus_info[id]->metacontent); 1118} 1119 1120#if defined(MAGICKCORE_OPENCL_SUPPORT) 1121/* 1122%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1123% % 1124% % 1125% % 1126+ G e t A u t h e n t i c O p e n C L B u f f e r % 1127% % 1128% % 1129% % 1130%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1131% 1132% GetAuthenticOpenCLBuffer() returns an OpenCL buffer used to execute OpenCL 1133% operations. 1134% 1135% The format of the GetAuthenticOpenCLBuffer() method is: 1136% 1137% cl_mem GetAuthenticOpenCLBuffer(const Image *image, 1138% MagickCLDevice device,ExceptionInfo *exception) 1139% 1140% A description of each parameter follows: 1141% 1142% o image: the image. 1143% 1144% o device: the device to use. 1145% 1146% o exception: return any errors or warnings in this structure. 1147% 1148*/ 1149MagickPrivate cl_mem GetAuthenticOpenCLBuffer(const Image *image, 1150 MagickCLDevice device,ExceptionInfo *exception) 1151{ 1152 CacheInfo 1153 *magick_restrict cache_info; 1154 1155 cl_int 1156 status; 1157 1158 assert(image != (const Image *) NULL); 1159 assert(device != (const MagickCLDevice) NULL); 1160 cache_info=(CacheInfo *) image->cache; 1161 if (cache_info->type == UndefinedCache) 1162 SyncImagePixelCache((Image *) image,exception); 1163 if ((cache_info->type != MemoryCache) || (cache_info->mapped != MagickFalse)) 1164 return((cl_mem) NULL); 1165 if ((cache_info->opencl != (MagickCLCacheInfo) NULL) && 1166 (cache_info->opencl->device->context != device->context)) 1167 cache_info->opencl=CopyMagickCLCacheInfo(cache_info->opencl); 1168 if (cache_info->opencl == (MagickCLCacheInfo) NULL) 1169 { 1170 assert(cache_info->pixels != (Quantum *) NULL); 1171 cache_info->opencl=AcquireMagickCLCacheInfo(device,cache_info->pixels, 1172 cache_info->length); 1173 if (cache_info->opencl == (MagickCLCacheInfo) NULL) 1174 return((cl_mem) NULL); 1175 } 1176 assert(cache_info->opencl->pixels == cache_info->pixels); 1177 return(cache_info->opencl->buffer); 1178} 1179#endif 1180 1181/* 1182%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1183% % 1184% % 1185% % 1186+ 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 % 1187% % 1188% % 1189% % 1190%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1191% 1192% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or 1193% disk pixel cache as defined by the geometry parameters. A pointer to the 1194% pixels is returned if the pixels are transferred, otherwise a NULL is 1195% returned. 1196% 1197% The format of the GetAuthenticPixelCacheNexus() method is: 1198% 1199% Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x, 1200% const ssize_t y,const size_t columns,const size_t rows, 1201% NexusInfo *nexus_info,ExceptionInfo *exception) 1202% 1203% A description of each parameter follows: 1204% 1205% o image: the image. 1206% 1207% o x,y,columns,rows: These values define the perimeter of a region of 1208% pixels. 1209% 1210% o nexus_info: the cache nexus to return. 1211% 1212% o exception: return any errors or warnings in this structure. 1213% 1214*/ 1215 1216MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x, 1217 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info, 1218 ExceptionInfo *exception) 1219{ 1220 CacheInfo 1221 *magick_restrict cache_info; 1222 1223 Quantum 1224 *magick_restrict pixels; 1225 1226 /* 1227 Transfer pixels from the cache. 1228 */ 1229 assert(image != (Image *) NULL); 1230 assert(image->signature == MagickCoreSignature); 1231 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue, 1232 nexus_info,exception); 1233 if (pixels == (Quantum *) NULL) 1234 return((Quantum *) NULL); 1235 cache_info=(CacheInfo *) image->cache; 1236 assert(cache_info->signature == MagickCoreSignature); 1237 if (nexus_info->authentic_pixel_cache != MagickFalse) 1238 return(pixels); 1239 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse) 1240 return((Quantum *) NULL); 1241 if (cache_info->metacontent_extent != 0) 1242 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse) 1243 return((Quantum *) NULL); 1244 return(pixels); 1245} 1246 1247/* 1248%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1249% % 1250% % 1251% % 1252+ 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 % 1253% % 1254% % 1255% % 1256%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1257% 1258% GetAuthenticPixelsFromCache() returns the pixels associated with the last 1259% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods. 1260% 1261% The format of the GetAuthenticPixelsFromCache() method is: 1262% 1263% Quantum *GetAuthenticPixelsFromCache(const Image image) 1264% 1265% A description of each parameter follows: 1266% 1267% o image: the image. 1268% 1269*/ 1270static Quantum *GetAuthenticPixelsFromCache(const Image *image) 1271{ 1272 CacheInfo 1273 *magick_restrict cache_info; 1274 1275 const int 1276 id = GetOpenMPThreadId(); 1277 1278 assert(image != (const Image *) NULL); 1279 assert(image->signature == MagickCoreSignature); 1280 assert(image->cache != (Cache) NULL); 1281 cache_info=(CacheInfo *) image->cache; 1282 assert(cache_info->signature == MagickCoreSignature); 1283 assert(id < (int) cache_info->number_threads); 1284 return(cache_info->nexus_info[id]->pixels); 1285} 1286 1287/* 1288%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1289% % 1290% % 1291% % 1292% G e t A u t h e n t i c P i x e l Q u e u e % 1293% % 1294% % 1295% % 1296%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1297% 1298% GetAuthenticPixelQueue() returns the authentic pixels associated 1299% corresponding with the last call to QueueAuthenticPixels() or 1300% GetAuthenticPixels(). 1301% 1302% The format of the GetAuthenticPixelQueue() method is: 1303% 1304% Quantum *GetAuthenticPixelQueue(const Image image) 1305% 1306% A description of each parameter follows: 1307% 1308% o image: the image. 1309% 1310*/ 1311MagickExport Quantum *GetAuthenticPixelQueue(const Image *image) 1312{ 1313 CacheInfo 1314 *magick_restrict cache_info; 1315 1316 const int 1317 id = GetOpenMPThreadId(); 1318 1319 assert(image != (const Image *) NULL); 1320 assert(image->signature == MagickCoreSignature); 1321 assert(image->cache != (Cache) NULL); 1322 cache_info=(CacheInfo *) image->cache; 1323 assert(cache_info->signature == MagickCoreSignature); 1324 if (cache_info->methods.get_authentic_pixels_from_handler != 1325 (GetAuthenticPixelsFromHandler) NULL) 1326 return(cache_info->methods.get_authentic_pixels_from_handler(image)); 1327 assert(id < (int) cache_info->number_threads); 1328 return(cache_info->nexus_info[id]->pixels); 1329} 1330 1331/* 1332%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1333% % 1334% % 1335% % 1336% G e t A u t h e n t i c P i x e l s % 1337% % 1338% % 1339% % 1340%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1341% 1342% GetAuthenticPixels() obtains a pixel region for read/write access. If the 1343% region is successfully accessed, a pointer to a Quantum array 1344% representing the region is returned, otherwise NULL is returned. 1345% 1346% The returned pointer may point to a temporary working copy of the pixels 1347% or it may point to the original pixels in memory. Performance is maximized 1348% if the selected region is part of one row, or one or more full rows, since 1349% then there is opportunity to access the pixels in-place (without a copy) 1350% if the image is in memory, or in a memory-mapped file. The returned pointer 1351% must *never* be deallocated by the user. 1352% 1353% Pixels accessed via the returned pointer represent a simple array of type 1354% Quantum. If the image has corresponding metacontent,call 1355% GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the 1356% meta-content corresponding to the region. Once the Quantum array has 1357% been updated, the changes must be saved back to the underlying image using 1358% SyncAuthenticPixels() or they may be lost. 1359% 1360% The format of the GetAuthenticPixels() method is: 1361% 1362% Quantum *GetAuthenticPixels(Image *image,const ssize_t x, 1363% const ssize_t y,const size_t columns,const size_t rows, 1364% ExceptionInfo *exception) 1365% 1366% A description of each parameter follows: 1367% 1368% o image: the image. 1369% 1370% o x,y,columns,rows: These values define the perimeter of a region of 1371% pixels. 1372% 1373% o exception: return any errors or warnings in this structure. 1374% 1375*/ 1376MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x, 1377 const ssize_t y,const size_t columns,const size_t rows, 1378 ExceptionInfo *exception) 1379{ 1380 CacheInfo 1381 *magick_restrict cache_info; 1382 1383 const int 1384 id = GetOpenMPThreadId(); 1385 1386 Quantum 1387 *pixels; 1388 1389 assert(image != (Image *) NULL); 1390 assert(image->signature == MagickCoreSignature); 1391 assert(image->cache != (Cache) NULL); 1392 cache_info=(CacheInfo *) image->cache; 1393 assert(cache_info->signature == MagickCoreSignature); 1394 if (cache_info->methods.get_authentic_pixels_handler != 1395 (GetAuthenticPixelsHandler) NULL) 1396 { 1397 pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns, 1398 rows,exception); 1399 return(pixels); 1400 } 1401 assert(id < (int) cache_info->number_threads); 1402 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows, 1403 cache_info->nexus_info[id],exception); 1404 return(pixels); 1405} 1406 1407/* 1408%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1409% % 1410% % 1411% % 1412+ G e t A u t h e n t i c P i x e l s C a c h e % 1413% % 1414% % 1415% % 1416%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1417% 1418% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache 1419% as defined by the geometry parameters. A pointer to the pixels is returned 1420% if the pixels are transferred, otherwise a NULL is returned. 1421% 1422% The format of the GetAuthenticPixelsCache() method is: 1423% 1424% Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x, 1425% const ssize_t y,const size_t columns,const size_t rows, 1426% ExceptionInfo *exception) 1427% 1428% A description of each parameter follows: 1429% 1430% o image: the image. 1431% 1432% o x,y,columns,rows: These values define the perimeter of a region of 1433% pixels. 1434% 1435% o exception: return any errors or warnings in this structure. 1436% 1437*/ 1438static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x, 1439 const ssize_t y,const size_t columns,const size_t rows, 1440 ExceptionInfo *exception) 1441{ 1442 CacheInfo 1443 *magick_restrict cache_info; 1444 1445 const int 1446 id = GetOpenMPThreadId(); 1447 1448 Quantum 1449 *magick_restrict pixels; 1450 1451 assert(image != (const Image *) NULL); 1452 assert(image->signature == MagickCoreSignature); 1453 assert(image->cache != (Cache) NULL); 1454 cache_info=(CacheInfo *) image->cache; 1455 if (cache_info == (Cache) NULL) 1456 return((Quantum *) NULL); 1457 assert(cache_info->signature == MagickCoreSignature); 1458 assert(id < (int) cache_info->number_threads); 1459 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows, 1460 cache_info->nexus_info[id],exception); 1461 return(pixels); 1462} 1463 1464/* 1465%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1466% % 1467% % 1468% % 1469+ G e t I m a g e E x t e n t % 1470% % 1471% % 1472% % 1473%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1474% 1475% GetImageExtent() returns the extent of the pixels associated corresponding 1476% with the last call to QueueAuthenticPixels() or GetAuthenticPixels(). 1477% 1478% The format of the GetImageExtent() method is: 1479% 1480% MagickSizeType GetImageExtent(const Image *image) 1481% 1482% A description of each parameter follows: 1483% 1484% o image: the image. 1485% 1486*/ 1487MagickExport MagickSizeType GetImageExtent(const Image *image) 1488{ 1489 CacheInfo 1490 *magick_restrict cache_info; 1491 1492 const int 1493 id = GetOpenMPThreadId(); 1494 1495 assert(image != (Image *) NULL); 1496 assert(image->signature == MagickCoreSignature); 1497 if (image->debug != MagickFalse) 1498 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 1499 assert(image->cache != (Cache) NULL); 1500 cache_info=(CacheInfo *) image->cache; 1501 assert(cache_info->signature == MagickCoreSignature); 1502 assert(id < (int) cache_info->number_threads); 1503 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id])); 1504} 1505 1506/* 1507%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1508% % 1509% % 1510% % 1511+ G e t I m a g e P i x e l C a c h e % 1512% % 1513% % 1514% % 1515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1516% 1517% GetImagePixelCache() ensures that there is only a single reference to the 1518% pixel cache to be modified, updating the provided cache pointer to point to 1519% a clone of the original pixel cache if necessary. 1520% 1521% The format of the GetImagePixelCache method is: 1522% 1523% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone, 1524% ExceptionInfo *exception) 1525% 1526% A description of each parameter follows: 1527% 1528% o image: the image. 1529% 1530% o clone: any value other than MagickFalse clones the cache pixels. 1531% 1532% o exception: return any errors or warnings in this structure. 1533% 1534*/ 1535 1536static inline MagickBooleanType ValidatePixelCacheMorphology( 1537 const Image *magick_restrict image) 1538{ 1539 const CacheInfo 1540 *magick_restrict cache_info; 1541 1542 const PixelChannelMap 1543 *magick_restrict p, 1544 *magick_restrict q; 1545 1546 /* 1547 Does the image match the pixel cache morphology? 1548 */ 1549 cache_info=(CacheInfo *) image->cache; 1550 p=image->channel_map; 1551 q=cache_info->channel_map; 1552 if ((image->storage_class != cache_info->storage_class) || 1553 (image->colorspace != cache_info->colorspace) || 1554 (image->alpha_trait != cache_info->alpha_trait) || 1555 (image->read_mask != cache_info->read_mask) || 1556 (image->write_mask != cache_info->write_mask) || 1557 (image->columns != cache_info->columns) || 1558 (image->rows != cache_info->rows) || 1559 (image->number_channels != cache_info->number_channels) || 1560 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) || 1561 (image->metacontent_extent != cache_info->metacontent_extent) || 1562 (cache_info->nexus_info == (NexusInfo **) NULL)) 1563 return(MagickFalse); 1564 return(MagickTrue); 1565} 1566 1567static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone, 1568 ExceptionInfo *exception) 1569{ 1570 CacheInfo 1571 *magick_restrict cache_info; 1572 1573 MagickBooleanType 1574 destroy, 1575 status; 1576 1577 static MagickSizeType 1578 cache_timelimit = MagickResourceInfinity, 1579 cpu_throttle = MagickResourceInfinity, 1580 cycles = 0; 1581 1582 status=MagickTrue; 1583 if (cpu_throttle == MagickResourceInfinity) 1584 cpu_throttle=GetMagickResourceLimit(ThrottleResource); 1585 if ((cpu_throttle != 0) && ((cycles++ % 32) == 0)) 1586 MagickDelay(cpu_throttle); 1587 if (cache_epoch == 0) 1588 { 1589 /* 1590 Set the expire time in seconds. 1591 */ 1592 cache_timelimit=GetMagickResourceLimit(TimeResource); 1593 cache_epoch=time((time_t *) NULL); 1594 } 1595 if ((cache_timelimit != MagickResourceInfinity) && 1596 ((MagickSizeType) (time((time_t *) NULL)-cache_epoch) >= cache_timelimit)) 1597 { 1598#if defined(ECANCELED) 1599 errno=ECANCELED; 1600#endif 1601 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded"); 1602 } 1603 LockSemaphoreInfo(image->semaphore); 1604 assert(image->cache != (Cache) NULL); 1605 cache_info=(CacheInfo *) image->cache; 1606#if defined(MAGICKCORE_OPENCL_SUPPORT) 1607 CopyOpenCLBuffer(cache_info); 1608#endif 1609 destroy=MagickFalse; 1610 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode)) 1611 { 1612 LockSemaphoreInfo(cache_info->semaphore); 1613 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode)) 1614 { 1615 CacheInfo 1616 *clone_info; 1617 1618 Image 1619 clone_image; 1620 1621 /* 1622 Clone pixel cache. 1623 */ 1624 clone_image=(*image); 1625 clone_image.semaphore=AcquireSemaphoreInfo(); 1626 clone_image.reference_count=1; 1627 clone_image.cache=ClonePixelCache(cache_info); 1628 clone_info=(CacheInfo *) clone_image.cache; 1629 status=OpenPixelCache(&clone_image,IOMode,exception); 1630 if (status != MagickFalse) 1631 { 1632 if (clone != MagickFalse) 1633 status=ClonePixelCacheRepository(clone_info,cache_info, 1634 exception); 1635 if (status != MagickFalse) 1636 { 1637 if (cache_info->reference_count == 1) 1638 cache_info->nexus_info=(NexusInfo **) NULL; 1639 destroy=MagickTrue; 1640 image->cache=clone_image.cache; 1641 } 1642 } 1643 RelinquishSemaphoreInfo(&clone_image.semaphore); 1644 } 1645 UnlockSemaphoreInfo(cache_info->semaphore); 1646 } 1647 if (destroy != MagickFalse) 1648 cache_info=(CacheInfo *) DestroyPixelCache(cache_info); 1649 if (status != MagickFalse) 1650 { 1651 /* 1652 Ensure the image matches the pixel cache morphology. 1653 */ 1654 image->type=UndefinedType; 1655 if (ValidatePixelCacheMorphology(image) == MagickFalse) 1656 { 1657 status=OpenPixelCache(image,IOMode,exception); 1658 cache_info=(CacheInfo *) image->cache; 1659 if (cache_info->type == DiskCache) 1660 (void) ClosePixelCacheOnDisk(cache_info); 1661 } 1662 } 1663 UnlockSemaphoreInfo(image->semaphore); 1664 if (status == MagickFalse) 1665 return((Cache) NULL); 1666 return(image->cache); 1667} 1668 1669/* 1670%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1671% % 1672% % 1673% % 1674+ G e t I m a g e P i x e l C a c h e T y p e % 1675% % 1676% % 1677% % 1678%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1679% 1680% GetImagePixelCacheType() returns the pixel cache type: UndefinedCache, 1681% DiskCache, MemoryCache, MapCache, or PingCache. 1682% 1683% The format of the GetImagePixelCacheType() method is: 1684% 1685% CacheType GetImagePixelCacheType(const Image *image) 1686% 1687% A description of each parameter follows: 1688% 1689% o image: the image. 1690% 1691*/ 1692MagickExport CacheType GetImagePixelCacheType(const Image *image) 1693{ 1694 CacheInfo 1695 *magick_restrict cache_info; 1696 1697 assert(image != (Image *) NULL); 1698 assert(image->signature == MagickCoreSignature); 1699 assert(image->cache != (Cache) NULL); 1700 cache_info=(CacheInfo *) image->cache; 1701 assert(cache_info->signature == MagickCoreSignature); 1702 return(cache_info->type); 1703} 1704 1705/* 1706%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1707% % 1708% % 1709% % 1710% G e t O n e A u t h e n t i c P i x e l % 1711% % 1712% % 1713% % 1714%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1715% 1716% GetOneAuthenticPixel() returns a single pixel at the specified (x,y) 1717% location. The image background color is returned if an error occurs. 1718% 1719% The format of the GetOneAuthenticPixel() method is: 1720% 1721% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x, 1722% const ssize_t y,Quantum *pixel,ExceptionInfo *exception) 1723% 1724% A description of each parameter follows: 1725% 1726% o image: the image. 1727% 1728% o x,y: These values define the location of the pixel to return. 1729% 1730% o pixel: return a pixel at the specified (x,y) location. 1731% 1732% o exception: return any errors or warnings in this structure. 1733% 1734*/ 1735 1736static inline MagickBooleanType CopyPixel(const Image *image, 1737 const Quantum *source,Quantum *destination) 1738{ 1739 register ssize_t 1740 i; 1741 1742 if (source == (const Quantum *) NULL) 1743 { 1744 destination[RedPixelChannel]=ClampToQuantum(image->background_color.red); 1745 destination[GreenPixelChannel]=ClampToQuantum( 1746 image->background_color.green); 1747 destination[BluePixelChannel]=ClampToQuantum( 1748 image->background_color.blue); 1749 destination[BlackPixelChannel]=ClampToQuantum( 1750 image->background_color.black); 1751 destination[AlphaPixelChannel]=ClampToQuantum( 1752 image->background_color.alpha); 1753 return(MagickFalse); 1754 } 1755 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 1756 { 1757 PixelChannel channel=GetPixelChannelChannel(image,i); 1758 destination[channel]=source[i]; 1759 } 1760 return(MagickTrue); 1761} 1762 1763MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image, 1764 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception) 1765{ 1766 CacheInfo 1767 *magick_restrict cache_info; 1768 1769 register Quantum 1770 *magick_restrict q; 1771 1772 assert(image != (Image *) NULL); 1773 assert(image->signature == MagickCoreSignature); 1774 assert(image->cache != (Cache) NULL); 1775 cache_info=(CacheInfo *) image->cache; 1776 assert(cache_info->signature == MagickCoreSignature); 1777 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel)); 1778 if (cache_info->methods.get_one_authentic_pixel_from_handler != 1779 (GetOneAuthenticPixelFromHandler) NULL) 1780 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y, 1781 pixel,exception)); 1782 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception); 1783 return(CopyPixel(image,q,pixel)); 1784} 1785 1786/* 1787%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1788% % 1789% % 1790% % 1791+ 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 % 1792% % 1793% % 1794% % 1795%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1796% 1797% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y) 1798% location. The image background color is returned if an error occurs. 1799% 1800% The format of the GetOneAuthenticPixelFromCache() method is: 1801% 1802% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image, 1803% const ssize_t x,const ssize_t y,Quantum *pixel, 1804% ExceptionInfo *exception) 1805% 1806% A description of each parameter follows: 1807% 1808% o image: the image. 1809% 1810% o x,y: These values define the location of the pixel to return. 1811% 1812% o pixel: return a pixel at the specified (x,y) location. 1813% 1814% o exception: return any errors or warnings in this structure. 1815% 1816*/ 1817static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image, 1818 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception) 1819{ 1820 CacheInfo 1821 *magick_restrict cache_info; 1822 1823 const int 1824 id = GetOpenMPThreadId(); 1825 1826 register Quantum 1827 *magick_restrict q; 1828 1829 assert(image != (const Image *) NULL); 1830 assert(image->signature == MagickCoreSignature); 1831 assert(image->cache != (Cache) NULL); 1832 cache_info=(CacheInfo *) image->cache; 1833 assert(cache_info->signature == MagickCoreSignature); 1834 assert(id < (int) cache_info->number_threads); 1835 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel)); 1836 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id], 1837 exception); 1838 return(CopyPixel(image,q,pixel)); 1839} 1840 1841/* 1842%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1843% % 1844% % 1845% % 1846% G e t O n e V i r t u a l P i x e l % 1847% % 1848% % 1849% % 1850%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1851% 1852% GetOneVirtualPixel() returns a single virtual pixel at the specified 1853% (x,y) location. The image background color is returned if an error occurs. 1854% If you plan to modify the pixel, use GetOneAuthenticPixel() instead. 1855% 1856% The format of the GetOneVirtualPixel() method is: 1857% 1858% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x, 1859% const ssize_t y,Quantum *pixel,ExceptionInfo exception) 1860% 1861% A description of each parameter follows: 1862% 1863% o image: the image. 1864% 1865% o x,y: These values define the location of the pixel to return. 1866% 1867% o pixel: return a pixel at the specified (x,y) location. 1868% 1869% o exception: return any errors or warnings in this structure. 1870% 1871*/ 1872MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image, 1873 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception) 1874{ 1875 CacheInfo 1876 *magick_restrict cache_info; 1877 1878 const int 1879 id = GetOpenMPThreadId(); 1880 1881 const Quantum 1882 *p; 1883 1884 assert(image != (const Image *) NULL); 1885 assert(image->signature == MagickCoreSignature); 1886 assert(image->cache != (Cache) NULL); 1887 cache_info=(CacheInfo *) image->cache; 1888 assert(cache_info->signature == MagickCoreSignature); 1889 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel)); 1890 if (cache_info->methods.get_one_virtual_pixel_from_handler != 1891 (GetOneVirtualPixelFromHandler) NULL) 1892 return(cache_info->methods.get_one_virtual_pixel_from_handler(image, 1893 GetPixelCacheVirtualMethod(image),x,y,pixel,exception)); 1894 assert(id < (int) cache_info->number_threads); 1895 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y, 1896 1UL,1UL,cache_info->nexus_info[id],exception); 1897 return(CopyPixel(image,p,pixel)); 1898} 1899 1900/* 1901%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1902% % 1903% % 1904% % 1905+ 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 % 1906% % 1907% % 1908% % 1909%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1910% 1911% GetOneVirtualPixelFromCache() returns a single virtual pixel at the 1912% specified (x,y) location. The image background color is returned if an 1913% error occurs. 1914% 1915% The format of the GetOneVirtualPixelFromCache() method is: 1916% 1917% MagickBooleanType GetOneVirtualPixelFromCache(const Image image, 1918% const VirtualPixelMethod method,const ssize_t x,const ssize_t y, 1919% Quantum *pixel,ExceptionInfo *exception) 1920% 1921% A description of each parameter follows: 1922% 1923% o image: the image. 1924% 1925% o virtual_pixel_method: the virtual pixel method. 1926% 1927% o x,y: These values define the location of the pixel to return. 1928% 1929% o pixel: return a pixel at the specified (x,y) location. 1930% 1931% o exception: return any errors or warnings in this structure. 1932% 1933*/ 1934static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image, 1935 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y, 1936 Quantum *pixel,ExceptionInfo *exception) 1937{ 1938 CacheInfo 1939 *magick_restrict cache_info; 1940 1941 const int 1942 id = GetOpenMPThreadId(); 1943 1944 const Quantum 1945 *p; 1946 1947 assert(image != (const Image *) NULL); 1948 assert(image->signature == MagickCoreSignature); 1949 assert(image->cache != (Cache) NULL); 1950 cache_info=(CacheInfo *) image->cache; 1951 assert(cache_info->signature == MagickCoreSignature); 1952 assert(id < (int) cache_info->number_threads); 1953 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel)); 1954 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL, 1955 cache_info->nexus_info[id],exception); 1956 return(CopyPixel(image,p,pixel)); 1957} 1958 1959/* 1960%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1961% % 1962% % 1963% % 1964% G e t O n e V i r t u a l P i x e l I n f o % 1965% % 1966% % 1967% % 1968%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1969% 1970% GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y) 1971% location. The image background color is returned if an error occurs. If 1972% you plan to modify the pixel, use GetOneAuthenticPixel() instead. 1973% 1974% The format of the GetOneVirtualPixelInfo() method is: 1975% 1976% MagickBooleanType GetOneVirtualPixelInfo(const Image image, 1977% const VirtualPixelMethod virtual_pixel_method,const ssize_t x, 1978% const ssize_t y,PixelInfo *pixel,ExceptionInfo exception) 1979% 1980% A description of each parameter follows: 1981% 1982% o image: the image. 1983% 1984% o virtual_pixel_method: the virtual pixel method. 1985% 1986% o x,y: these values define the location of the pixel to return. 1987% 1988% o pixel: return a pixel at the specified (x,y) location. 1989% 1990% o exception: return any errors or warnings in this structure. 1991% 1992*/ 1993MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image, 1994 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y, 1995 PixelInfo *pixel,ExceptionInfo *exception) 1996{ 1997 CacheInfo 1998 *magick_restrict cache_info; 1999 2000 const int 2001 id = GetOpenMPThreadId(); 2002 2003 register const Quantum 2004 *magick_restrict p; 2005 2006 assert(image != (const Image *) NULL); 2007 assert(image->signature == MagickCoreSignature); 2008 assert(image->cache != (Cache) NULL); 2009 cache_info=(CacheInfo *) image->cache; 2010 assert(cache_info->signature == MagickCoreSignature); 2011 assert(id < (int) cache_info->number_threads); 2012 GetPixelInfo(image,pixel); 2013 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL, 2014 cache_info->nexus_info[id],exception); 2015 if (p == (const Quantum *) NULL) 2016 return(MagickFalse); 2017 GetPixelInfoPixel(image,p,pixel); 2018 return(MagickTrue); 2019} 2020 2021/* 2022%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2023% % 2024% % 2025% % 2026+ G e t P i x e l C a c h e C o l o r s p a c e % 2027% % 2028% % 2029% % 2030%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2031% 2032% GetPixelCacheColorspace() returns the class type of the pixel cache. 2033% 2034% The format of the GetPixelCacheColorspace() method is: 2035% 2036% Colorspace GetPixelCacheColorspace(Cache cache) 2037% 2038% A description of each parameter follows: 2039% 2040% o cache: the pixel cache. 2041% 2042*/ 2043MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache) 2044{ 2045 CacheInfo 2046 *magick_restrict cache_info; 2047 2048 assert(cache != (Cache) NULL); 2049 cache_info=(CacheInfo *) cache; 2050 assert(cache_info->signature == MagickCoreSignature); 2051 if (cache_info->debug != MagickFalse) 2052 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 2053 cache_info->filename); 2054 return(cache_info->colorspace); 2055} 2056 2057/* 2058%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2059% % 2060% % 2061% % 2062+ G e t P i x e l C a c h e M e t h o d s % 2063% % 2064% % 2065% % 2066%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2067% 2068% GetPixelCacheMethods() initializes the CacheMethods structure. 2069% 2070% The format of the GetPixelCacheMethods() method is: 2071% 2072% void GetPixelCacheMethods(CacheMethods *cache_methods) 2073% 2074% A description of each parameter follows: 2075% 2076% o cache_methods: Specifies a pointer to a CacheMethods structure. 2077% 2078*/ 2079MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods) 2080{ 2081 assert(cache_methods != (CacheMethods *) NULL); 2082 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods)); 2083 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache; 2084 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache; 2085 cache_methods->get_virtual_metacontent_from_handler= 2086 GetVirtualMetacontentFromCache; 2087 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache; 2088 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache; 2089 cache_methods->get_authentic_metacontent_from_handler= 2090 GetAuthenticMetacontentFromCache; 2091 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache; 2092 cache_methods->get_one_authentic_pixel_from_handler= 2093 GetOneAuthenticPixelFromCache; 2094 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache; 2095 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache; 2096 cache_methods->destroy_pixel_handler=DestroyImagePixelCache; 2097} 2098 2099/* 2100%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2101% % 2102% % 2103% % 2104+ G e t P i x e l C a c h e N e x u s E x t e n t % 2105% % 2106% % 2107% % 2108%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2109% 2110% GetPixelCacheNexusExtent() returns the extent of the pixels associated 2111% corresponding with the last call to SetPixelCacheNexusPixels() or 2112% GetPixelCacheNexusPixels(). 2113% 2114% The format of the GetPixelCacheNexusExtent() method is: 2115% 2116% MagickSizeType GetPixelCacheNexusExtent(const Cache cache, 2117% NexusInfo *nexus_info) 2118% 2119% A description of each parameter follows: 2120% 2121% o nexus_info: the nexus info. 2122% 2123*/ 2124MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache, 2125 NexusInfo *magick_restrict nexus_info) 2126{ 2127 CacheInfo 2128 *magick_restrict cache_info; 2129 2130 MagickSizeType 2131 extent; 2132 2133 assert(cache != NULL); 2134 cache_info=(CacheInfo *) cache; 2135 assert(cache_info->signature == MagickCoreSignature); 2136 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height; 2137 if (extent == 0) 2138 return((MagickSizeType) cache_info->columns*cache_info->rows); 2139 return(extent); 2140} 2141 2142/* 2143%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2144% % 2145% % 2146% % 2147+ G e t P i x e l C a c h e P i x e l s % 2148% % 2149% % 2150% % 2151%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2152% 2153% GetPixelCachePixels() returns the pixels associated with the specified image. 2154% 2155% The format of the GetPixelCachePixels() method is: 2156% 2157% void *GetPixelCachePixels(Image *image,MagickSizeType *length, 2158% ExceptionInfo *exception) 2159% 2160% A description of each parameter follows: 2161% 2162% o image: the image. 2163% 2164% o length: the pixel cache length. 2165% 2166% o exception: return any errors or warnings in this structure. 2167% 2168*/ 2169MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length, 2170 ExceptionInfo *exception) 2171{ 2172 CacheInfo 2173 *magick_restrict cache_info; 2174 2175 assert(image != (const Image *) NULL); 2176 assert(image->signature == MagickCoreSignature); 2177 assert(image->cache != (Cache) NULL); 2178 assert(length != (MagickSizeType *) NULL); 2179 assert(exception != (ExceptionInfo *) NULL); 2180 assert(exception->signature == MagickCoreSignature); 2181 cache_info=(CacheInfo *) image->cache; 2182 assert(cache_info->signature == MagickCoreSignature); 2183 *length=0; 2184 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache)) 2185 return((void *) NULL); 2186 *length=cache_info->length; 2187 return((void *) cache_info->pixels); 2188} 2189 2190/* 2191%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2192% % 2193% % 2194% % 2195+ 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 % 2196% % 2197% % 2198% % 2199%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2200% 2201% GetPixelCacheStorageClass() returns the class type of the pixel cache. 2202% 2203% The format of the GetPixelCacheStorageClass() method is: 2204% 2205% ClassType GetPixelCacheStorageClass(Cache cache) 2206% 2207% A description of each parameter follows: 2208% 2209% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass. 2210% 2211% o cache: the pixel cache. 2212% 2213*/ 2214MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache) 2215{ 2216 CacheInfo 2217 *magick_restrict cache_info; 2218 2219 assert(cache != (Cache) NULL); 2220 cache_info=(CacheInfo *) cache; 2221 assert(cache_info->signature == MagickCoreSignature); 2222 if (cache_info->debug != MagickFalse) 2223 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 2224 cache_info->filename); 2225 return(cache_info->storage_class); 2226} 2227 2228/* 2229%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2230% % 2231% % 2232% % 2233+ G e t P i x e l C a c h e T i l e S i z e % 2234% % 2235% % 2236% % 2237%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2238% 2239% GetPixelCacheTileSize() returns the pixel cache tile size. 2240% 2241% The format of the GetPixelCacheTileSize() method is: 2242% 2243% void GetPixelCacheTileSize(const Image *image,size_t *width, 2244% size_t *height) 2245% 2246% A description of each parameter follows: 2247% 2248% o image: the image. 2249% 2250% o width: the optimize cache tile width in pixels. 2251% 2252% o height: the optimize cache tile height in pixels. 2253% 2254*/ 2255MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width, 2256 size_t *height) 2257{ 2258 CacheInfo 2259 *magick_restrict cache_info; 2260 2261 assert(image != (Image *) NULL); 2262 assert(image->signature == MagickCoreSignature); 2263 if (image->debug != MagickFalse) 2264 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 2265 cache_info=(CacheInfo *) image->cache; 2266 assert(cache_info->signature == MagickCoreSignature); 2267 *width=2048UL/(cache_info->number_channels*sizeof(Quantum)); 2268 if (GetImagePixelCacheType(image) == DiskCache) 2269 *width=8192UL/(cache_info->number_channels*sizeof(Quantum)); 2270 *height=(*width); 2271} 2272 2273/* 2274%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2275% % 2276% % 2277% % 2278+ 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 % 2279% % 2280% % 2281% % 2282%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2283% 2284% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the 2285% pixel cache. A virtual pixel is any pixel access that is outside the 2286% boundaries of the image cache. 2287% 2288% The format of the GetPixelCacheVirtualMethod() method is: 2289% 2290% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image) 2291% 2292% A description of each parameter follows: 2293% 2294% o image: the image. 2295% 2296*/ 2297MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image) 2298{ 2299 CacheInfo 2300 *magick_restrict cache_info; 2301 2302 assert(image != (Image *) NULL); 2303 assert(image->signature == MagickCoreSignature); 2304 assert(image->cache != (Cache) NULL); 2305 cache_info=(CacheInfo *) image->cache; 2306 assert(cache_info->signature == MagickCoreSignature); 2307 return(cache_info->virtual_pixel_method); 2308} 2309 2310/* 2311%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2312% % 2313% % 2314% % 2315+ 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 % 2316% % 2317% % 2318% % 2319%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2320% 2321% GetVirtualMetacontentFromCache() returns the meta-content corresponding with 2322% the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache(). 2323% 2324% The format of the GetVirtualMetacontentFromCache() method is: 2325% 2326% void *GetVirtualMetacontentFromCache(const Image *image) 2327% 2328% A description of each parameter follows: 2329% 2330% o image: the image. 2331% 2332*/ 2333static const void *GetVirtualMetacontentFromCache(const Image *image) 2334{ 2335 CacheInfo 2336 *magick_restrict cache_info; 2337 2338 const int 2339 id = GetOpenMPThreadId(); 2340 2341 const void 2342 *magick_restrict metacontent; 2343 2344 assert(image != (const Image *) NULL); 2345 assert(image->signature == MagickCoreSignature); 2346 assert(image->cache != (Cache) NULL); 2347 cache_info=(CacheInfo *) image->cache; 2348 assert(cache_info->signature == MagickCoreSignature); 2349 assert(id < (int) cache_info->number_threads); 2350 metacontent=GetVirtualMetacontentFromNexus(cache_info, 2351 cache_info->nexus_info[id]); 2352 return(metacontent); 2353} 2354 2355/* 2356%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2357% % 2358% % 2359% % 2360+ 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 % 2361% % 2362% % 2363% % 2364%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2365% 2366% GetVirtualMetacontentFromNexus() returns the meta-content for the specified 2367% cache nexus. 2368% 2369% The format of the GetVirtualMetacontentFromNexus() method is: 2370% 2371% const void *GetVirtualMetacontentFromNexus(const Cache cache, 2372% NexusInfo *nexus_info) 2373% 2374% A description of each parameter follows: 2375% 2376% o cache: the pixel cache. 2377% 2378% o nexus_info: the cache nexus to return the meta-content. 2379% 2380*/ 2381MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache, 2382 NexusInfo *magick_restrict nexus_info) 2383{ 2384 CacheInfo 2385 *magick_restrict cache_info; 2386 2387 assert(cache != (Cache) NULL); 2388 cache_info=(CacheInfo *) cache; 2389 assert(cache_info->signature == MagickCoreSignature); 2390 if (cache_info->storage_class == UndefinedClass) 2391 return((void *) NULL); 2392 return(nexus_info->metacontent); 2393} 2394 2395/* 2396%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2397% % 2398% % 2399% % 2400% G e t V i r t u a l M e t a c o n t e n t % 2401% % 2402% % 2403% % 2404%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2405% 2406% GetVirtualMetacontent() returns the virtual metacontent corresponding with 2407% the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is 2408% returned if the meta-content are not available. 2409% 2410% The format of the GetVirtualMetacontent() method is: 2411% 2412% const void *GetVirtualMetacontent(const Image *image) 2413% 2414% A description of each parameter follows: 2415% 2416% o image: the image. 2417% 2418*/ 2419MagickExport const void *GetVirtualMetacontent(const Image *image) 2420{ 2421 CacheInfo 2422 *magick_restrict cache_info; 2423 2424 const int 2425 id = GetOpenMPThreadId(); 2426 2427 const void 2428 *magick_restrict metacontent; 2429 2430 assert(image != (const Image *) NULL); 2431 assert(image->signature == MagickCoreSignature); 2432 assert(image->cache != (Cache) NULL); 2433 cache_info=(CacheInfo *) image->cache; 2434 assert(cache_info->signature == MagickCoreSignature); 2435 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image); 2436 if (metacontent != (void *) NULL) 2437 return(metacontent); 2438 assert(id < (int) cache_info->number_threads); 2439 metacontent=GetVirtualMetacontentFromNexus(cache_info, 2440 cache_info->nexus_info[id]); 2441 return(metacontent); 2442} 2443 2444/* 2445%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2446% % 2447% % 2448% % 2449+ 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 % 2450% % 2451% % 2452% % 2453%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2454% 2455% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk 2456% pixel cache as defined by the geometry parameters. A pointer to the pixels 2457% is returned if the pixels are transferred, otherwise a NULL is returned. 2458% 2459% The format of the GetVirtualPixelsFromNexus() method is: 2460% 2461% Quantum *GetVirtualPixelsFromNexus(const Image *image, 2462% const VirtualPixelMethod method,const ssize_t x,const ssize_t y, 2463% const size_t columns,const size_t rows,NexusInfo *nexus_info, 2464% ExceptionInfo *exception) 2465% 2466% A description of each parameter follows: 2467% 2468% o image: the image. 2469% 2470% o virtual_pixel_method: the virtual pixel method. 2471% 2472% o x,y,columns,rows: These values define the perimeter of a region of 2473% pixels. 2474% 2475% o nexus_info: the cache nexus to acquire. 2476% 2477% o exception: return any errors or warnings in this structure. 2478% 2479*/ 2480 2481static ssize_t 2482 DitherMatrix[64] = 2483 { 2484 0, 48, 12, 60, 3, 51, 15, 63, 2485 32, 16, 44, 28, 35, 19, 47, 31, 2486 8, 56, 4, 52, 11, 59, 7, 55, 2487 40, 24, 36, 20, 43, 27, 39, 23, 2488 2, 50, 14, 62, 1, 49, 13, 61, 2489 34, 18, 46, 30, 33, 17, 45, 29, 2490 10, 58, 6, 54, 9, 57, 5, 53, 2491 42, 26, 38, 22, 41, 25, 37, 21 2492 }; 2493 2494static inline ssize_t DitherX(const ssize_t x,const size_t columns) 2495{ 2496 ssize_t 2497 index; 2498 2499 index=x+DitherMatrix[x & 0x07]-32L; 2500 if (index < 0L) 2501 return(0L); 2502 if (index >= (ssize_t) columns) 2503 return((ssize_t) columns-1L); 2504 return(index); 2505} 2506 2507static inline ssize_t DitherY(const ssize_t y,const size_t rows) 2508{ 2509 ssize_t 2510 index; 2511 2512 index=y+DitherMatrix[y & 0x07]-32L; 2513 if (index < 0L) 2514 return(0L); 2515 if (index >= (ssize_t) rows) 2516 return((ssize_t) rows-1L); 2517 return(index); 2518} 2519 2520static inline ssize_t EdgeX(const ssize_t x,const size_t columns) 2521{ 2522 if (x < 0L) 2523 return(0L); 2524 if (x >= (ssize_t) columns) 2525 return((ssize_t) (columns-1)); 2526 return(x); 2527} 2528 2529static inline ssize_t EdgeY(const ssize_t y,const size_t rows) 2530{ 2531 if (y < 0L) 2532 return(0L); 2533 if (y >= (ssize_t) rows) 2534 return((ssize_t) (rows-1)); 2535 return(y); 2536} 2537 2538static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns) 2539{ 2540 return((ssize_t) (columns*GetPseudoRandomValue(random_info))); 2541} 2542 2543static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows) 2544{ 2545 return((ssize_t) (rows*GetPseudoRandomValue(random_info))); 2546} 2547 2548static inline MagickModulo VirtualPixelModulo(const ssize_t offset, 2549 const size_t extent) 2550{ 2551 MagickModulo 2552 modulo; 2553 2554 /* 2555 Compute the remainder of dividing offset by extent. It returns not only 2556 the quotient (tile the offset falls in) but also the positive remainer 2557 within that tile such that 0 <= remainder < extent. This method is 2558 essentially a ldiv() using a floored modulo division rather than the 2559 normal default truncated modulo division. 2560 */ 2561 modulo.quotient=offset/(ssize_t) extent; 2562 if (offset < 0L) 2563 modulo.quotient--; 2564 modulo.remainder=offset-modulo.quotient*(ssize_t) extent; 2565 return(modulo); 2566} 2567 2568MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image, 2569 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y, 2570 const size_t columns,const size_t rows,NexusInfo *nexus_info, 2571 ExceptionInfo *exception) 2572{ 2573 CacheInfo 2574 *magick_restrict cache_info; 2575 2576 MagickOffsetType 2577 offset; 2578 2579 MagickSizeType 2580 length, 2581 number_pixels; 2582 2583 NexusInfo 2584 **magick_restrict virtual_nexus; 2585 2586 Quantum 2587 *magick_restrict pixels, 2588 virtual_pixel[MaxPixelChannels]; 2589 2590 RectangleInfo 2591 region; 2592 2593 register const Quantum 2594 *magick_restrict p; 2595 2596 register const void 2597 *magick_restrict r; 2598 2599 register Quantum 2600 *magick_restrict q; 2601 2602 register ssize_t 2603 i, 2604 u; 2605 2606 register unsigned char 2607 *magick_restrict s; 2608 2609 ssize_t 2610 v; 2611 2612 void 2613 *magick_restrict virtual_metacontent; 2614 2615 /* 2616 Acquire pixels. 2617 */ 2618 assert(image != (const Image *) NULL); 2619 assert(image->signature == MagickCoreSignature); 2620 assert(image->cache != (Cache) NULL); 2621 cache_info=(CacheInfo *) image->cache; 2622 assert(cache_info->signature == MagickCoreSignature); 2623 if (cache_info->type == UndefinedCache) 2624 return((const Quantum *) NULL); 2625 region.x=x; 2626 region.y=y; 2627 region.width=columns; 2628 region.height=rows; 2629 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,nexus_info, 2630 exception); 2631 if (pixels == (Quantum *) NULL) 2632 return((const Quantum *) NULL); 2633 q=pixels; 2634 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+ 2635 nexus_info->region.x; 2636 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+ 2637 nexus_info->region.width-1L; 2638 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows; 2639 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels)) 2640 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) && 2641 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows)) 2642 { 2643 MagickBooleanType 2644 status; 2645 2646 /* 2647 Pixel request is inside cache extents. 2648 */ 2649 if (nexus_info->authentic_pixel_cache != MagickFalse) 2650 return(q); 2651 status=ReadPixelCachePixels(cache_info,nexus_info,exception); 2652 if (status == MagickFalse) 2653 return((const Quantum *) NULL); 2654 if (cache_info->metacontent_extent != 0) 2655 { 2656 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception); 2657 if (status == MagickFalse) 2658 return((const Quantum *) NULL); 2659 } 2660 return(q); 2661 } 2662 /* 2663 Pixel request is outside cache extents. 2664 */ 2665 s=(unsigned char *) nexus_info->metacontent; 2666 virtual_nexus=AcquirePixelCacheNexus(1); 2667 if (virtual_nexus == (NexusInfo **) NULL) 2668 { 2669 if (virtual_nexus != (NexusInfo **) NULL) 2670 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1); 2671 (void) ThrowMagickException(exception,GetMagickModule(),CacheError, 2672 "UnableToGetCacheNexus","`%s'",image->filename); 2673 return((const Quantum *) NULL); 2674 } 2675 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels* 2676 sizeof(*virtual_pixel)); 2677 virtual_metacontent=(void *) NULL; 2678 switch (virtual_pixel_method) 2679 { 2680 case BackgroundVirtualPixelMethod: 2681 case BlackVirtualPixelMethod: 2682 case GrayVirtualPixelMethod: 2683 case TransparentVirtualPixelMethod: 2684 case MaskVirtualPixelMethod: 2685 case WhiteVirtualPixelMethod: 2686 case EdgeVirtualPixelMethod: 2687 case CheckerTileVirtualPixelMethod: 2688 case HorizontalTileVirtualPixelMethod: 2689 case VerticalTileVirtualPixelMethod: 2690 { 2691 if (cache_info->metacontent_extent != 0) 2692 { 2693 /* 2694 Acquire a metacontent buffer. 2695 */ 2696 virtual_metacontent=(void *) AcquireQuantumMemory(1, 2697 cache_info->metacontent_extent); 2698 if (virtual_metacontent == (void *) NULL) 2699 { 2700 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1); 2701 (void) ThrowMagickException(exception,GetMagickModule(), 2702 CacheError,"UnableToGetCacheNexus","`%s'",image->filename); 2703 return((const Quantum *) NULL); 2704 } 2705 (void) ResetMagickMemory(virtual_metacontent,0, 2706 cache_info->metacontent_extent); 2707 } 2708 switch (virtual_pixel_method) 2709 { 2710 case BlackVirtualPixelMethod: 2711 { 2712 for (i=0; i < (ssize_t) cache_info->number_channels; i++) 2713 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel); 2714 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel); 2715 break; 2716 } 2717 case GrayVirtualPixelMethod: 2718 { 2719 for (i=0; i < (ssize_t) cache_info->number_channels; i++) 2720 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2, 2721 virtual_pixel); 2722 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel); 2723 break; 2724 } 2725 case TransparentVirtualPixelMethod: 2726 { 2727 for (i=0; i < (ssize_t) cache_info->number_channels; i++) 2728 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel); 2729 SetPixelAlpha(image,TransparentAlpha,virtual_pixel); 2730 break; 2731 } 2732 case MaskVirtualPixelMethod: 2733 case WhiteVirtualPixelMethod: 2734 { 2735 for (i=0; i < (ssize_t) cache_info->number_channels; i++) 2736 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel); 2737 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel); 2738 break; 2739 } 2740 default: 2741 { 2742 SetPixelRed(image,ClampToQuantum(image->background_color.red), 2743 virtual_pixel); 2744 SetPixelGreen(image,ClampToQuantum(image->background_color.green), 2745 virtual_pixel); 2746 SetPixelBlue(image,ClampToQuantum(image->background_color.blue), 2747 virtual_pixel); 2748 SetPixelBlack(image,ClampToQuantum(image->background_color.black), 2749 virtual_pixel); 2750 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha), 2751 virtual_pixel); 2752 break; 2753 } 2754 } 2755 break; 2756 } 2757 default: 2758 break; 2759 } 2760 for (v=0; v < (ssize_t) rows; v++) 2761 { 2762 ssize_t 2763 y_offset; 2764 2765 y_offset=y+v; 2766 if ((virtual_pixel_method == EdgeVirtualPixelMethod) || 2767 (virtual_pixel_method == UndefinedVirtualPixelMethod)) 2768 y_offset=EdgeY(y_offset,cache_info->rows); 2769 for (u=0; u < (ssize_t) columns; u+=length) 2770 { 2771 ssize_t 2772 x_offset; 2773 2774 x_offset=x+u; 2775 length=(MagickSizeType) MagickMin(cache_info->columns-x_offset,columns-u); 2776 if (((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns)) || 2777 ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows)) || 2778 (length == 0)) 2779 { 2780 MagickModulo 2781 x_modulo, 2782 y_modulo; 2783 2784 /* 2785 Transfer a single pixel. 2786 */ 2787 length=(MagickSizeType) 1; 2788 switch (virtual_pixel_method) 2789 { 2790 case EdgeVirtualPixelMethod: 2791 default: 2792 { 2793 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method, 2794 EdgeX(x_offset,cache_info->columns), 2795 EdgeY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus, 2796 exception); 2797 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus); 2798 break; 2799 } 2800 case RandomVirtualPixelMethod: 2801 { 2802 if (cache_info->random_info == (RandomInfo *) NULL) 2803 cache_info->random_info=AcquireRandomInfo(); 2804 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method, 2805 RandomX(cache_info->random_info,cache_info->columns), 2806 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL, 2807 *virtual_nexus,exception); 2808 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus); 2809 break; 2810 } 2811 case DitherVirtualPixelMethod: 2812 { 2813 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method, 2814 DitherX(x_offset,cache_info->columns), 2815 DitherY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus, 2816 exception); 2817 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus); 2818 break; 2819 } 2820 case TileVirtualPixelMethod: 2821 { 2822 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns); 2823 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows); 2824 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method, 2825 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus, 2826 exception); 2827 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus); 2828 break; 2829 } 2830 case MirrorVirtualPixelMethod: 2831 { 2832 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns); 2833 if ((x_modulo.quotient & 0x01) == 1L) 2834 x_modulo.remainder=(ssize_t) cache_info->columns- 2835 x_modulo.remainder-1L; 2836 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows); 2837 if ((y_modulo.quotient & 0x01) == 1L) 2838 y_modulo.remainder=(ssize_t) cache_info->rows- 2839 y_modulo.remainder-1L; 2840 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method, 2841 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus, 2842 exception); 2843 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus); 2844 break; 2845 } 2846 case HorizontalTileEdgeVirtualPixelMethod: 2847 { 2848 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns); 2849 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method, 2850 x_modulo.remainder,EdgeY(y_offset,cache_info->rows),1UL,1UL, 2851 *virtual_nexus,exception); 2852 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus); 2853 break; 2854 } 2855 case VerticalTileEdgeVirtualPixelMethod: 2856 { 2857 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows); 2858 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method, 2859 EdgeX(x_offset,cache_info->columns),y_modulo.remainder,1UL,1UL, 2860 *virtual_nexus,exception); 2861 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus); 2862 break; 2863 } 2864 case BackgroundVirtualPixelMethod: 2865 case BlackVirtualPixelMethod: 2866 case GrayVirtualPixelMethod: 2867 case TransparentVirtualPixelMethod: 2868 case MaskVirtualPixelMethod: 2869 case WhiteVirtualPixelMethod: 2870 { 2871 p=virtual_pixel; 2872 r=virtual_metacontent; 2873 break; 2874 } 2875 case CheckerTileVirtualPixelMethod: 2876 { 2877 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns); 2878 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows); 2879 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L) 2880 { 2881 p=virtual_pixel; 2882 r=virtual_metacontent; 2883 break; 2884 } 2885 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method, 2886 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus, 2887 exception); 2888 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus); 2889 break; 2890 } 2891 case HorizontalTileVirtualPixelMethod: 2892 { 2893 if ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows)) 2894 { 2895 p=virtual_pixel; 2896 r=virtual_metacontent; 2897 break; 2898 } 2899 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns); 2900 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows); 2901 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method, 2902 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus, 2903 exception); 2904 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus); 2905 break; 2906 } 2907 case VerticalTileVirtualPixelMethod: 2908 { 2909 if ((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns)) 2910 { 2911 p=virtual_pixel; 2912 r=virtual_metacontent; 2913 break; 2914 } 2915 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns); 2916 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows); 2917 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method, 2918 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus, 2919 exception); 2920 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus); 2921 break; 2922 } 2923 } 2924 if (p == (const Quantum *) NULL) 2925 break; 2926 (void) memcpy(q,p,(size_t) length*cache_info->number_channels* 2927 sizeof(*p)); 2928 q+=cache_info->number_channels; 2929 if ((s != (void *) NULL) && (r != (const void *) NULL)) 2930 { 2931 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent); 2932 s+=cache_info->metacontent_extent; 2933 } 2934 continue; 2935 } 2936 /* 2937 Transfer a run of pixels. 2938 */ 2939 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x_offset,y_offset, 2940 (size_t) length,1UL,*virtual_nexus,exception); 2941 if (p == (const Quantum *) NULL) 2942 break; 2943 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus); 2944 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p)); 2945 q+=length*cache_info->number_channels; 2946 if ((r != (void *) NULL) && (s != (const void *) NULL)) 2947 { 2948 (void) memcpy(s,r,(size_t) length); 2949 s+=length*cache_info->metacontent_extent; 2950 } 2951 } 2952 if (u < (ssize_t) columns) 2953 break; 2954 } 2955 /* 2956 Free resources. 2957 */ 2958 if (virtual_metacontent != (void *) NULL) 2959 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent); 2960 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1); 2961 if (v < (ssize_t) rows) 2962 return((const Quantum *) NULL); 2963 return(pixels); 2964} 2965 2966/* 2967%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2968% % 2969% % 2970% % 2971+ G e t V i r t u a l P i x e l C a c h e % 2972% % 2973% % 2974% % 2975%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2976% 2977% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel 2978% cache as defined by the geometry parameters. A pointer to the pixels 2979% is returned if the pixels are transferred, otherwise a NULL is returned. 2980% 2981% The format of the GetVirtualPixelCache() method is: 2982% 2983% const Quantum *GetVirtualPixelCache(const Image *image, 2984% const VirtualPixelMethod virtual_pixel_method,const ssize_t x, 2985% const ssize_t y,const size_t columns,const size_t rows, 2986% ExceptionInfo *exception) 2987% 2988% A description of each parameter follows: 2989% 2990% o image: the image. 2991% 2992% o virtual_pixel_method: the virtual pixel method. 2993% 2994% o x,y,columns,rows: These values define the perimeter of a region of 2995% pixels. 2996% 2997% o exception: return any errors or warnings in this structure. 2998% 2999*/ 3000static const Quantum *GetVirtualPixelCache(const Image *image, 3001 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y, 3002 const size_t columns,const size_t rows,ExceptionInfo *exception) 3003{ 3004 CacheInfo 3005 *magick_restrict cache_info; 3006 3007 const int 3008 id = GetOpenMPThreadId(); 3009 3010 const Quantum 3011 *magick_restrict p; 3012 3013 assert(image != (const Image *) NULL); 3014 assert(image->signature == MagickCoreSignature); 3015 assert(image->cache != (Cache) NULL); 3016 cache_info=(CacheInfo *) image->cache; 3017 assert(cache_info->signature == MagickCoreSignature); 3018 assert(id < (int) cache_info->number_threads); 3019 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows, 3020 cache_info->nexus_info[id],exception); 3021 return(p); 3022} 3023 3024/* 3025%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3026% % 3027% % 3028% % 3029% G e t V i r t u a l P i x e l Q u e u e % 3030% % 3031% % 3032% % 3033%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3034% 3035% GetVirtualPixelQueue() returns the virtual pixels associated corresponding 3036% with the last call to QueueAuthenticPixels() or GetVirtualPixels(). 3037% 3038% The format of the GetVirtualPixelQueue() method is: 3039% 3040% const Quantum *GetVirtualPixelQueue(const Image image) 3041% 3042% A description of each parameter follows: 3043% 3044% o image: the image. 3045% 3046*/ 3047MagickExport const Quantum *GetVirtualPixelQueue(const Image *image) 3048{ 3049 CacheInfo 3050 *magick_restrict cache_info; 3051 3052 const int 3053 id = GetOpenMPThreadId(); 3054 3055 assert(image != (const Image *) NULL); 3056 assert(image->signature == MagickCoreSignature); 3057 assert(image->cache != (Cache) NULL); 3058 cache_info=(CacheInfo *) image->cache; 3059 assert(cache_info->signature == MagickCoreSignature); 3060 if (cache_info->methods.get_virtual_pixels_handler != 3061 (GetVirtualPixelsHandler) NULL) 3062 return(cache_info->methods.get_virtual_pixels_handler(image)); 3063 assert(id < (int) cache_info->number_threads); 3064 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id])); 3065} 3066 3067/* 3068%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3069% % 3070% % 3071% % 3072% G e t V i r t u a l P i x e l s % 3073% % 3074% % 3075% % 3076%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3077% 3078% GetVirtualPixels() returns an immutable pixel region. If the 3079% region is successfully accessed, a pointer to it is returned, otherwise 3080% NULL is returned. The returned pointer may point to a temporary working 3081% copy of the pixels or it may point to the original pixels in memory. 3082% Performance is maximized if the selected region is part of one row, or one 3083% or more full rows, since there is opportunity to access the pixels in-place 3084% (without a copy) if the image is in memory, or in a memory-mapped file. The 3085% returned pointer must *never* be deallocated by the user. 3086% 3087% Pixels accessed via the returned pointer represent a simple array of type 3088% Quantum. If the image type is CMYK or the storage class is PseudoClass, 3089% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to 3090% access the meta-content (of type void) corresponding to the the 3091% region. 3092% 3093% If you plan to modify the pixels, use GetAuthenticPixels() instead. 3094% 3095% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread- 3096% safe. In a threaded environment, use GetCacheViewVirtualPixels() or 3097% GetCacheViewAuthenticPixels() instead. 3098% 3099% The format of the GetVirtualPixels() method is: 3100% 3101% const Quantum *GetVirtualPixels(const Image *image,const ssize_t x, 3102% const ssize_t y,const size_t columns,const size_t rows, 3103% ExceptionInfo *exception) 3104% 3105% A description of each parameter follows: 3106% 3107% o image: the image. 3108% 3109% o x,y,columns,rows: These values define the perimeter of a region of 3110% pixels. 3111% 3112% o exception: return any errors or warnings in this structure. 3113% 3114*/ 3115MagickExport const Quantum *GetVirtualPixels(const Image *image, 3116 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows, 3117 ExceptionInfo *exception) 3118{ 3119 CacheInfo 3120 *magick_restrict cache_info; 3121 3122 const int 3123 id = GetOpenMPThreadId(); 3124 3125 const Quantum 3126 *magick_restrict p; 3127 3128 assert(image != (const Image *) NULL); 3129 assert(image->signature == MagickCoreSignature); 3130 assert(image->cache != (Cache) NULL); 3131 cache_info=(CacheInfo *) image->cache; 3132 assert(cache_info->signature == MagickCoreSignature); 3133 if (cache_info->methods.get_virtual_pixel_handler != 3134 (GetVirtualPixelHandler) NULL) 3135 return(cache_info->methods.get_virtual_pixel_handler(image, 3136 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception)); 3137 assert(id < (int) cache_info->number_threads); 3138 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y, 3139 columns,rows,cache_info->nexus_info[id],exception); 3140 return(p); 3141} 3142 3143/* 3144%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3145% % 3146% % 3147% % 3148+ 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 % 3149% % 3150% % 3151% % 3152%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3153% 3154% GetVirtualPixelsCache() returns the pixels associated corresponding with the 3155% last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache(). 3156% 3157% The format of the GetVirtualPixelsCache() method is: 3158% 3159% Quantum *GetVirtualPixelsCache(const Image *image) 3160% 3161% A description of each parameter follows: 3162% 3163% o image: the image. 3164% 3165*/ 3166static const Quantum *GetVirtualPixelsCache(const Image *image) 3167{ 3168 CacheInfo 3169 *magick_restrict cache_info; 3170 3171 const int 3172 id = GetOpenMPThreadId(); 3173 3174 assert(image != (const Image *) NULL); 3175 assert(image->signature == MagickCoreSignature); 3176 assert(image->cache != (Cache) NULL); 3177 cache_info=(CacheInfo *) image->cache; 3178 assert(cache_info->signature == MagickCoreSignature); 3179 assert(id < (int) cache_info->number_threads); 3180 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id])); 3181} 3182 3183/* 3184%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3185% % 3186% % 3187% % 3188+ G e t V i r t u a l P i x e l s N e x u s % 3189% % 3190% % 3191% % 3192%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3193% 3194% GetVirtualPixelsNexus() returns the pixels associated with the specified 3195% cache nexus. 3196% 3197% The format of the GetVirtualPixelsNexus() method is: 3198% 3199% const Quantum *GetVirtualPixelsNexus(const Cache cache, 3200% NexusInfo *nexus_info) 3201% 3202% A description of each parameter follows: 3203% 3204% o cache: the pixel cache. 3205% 3206% o nexus_info: the cache nexus to return the colormap pixels. 3207% 3208*/ 3209MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache, 3210 NexusInfo *magick_restrict nexus_info) 3211{ 3212 CacheInfo 3213 *magick_restrict cache_info; 3214 3215 assert(cache != (Cache) NULL); 3216 cache_info=(CacheInfo *) cache; 3217 assert(cache_info->signature == MagickCoreSignature); 3218 if (cache_info->storage_class == UndefinedClass) 3219 return((Quantum *) NULL); 3220 return((const Quantum *) nexus_info->pixels); 3221} 3222 3223/* 3224%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3225% % 3226% % 3227% % 3228+ O p e n P i x e l C a c h e % 3229% % 3230% % 3231% % 3232%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3233% 3234% OpenPixelCache() allocates the pixel cache. This includes defining the cache 3235% dimensions, allocating space for the image pixels and optionally the 3236% metacontent, and memory mapping the cache if it is disk based. The cache 3237% nexus array is initialized as well. 3238% 3239% The format of the OpenPixelCache() method is: 3240% 3241% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode, 3242% ExceptionInfo *exception) 3243% 3244% A description of each parameter follows: 3245% 3246% o image: the image. 3247% 3248% o mode: ReadMode, WriteMode, or IOMode. 3249% 3250% o exception: return any errors or warnings in this structure. 3251% 3252*/ 3253 3254#if defined(__cplusplus) || defined(c_plusplus) 3255extern "C" { 3256#endif 3257 3258#if defined(SIGBUS) 3259static void CacheSignalHandler(int status) 3260{ 3261 ThrowFatalException(CacheFatalError,"UnableToExtendPixelCache"); 3262} 3263#endif 3264 3265#if defined(__cplusplus) || defined(c_plusplus) 3266} 3267#endif 3268 3269static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info, 3270 const MapMode mode) 3271{ 3272 int 3273 file; 3274 3275 /* 3276 Open pixel cache on disk. 3277 */ 3278 if ((cache_info->file != -1) && (cache_info->mode == mode)) 3279 return(MagickTrue); /* cache already open and in the proper mode */ 3280 if (*cache_info->cache_filename == '\0') 3281 file=AcquireUniqueFileResource(cache_info->cache_filename); 3282 else 3283 switch (mode) 3284 { 3285 case ReadMode: 3286 { 3287 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0); 3288 break; 3289 } 3290 case WriteMode: 3291 { 3292 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT | 3293 O_BINARY | O_EXCL,S_MODE); 3294 if (file == -1) 3295 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE); 3296 break; 3297 } 3298 case IOMode: 3299 default: 3300 { 3301 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY | 3302 O_EXCL,S_MODE); 3303 if (file == -1) 3304 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE); 3305 break; 3306 } 3307 } 3308 if (file == -1) 3309 return(MagickFalse); 3310 (void) AcquireMagickResource(FileResource,1); 3311 if (cache_info->file != -1) 3312 (void) ClosePixelCacheOnDisk(cache_info); 3313 cache_info->file=file; 3314 cache_info->mode=mode; 3315 return(MagickTrue); 3316} 3317 3318static inline MagickOffsetType WritePixelCacheRegion( 3319 const CacheInfo *magick_restrict cache_info,const MagickOffsetType offset, 3320 const MagickSizeType length,const unsigned char *magick_restrict buffer) 3321{ 3322 register MagickOffsetType 3323 i; 3324 3325 ssize_t 3326 count; 3327 3328#if !defined(MAGICKCORE_HAVE_PWRITE) 3329 if (lseek(cache_info->file,offset,SEEK_SET) < 0) 3330 return((MagickOffsetType) -1); 3331#endif 3332 count=0; 3333 for (i=0; i < (MagickOffsetType) length; i+=count) 3334 { 3335#if !defined(MAGICKCORE_HAVE_PWRITE) 3336 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,(size_t) 3337 SSIZE_MAX)); 3338#else 3339 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,(size_t) 3340 SSIZE_MAX),(off_t) (offset+i)); 3341#endif 3342 if (count <= 0) 3343 { 3344 count=0; 3345 if (errno != EINTR) 3346 break; 3347 } 3348 } 3349 return(i); 3350} 3351 3352static MagickBooleanType SetPixelCacheExtent(Image *image,MagickSizeType length) 3353{ 3354 CacheInfo 3355 *magick_restrict cache_info; 3356 3357 MagickOffsetType 3358 count, 3359 extent, 3360 offset; 3361 3362 cache_info=(CacheInfo *) image->cache; 3363 if (image->debug != MagickFalse) 3364 { 3365 char 3366 format[MagickPathExtent], 3367 message[MagickPathExtent]; 3368 3369 (void) FormatMagickSize(length,MagickFalse,"B",MagickPathExtent,format); 3370 (void) FormatLocaleString(message,MagickPathExtent, 3371 "extend %s (%s[%d], disk, %s)",cache_info->filename, 3372 cache_info->cache_filename,cache_info->file,format); 3373 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message); 3374 } 3375 if (length != (MagickSizeType) ((MagickOffsetType) length)) 3376 return(MagickFalse); 3377 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END); 3378 if (offset < 0) 3379 return(MagickFalse); 3380 if ((MagickSizeType) offset >= length) 3381 count=(MagickOffsetType) 1; 3382 else 3383 { 3384 extent=(MagickOffsetType) length-1; 3385 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *) 3386 ""); 3387#if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE) 3388 if (cache_info->synchronize != MagickFalse) 3389 (void) posix_fallocate(cache_info->file,offset+1,extent-offset); 3390#endif 3391#if defined(SIGBUS) 3392 (void) signal(SIGBUS,CacheSignalHandler); 3393#endif 3394 } 3395 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_SET); 3396 if (offset < 0) 3397 return(MagickFalse); 3398 return(count != (MagickOffsetType) 1 ? MagickFalse : MagickTrue); 3399} 3400 3401static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode, 3402 ExceptionInfo *exception) 3403{ 3404 CacheInfo 3405 *magick_restrict cache_info, 3406 source_info; 3407 3408 char 3409 format[MagickPathExtent], 3410 message[MagickPathExtent]; 3411 3412 const char 3413 *type; 3414 3415 MagickBooleanType 3416 status; 3417 3418 MagickSizeType 3419 length, 3420 number_pixels; 3421 3422 size_t 3423 columns, 3424 packet_size; 3425 3426 assert(image != (const Image *) NULL); 3427 assert(image->signature == MagickCoreSignature); 3428 assert(image->cache != (Cache) NULL); 3429 if (image->debug != MagickFalse) 3430 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 3431 if ((image->columns == 0) || (image->rows == 0)) 3432 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename); 3433 cache_info=(CacheInfo *) image->cache; 3434 assert(cache_info->signature == MagickCoreSignature); 3435 if ((AcquireMagickResource(WidthResource,image->columns) == MagickFalse) || 3436 (AcquireMagickResource(HeightResource,image->rows) == MagickFalse)) 3437 ThrowBinaryException(ImageError,"WidthOrHeightExceedsLimit", 3438 image->filename); 3439 source_info=(*cache_info); 3440 source_info.file=(-1); 3441 (void) FormatLocaleString(cache_info->filename,MagickPathExtent,"%s[%.20g]", 3442 image->filename,(double) GetImageIndexInList(image)); 3443 cache_info->storage_class=image->storage_class; 3444 cache_info->colorspace=image->colorspace; 3445 cache_info->alpha_trait=image->alpha_trait; 3446 cache_info->read_mask=image->read_mask; 3447 cache_info->write_mask=image->write_mask; 3448 cache_info->rows=image->rows; 3449 cache_info->columns=image->columns; 3450 InitializePixelChannelMap(image); 3451 cache_info->number_channels=GetPixelChannels(image); 3452 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels* 3453 sizeof(*image->channel_map)); 3454 cache_info->metacontent_extent=image->metacontent_extent; 3455 cache_info->mode=mode; 3456 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows; 3457 packet_size=cache_info->number_channels*sizeof(Quantum); 3458 if (image->metacontent_extent != 0) 3459 packet_size+=cache_info->metacontent_extent; 3460 length=number_pixels*packet_size; 3461 columns=(size_t) (length/cache_info->rows/packet_size); 3462 if ((cache_info->columns != columns) || ((ssize_t) cache_info->columns < 0) || 3463 ((ssize_t) cache_info->rows < 0)) 3464 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed", 3465 image->filename); 3466 cache_info->length=length; 3467 if (image->ping != MagickFalse) 3468 { 3469 cache_info->storage_class=image->storage_class; 3470 cache_info->colorspace=image->colorspace; 3471 cache_info->type=PingCache; 3472 return(MagickTrue); 3473 } 3474 status=AcquireMagickResource(AreaResource,cache_info->length); 3475 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+ 3476 cache_info->metacontent_extent); 3477 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length))) 3478 { 3479 status=AcquireMagickResource(MemoryResource,cache_info->length); 3480 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) || 3481 (cache_info->type == MemoryCache)) 3482 { 3483 status=MagickTrue; 3484 cache_info->mapped=MagickFalse; 3485 cache_info->pixels=(Quantum *) MagickAssumeAligned( 3486 AcquireAlignedMemory(1,(size_t) cache_info->length)); 3487 if (cache_info->pixels == (Quantum *) NULL) 3488 cache_info->pixels=source_info.pixels; 3489 else 3490 { 3491 /* 3492 Create memory pixel cache. 3493 */ 3494 cache_info->type=MemoryCache; 3495 cache_info->metacontent=(void *) NULL; 3496 if (cache_info->metacontent_extent != 0) 3497 cache_info->metacontent=(void *) (cache_info->pixels+ 3498 number_pixels*cache_info->number_channels); 3499 if ((source_info.storage_class != UndefinedClass) && 3500 (mode != ReadMode)) 3501 { 3502 status=ClonePixelCacheRepository(cache_info,&source_info, 3503 exception); 3504 RelinquishPixelCachePixels(&source_info); 3505 } 3506 if (image->debug != MagickFalse) 3507 { 3508 (void) FormatMagickSize(cache_info->length,MagickTrue,"B", 3509 MagickPathExtent,format); 3510 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) 3511 cache_info->type); 3512 (void) FormatLocaleString(message,MagickPathExtent, 3513 "open %s (%s %s, %.20gx%.20gx%.20g %s)", 3514 cache_info->filename,cache_info->mapped != MagickFalse ? 3515 "Anonymous" : "Heap",type,(double) cache_info->columns, 3516 (double) cache_info->rows,(double) 3517 cache_info->number_channels,format); 3518 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s", 3519 message); 3520 } 3521 return(status == 0 ? MagickFalse : MagickTrue); 3522 } 3523 } 3524 RelinquishMagickResource(MemoryResource,cache_info->length); 3525 } 3526 /* 3527 Create pixel cache on disk. 3528 */ 3529 status=AcquireMagickResource(DiskResource,cache_info->length); 3530 if ((status == MagickFalse) || (cache_info->type == DistributedCache)) 3531 { 3532 DistributeCacheInfo 3533 *server_info; 3534 3535 if (cache_info->type == DistributedCache) 3536 RelinquishMagickResource(DiskResource,cache_info->length); 3537 server_info=AcquireDistributeCacheInfo(exception); 3538 if (server_info != (DistributeCacheInfo *) NULL) 3539 { 3540 status=OpenDistributePixelCache(server_info,image); 3541 if (status == MagickFalse) 3542 { 3543 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache", 3544 GetDistributeCacheHostname(server_info)); 3545 server_info=DestroyDistributeCacheInfo(server_info); 3546 } 3547 else 3548 { 3549 /* 3550 Create a distributed pixel cache. 3551 */ 3552 status=MagickTrue; 3553 cache_info->type=DistributedCache; 3554 cache_info->server_info=server_info; 3555 (void) FormatLocaleString(cache_info->cache_filename, 3556 MagickPathExtent,"%s:%d",GetDistributeCacheHostname( 3557 (DistributeCacheInfo *) cache_info->server_info), 3558 GetDistributeCachePort((DistributeCacheInfo *) 3559 cache_info->server_info)); 3560 if ((source_info.storage_class != UndefinedClass) && 3561 (mode != ReadMode)) 3562 { 3563 status=ClonePixelCacheRepository(cache_info,&source_info, 3564 exception); 3565 RelinquishPixelCachePixels(&source_info); 3566 } 3567 if (image->debug != MagickFalse) 3568 { 3569 (void) FormatMagickSize(cache_info->length,MagickFalse,"B", 3570 MagickPathExtent,format); 3571 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) 3572 cache_info->type); 3573 (void) FormatLocaleString(message,MagickPathExtent, 3574 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)", 3575 cache_info->filename,cache_info->cache_filename, 3576 GetDistributeCacheFile((DistributeCacheInfo *) 3577 cache_info->server_info),type,(double) cache_info->columns, 3578 (double) cache_info->rows,(double) 3579 cache_info->number_channels,format); 3580 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s", 3581 message); 3582 } 3583 return(status == 0 ? MagickFalse : MagickTrue); 3584 } 3585 } 3586 RelinquishMagickResource(DiskResource,cache_info->length); 3587 (void) ThrowMagickException(exception,GetMagickModule(),CacheError, 3588 "CacheResourcesExhausted","`%s'",image->filename); 3589 return(MagickFalse); 3590 } 3591 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode)) 3592 { 3593 (void) ClosePixelCacheOnDisk(cache_info); 3594 *cache_info->cache_filename='\0'; 3595 } 3596 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse) 3597 { 3598 RelinquishMagickResource(DiskResource,cache_info->length); 3599 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache", 3600 image->filename); 3601 return(MagickFalse); 3602 } 3603 status=SetPixelCacheExtent(image,(MagickSizeType) cache_info->offset+ 3604 cache_info->length); 3605 if (status == MagickFalse) 3606 { 3607 ThrowFileException(exception,CacheError,"UnableToExtendCache", 3608 image->filename); 3609 return(MagickFalse); 3610 } 3611 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+ 3612 cache_info->metacontent_extent); 3613 if (length != (MagickSizeType) ((size_t) length)) 3614 cache_info->type=DiskCache; 3615 else 3616 { 3617 status=AcquireMagickResource(MapResource,cache_info->length); 3618 if ((status == MagickFalse) && (cache_info->type != MapCache) && 3619 (cache_info->type != MemoryCache)) 3620 { 3621 status=MagickTrue; 3622 cache_info->type=DiskCache; 3623 } 3624 else 3625 { 3626 status=MagickTrue; 3627 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode, 3628 cache_info->offset,(size_t) cache_info->length); 3629 if (cache_info->pixels == (Quantum *) NULL) 3630 { 3631 cache_info->type=DiskCache; 3632 cache_info->pixels=source_info.pixels; 3633 } 3634 else 3635 { 3636 /* 3637 Create file-backed memory-mapped pixel cache. 3638 */ 3639 (void) ClosePixelCacheOnDisk(cache_info); 3640 cache_info->type=MapCache; 3641 cache_info->mapped=MagickTrue; 3642 cache_info->metacontent=(void *) NULL; 3643 if (cache_info->metacontent_extent != 0) 3644 cache_info->metacontent=(void *) (cache_info->pixels+ 3645 number_pixels*cache_info->number_channels); 3646 if ((source_info.storage_class != UndefinedClass) && 3647 (mode != ReadMode)) 3648 { 3649 status=ClonePixelCacheRepository(cache_info,&source_info, 3650 exception); 3651 RelinquishPixelCachePixels(&source_info); 3652 } 3653 if (image->debug != MagickFalse) 3654 { 3655 (void) FormatMagickSize(cache_info->length,MagickTrue,"B", 3656 MagickPathExtent,format); 3657 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) 3658 cache_info->type); 3659 (void) FormatLocaleString(message,MagickPathExtent, 3660 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)", 3661 cache_info->filename,cache_info->cache_filename, 3662 cache_info->file,type,(double) cache_info->columns,(double) 3663 cache_info->rows,(double) cache_info->number_channels, 3664 format); 3665 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s", 3666 message); 3667 } 3668 return(status == 0 ? MagickFalse : MagickTrue); 3669 } 3670 } 3671 RelinquishMagickResource(MapResource,cache_info->length); 3672 } 3673 status=MagickTrue; 3674 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode)) 3675 { 3676 status=ClonePixelCacheRepository(cache_info,&source_info,exception); 3677 RelinquishPixelCachePixels(&source_info); 3678 } 3679 if (image->debug != MagickFalse) 3680 { 3681 (void) FormatMagickSize(cache_info->length,MagickFalse,"B", 3682 MagickPathExtent,format); 3683 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) 3684 cache_info->type); 3685 (void) FormatLocaleString(message,MagickPathExtent, 3686 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",cache_info->filename, 3687 cache_info->cache_filename,cache_info->file,type,(double) 3688 cache_info->columns,(double) cache_info->rows,(double) 3689 cache_info->number_channels,format); 3690 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message); 3691 } 3692 return(status == 0 ? MagickFalse : MagickTrue); 3693} 3694 3695/* 3696%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3697% % 3698% % 3699% % 3700+ P e r s i s t P i x e l C a c h e % 3701% % 3702% % 3703% % 3704%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3705% 3706% PersistPixelCache() attaches to or initializes a persistent pixel cache. A 3707% persistent pixel cache is one that resides on disk and is not destroyed 3708% when the program exits. 3709% 3710% The format of the PersistPixelCache() method is: 3711% 3712% MagickBooleanType PersistPixelCache(Image *image,const char *filename, 3713% const MagickBooleanType attach,MagickOffsetType *offset, 3714% ExceptionInfo *exception) 3715% 3716% A description of each parameter follows: 3717% 3718% o image: the image. 3719% 3720% o filename: the persistent pixel cache filename. 3721% 3722% o attach: A value other than zero initializes the persistent pixel cache. 3723% 3724% o initialize: A value other than zero initializes the persistent pixel 3725% cache. 3726% 3727% o offset: the offset in the persistent cache to store pixels. 3728% 3729% o exception: return any errors or warnings in this structure. 3730% 3731*/ 3732MagickExport MagickBooleanType PersistPixelCache(Image *image, 3733 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset, 3734 ExceptionInfo *exception) 3735{ 3736 CacheInfo 3737 *magick_restrict cache_info, 3738 *magick_restrict clone_info; 3739 3740 Image 3741 clone_image; 3742 3743 MagickBooleanType 3744 status; 3745 3746 ssize_t 3747 page_size; 3748 3749 assert(image != (Image *) NULL); 3750 assert(image->signature == MagickCoreSignature); 3751 if (image->debug != MagickFalse) 3752 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 3753 assert(image->cache != (void *) NULL); 3754 assert(filename != (const char *) NULL); 3755 assert(offset != (MagickOffsetType *) NULL); 3756 page_size=GetMagickPageSize(); 3757 cache_info=(CacheInfo *) image->cache; 3758 assert(cache_info->signature == MagickCoreSignature); 3759#if defined(MAGICKCORE_OPENCL_SUPPORT) 3760 CopyOpenCLBuffer(cache_info); 3761#endif 3762 if (attach != MagickFalse) 3763 { 3764 /* 3765 Attach existing persistent pixel cache. 3766 */ 3767 if (image->debug != MagickFalse) 3768 (void) LogMagickEvent(CacheEvent,GetMagickModule(), 3769 "attach persistent cache"); 3770 (void) CopyMagickString(cache_info->cache_filename,filename, 3771 MagickPathExtent); 3772 cache_info->type=DiskCache; 3773 cache_info->offset=(*offset); 3774 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse) 3775 return(MagickFalse); 3776 *offset+=cache_info->length+page_size-(cache_info->length % page_size); 3777 return(MagickTrue); 3778 } 3779 if ((cache_info->mode != ReadMode) && 3780 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) && 3781 (cache_info->reference_count == 1)) 3782 { 3783 LockSemaphoreInfo(cache_info->semaphore); 3784 if ((cache_info->mode != ReadMode) && 3785 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) && 3786 (cache_info->reference_count == 1)) 3787 { 3788 /* 3789 Usurp existing persistent pixel cache. 3790 */ 3791 if (rename_utf8(cache_info->cache_filename, filename) == 0) 3792 { 3793 (void) CopyMagickString(cache_info->cache_filename,filename, 3794 MagickPathExtent); 3795 *offset+=cache_info->length+page_size-(cache_info->length % 3796 page_size); 3797 UnlockSemaphoreInfo(cache_info->semaphore); 3798 cache_info=(CacheInfo *) ReferencePixelCache(cache_info); 3799 if (image->debug != MagickFalse) 3800 (void) LogMagickEvent(CacheEvent,GetMagickModule(), 3801 "Usurp resident persistent cache"); 3802 return(MagickTrue); 3803 } 3804 } 3805 UnlockSemaphoreInfo(cache_info->semaphore); 3806 } 3807 /* 3808 Clone persistent pixel cache. 3809 */ 3810 clone_image=(*image); 3811 clone_info=(CacheInfo *) clone_image.cache; 3812 image->cache=ClonePixelCache(cache_info); 3813 cache_info=(CacheInfo *) ReferencePixelCache(image->cache); 3814 (void) CopyMagickString(cache_info->cache_filename,filename,MagickPathExtent); 3815 cache_info->type=DiskCache; 3816 cache_info->offset=(*offset); 3817 cache_info=(CacheInfo *) image->cache; 3818 status=OpenPixelCache(image,IOMode,exception); 3819 if (status != MagickFalse) 3820 status=ClonePixelCacheRepository(cache_info,clone_info,exception); 3821 *offset+=cache_info->length+page_size-(cache_info->length % page_size); 3822 clone_info=(CacheInfo *) DestroyPixelCache(clone_info); 3823 return(status); 3824} 3825 3826/* 3827%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3828% % 3829% % 3830% % 3831+ Q u e u e A u t h e n t i c P i x e l C a c h e N e x u s % 3832% % 3833% % 3834% % 3835%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3836% 3837% QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as 3838% defined by the region rectangle and returns a pointer to the region. This 3839% region is subsequently transferred from the pixel cache with 3840% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the 3841% pixels are transferred, otherwise a NULL is returned. 3842% 3843% The format of the QueueAuthenticPixelCacheNexus() method is: 3844% 3845% Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x, 3846% const ssize_t y,const size_t columns,const size_t rows, 3847% const MagickBooleanType clone,NexusInfo *nexus_info, 3848% ExceptionInfo *exception) 3849% 3850% A description of each parameter follows: 3851% 3852% o image: the image. 3853% 3854% o x,y,columns,rows: These values define the perimeter of a region of 3855% pixels. 3856% 3857% o nexus_info: the cache nexus to set. 3858% 3859% o clone: clone the pixel cache. 3860% 3861% o exception: return any errors or warnings in this structure. 3862% 3863*/ 3864MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image, 3865 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows, 3866 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception) 3867{ 3868 CacheInfo 3869 *magick_restrict cache_info; 3870 3871 MagickOffsetType 3872 offset; 3873 3874 MagickSizeType 3875 number_pixels; 3876 3877 Quantum 3878 *magick_restrict pixels; 3879 3880 RectangleInfo 3881 region; 3882 3883 /* 3884 Validate pixel cache geometry. 3885 */ 3886 assert(image != (const Image *) NULL); 3887 assert(image->signature == MagickCoreSignature); 3888 assert(image->cache != (Cache) NULL); 3889 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception); 3890 if (cache_info == (Cache) NULL) 3891 return((Quantum *) NULL); 3892 assert(cache_info->signature == MagickCoreSignature); 3893 if ((cache_info->columns == 0) || (cache_info->rows == 0) || (x < 0) || 3894 (y < 0) || (x >= (ssize_t) cache_info->columns) || 3895 (y >= (ssize_t) cache_info->rows)) 3896 { 3897 (void) ThrowMagickException(exception,GetMagickModule(),CacheError, 3898 "PixelsAreNotAuthentic","`%s'",image->filename); 3899 return((Quantum *) NULL); 3900 } 3901 offset=(MagickOffsetType) y*cache_info->columns+x; 3902 if (offset < 0) 3903 return((Quantum *) NULL); 3904 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows; 3905 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1; 3906 if ((MagickSizeType) offset >= number_pixels) 3907 return((Quantum *) NULL); 3908 /* 3909 Return pixel cache. 3910 */ 3911 region.x=x; 3912 region.y=y; 3913 region.width=columns; 3914 region.height=rows; 3915 pixels=SetPixelCacheNexusPixels(cache_info,WriteMode,®ion,nexus_info, 3916 exception); 3917 return(pixels); 3918} 3919 3920/* 3921%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3922% % 3923% % 3924% % 3925+ Q u e u e A u t h e n t i c P i x e l s C a c h e % 3926% % 3927% % 3928% % 3929%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3930% 3931% QueueAuthenticPixelsCache() allocates an region to store image pixels as 3932% defined by the region rectangle and returns a pointer to the region. This 3933% region is subsequently transferred from the pixel cache with 3934% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the 3935% pixels are transferred, otherwise a NULL is returned. 3936% 3937% The format of the QueueAuthenticPixelsCache() method is: 3938% 3939% Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x, 3940% const ssize_t y,const size_t columns,const size_t rows, 3941% ExceptionInfo *exception) 3942% 3943% A description of each parameter follows: 3944% 3945% o image: the image. 3946% 3947% o x,y,columns,rows: These values define the perimeter of a region of 3948% pixels. 3949% 3950% o exception: return any errors or warnings in this structure. 3951% 3952*/ 3953static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x, 3954 const ssize_t y,const size_t columns,const size_t rows, 3955 ExceptionInfo *exception) 3956{ 3957 CacheInfo 3958 *magick_restrict cache_info; 3959 3960 const int 3961 id = GetOpenMPThreadId(); 3962 3963 Quantum 3964 *magick_restrict pixels; 3965 3966 assert(image != (const Image *) NULL); 3967 assert(image->signature == MagickCoreSignature); 3968 assert(image->cache != (Cache) NULL); 3969 cache_info=(CacheInfo *) image->cache; 3970 assert(cache_info->signature == MagickCoreSignature); 3971 assert(id < (int) cache_info->number_threads); 3972 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse, 3973 cache_info->nexus_info[id],exception); 3974 return(pixels); 3975} 3976 3977/* 3978%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3979% % 3980% % 3981% % 3982% Q u e u e A u t h e n t i c P i x e l s % 3983% % 3984% % 3985% % 3986%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3987% 3988% QueueAuthenticPixels() queues a mutable pixel region. If the region is 3989% successfully initialized a pointer to a Quantum array representing the 3990% region is returned, otherwise NULL is returned. The returned pointer may 3991% point to a temporary working buffer for the pixels or it may point to the 3992% final location of the pixels in memory. 3993% 3994% Write-only access means that any existing pixel values corresponding to 3995% the region are ignored. This is useful if the initial image is being 3996% created from scratch, or if the existing pixel values are to be 3997% completely replaced without need to refer to their pre-existing values. 3998% The application is free to read and write the pixel buffer returned by 3999% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not 4000% initialize the pixel array values. Initializing pixel array values is the 4001% application's responsibility. 4002% 4003% Performance is maximized if the selected region is part of one row, or 4004% one or more full rows, since then there is opportunity to access the 4005% pixels in-place (without a copy) if the image is in memory, or in a 4006% memory-mapped file. The returned pointer must *never* be deallocated 4007% by the user. 4008% 4009% Pixels accessed via the returned pointer represent a simple array of type 4010% Quantum. If the image type is CMYK or the storage class is PseudoClass, 4011% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to 4012% obtain the meta-content (of type void) corresponding to the region. 4013% Once the Quantum (and/or Quantum) array has been updated, the 4014% changes must be saved back to the underlying image using 4015% SyncAuthenticPixels() or they may be lost. 4016% 4017% The format of the QueueAuthenticPixels() method is: 4018% 4019% Quantum *QueueAuthenticPixels(Image *image,const ssize_t x, 4020% const ssize_t y,const size_t columns,const size_t rows, 4021% ExceptionInfo *exception) 4022% 4023% A description of each parameter follows: 4024% 4025% o image: the image. 4026% 4027% o x,y,columns,rows: These values define the perimeter of a region of 4028% pixels. 4029% 4030% o exception: return any errors or warnings in this structure. 4031% 4032*/ 4033MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x, 4034 const ssize_t y,const size_t columns,const size_t rows, 4035 ExceptionInfo *exception) 4036{ 4037 CacheInfo 4038 *magick_restrict cache_info; 4039 4040 const int 4041 id = GetOpenMPThreadId(); 4042 4043 Quantum 4044 *magick_restrict pixels; 4045 4046 assert(image != (Image *) NULL); 4047 assert(image->signature == MagickCoreSignature); 4048 assert(image->cache != (Cache) NULL); 4049 cache_info=(CacheInfo *) image->cache; 4050 assert(cache_info->signature == MagickCoreSignature); 4051 if (cache_info->methods.queue_authentic_pixels_handler != 4052 (QueueAuthenticPixelsHandler) NULL) 4053 { 4054 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y, 4055 columns,rows,exception); 4056 return(pixels); 4057 } 4058 assert(id < (int) cache_info->number_threads); 4059 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse, 4060 cache_info->nexus_info[id],exception); 4061 return(pixels); 4062} 4063 4064/* 4065%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4066% % 4067% % 4068% % 4069+ R e a d P i x e l C a c h e M e t a c o n t e n t % 4070% % 4071% % 4072% % 4073%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4074% 4075% ReadPixelCacheMetacontent() reads metacontent from the specified region of 4076% the pixel cache. 4077% 4078% The format of the ReadPixelCacheMetacontent() method is: 4079% 4080% MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info, 4081% NexusInfo *nexus_info,ExceptionInfo *exception) 4082% 4083% A description of each parameter follows: 4084% 4085% o cache_info: the pixel cache. 4086% 4087% o nexus_info: the cache nexus to read the metacontent. 4088% 4089% o exception: return any errors or warnings in this structure. 4090% 4091*/ 4092 4093static inline MagickOffsetType ReadPixelCacheRegion( 4094 const CacheInfo *magick_restrict cache_info,const MagickOffsetType offset, 4095 const MagickSizeType length,unsigned char *magick_restrict buffer) 4096{ 4097 register MagickOffsetType 4098 i; 4099 4100 ssize_t 4101 count; 4102 4103#if !defined(MAGICKCORE_HAVE_PREAD) 4104 if (lseek(cache_info->file,offset,SEEK_SET) < 0) 4105 return((MagickOffsetType) -1); 4106#endif 4107 count=0; 4108 for (i=0; i < (MagickOffsetType) length; i+=count) 4109 { 4110#if !defined(MAGICKCORE_HAVE_PREAD) 4111 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,(size_t) 4112 SSIZE_MAX)); 4113#else 4114 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,(size_t) 4115 SSIZE_MAX),(off_t) (offset+i)); 4116#endif 4117 if (count <= 0) 4118 { 4119 count=0; 4120 if (errno != EINTR) 4121 break; 4122 } 4123 } 4124 return(i); 4125} 4126 4127static MagickBooleanType ReadPixelCacheMetacontent( 4128 CacheInfo *magick_restrict cache_info,NexusInfo *magick_restrict nexus_info, 4129 ExceptionInfo *exception) 4130{ 4131 MagickOffsetType 4132 count, 4133 offset; 4134 4135 MagickSizeType 4136 extent, 4137 length; 4138 4139 register ssize_t 4140 y; 4141 4142 register unsigned char 4143 *magick_restrict q; 4144 4145 size_t 4146 rows; 4147 4148 if (cache_info->metacontent_extent == 0) 4149 return(MagickFalse); 4150 if (nexus_info->authentic_pixel_cache != MagickFalse) 4151 return(MagickTrue); 4152 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+ 4153 nexus_info->region.x; 4154 length=(MagickSizeType) nexus_info->region.width* 4155 cache_info->metacontent_extent; 4156 extent=length*nexus_info->region.height; 4157 rows=nexus_info->region.height; 4158 y=0; 4159 q=(unsigned char *) nexus_info->metacontent; 4160 switch (cache_info->type) 4161 { 4162 case MemoryCache: 4163 case MapCache: 4164 { 4165 register unsigned char 4166 *magick_restrict p; 4167 4168 /* 4169 Read meta-content from memory. 4170 */ 4171 if ((cache_info->columns == nexus_info->region.width) && 4172 (extent == (MagickSizeType) ((size_t) extent))) 4173 { 4174 length=extent; 4175 rows=1UL; 4176 } 4177 p=(unsigned char *) cache_info->metacontent+offset* 4178 cache_info->metacontent_extent; 4179 for (y=0; y < (ssize_t) rows; y++) 4180 { 4181 (void) memcpy(q,p,(size_t) length); 4182 p+=cache_info->metacontent_extent*cache_info->columns; 4183 q+=cache_info->metacontent_extent*nexus_info->region.width; 4184 } 4185 break; 4186 } 4187 case DiskCache: 4188 { 4189 /* 4190 Read meta content from disk. 4191 */ 4192 LockSemaphoreInfo(cache_info->file_semaphore); 4193 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse) 4194 { 4195 ThrowFileException(exception,FileOpenError,"UnableToOpenFile", 4196 cache_info->cache_filename); 4197 UnlockSemaphoreInfo(cache_info->file_semaphore); 4198 return(MagickFalse); 4199 } 4200 if ((cache_info->columns == nexus_info->region.width) && 4201 (extent <= MagickMaxBufferExtent)) 4202 { 4203 length=extent; 4204 rows=1UL; 4205 } 4206 extent=(MagickSizeType) cache_info->columns*cache_info->rows; 4207 for (y=0; y < (ssize_t) rows; y++) 4208 { 4209 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent* 4210 cache_info->number_channels*sizeof(Quantum)+offset* 4211 cache_info->metacontent_extent,length,(unsigned char *) q); 4212 if (count != (MagickOffsetType) length) 4213 break; 4214 offset+=cache_info->columns; 4215 q+=cache_info->metacontent_extent*nexus_info->region.width; 4216 } 4217 if (IsFileDescriptorLimitExceeded() != MagickFalse) 4218 (void) ClosePixelCacheOnDisk(cache_info); 4219 UnlockSemaphoreInfo(cache_info->file_semaphore); 4220 break; 4221 } 4222 case DistributedCache: 4223 { 4224 RectangleInfo 4225 region; 4226 4227 /* 4228 Read metacontent from distributed cache. 4229 */ 4230 LockSemaphoreInfo(cache_info->file_semaphore); 4231 region=nexus_info->region; 4232 if ((cache_info->columns != nexus_info->region.width) || 4233 (extent > MagickMaxBufferExtent)) 4234 region.height=1UL; 4235 else 4236 { 4237 length=extent; 4238 rows=1UL; 4239 } 4240 for (y=0; y < (ssize_t) rows; y++) 4241 { 4242 count=ReadDistributePixelCacheMetacontent((DistributeCacheInfo *) 4243 cache_info->server_info,®ion,length,(unsigned char *) q); 4244 if (count != (MagickOffsetType) length) 4245 break; 4246 q+=cache_info->metacontent_extent*nexus_info->region.width; 4247 region.y++; 4248 } 4249 UnlockSemaphoreInfo(cache_info->file_semaphore); 4250 break; 4251 } 4252 default: 4253 break; 4254 } 4255 if (y < (ssize_t) rows) 4256 { 4257 ThrowFileException(exception,CacheError,"UnableToReadPixelCache", 4258 cache_info->cache_filename); 4259 return(MagickFalse); 4260 } 4261 if ((cache_info->debug != MagickFalse) && 4262 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse)) 4263 (void) LogMagickEvent(CacheEvent,GetMagickModule(), 4264 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double) 4265 nexus_info->region.width,(double) nexus_info->region.height,(double) 4266 nexus_info->region.x,(double) nexus_info->region.y); 4267 return(MagickTrue); 4268} 4269 4270/* 4271%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4272% % 4273% % 4274% % 4275+ R e a d P i x e l C a c h e P i x e l s % 4276% % 4277% % 4278% % 4279%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4280% 4281% ReadPixelCachePixels() reads pixels from the specified region of the pixel 4282% cache. 4283% 4284% The format of the ReadPixelCachePixels() method is: 4285% 4286% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info, 4287% NexusInfo *nexus_info,ExceptionInfo *exception) 4288% 4289% A description of each parameter follows: 4290% 4291% o cache_info: the pixel cache. 4292% 4293% o nexus_info: the cache nexus to read the pixels. 4294% 4295% o exception: return any errors or warnings in this structure. 4296% 4297*/ 4298static MagickBooleanType ReadPixelCachePixels( 4299 CacheInfo *magick_restrict cache_info,NexusInfo *magick_restrict nexus_info, 4300 ExceptionInfo *exception) 4301{ 4302 MagickOffsetType 4303 count, 4304 offset; 4305 4306 MagickSizeType 4307 extent, 4308 length; 4309 4310 register Quantum 4311 *magick_restrict q; 4312 4313 register ssize_t 4314 y; 4315 4316 size_t 4317 number_channels, 4318 rows; 4319 4320 if (nexus_info->authentic_pixel_cache != MagickFalse) 4321 return(MagickTrue); 4322 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns; 4323 if ((ssize_t) (offset/cache_info->columns) != nexus_info->region.y) 4324 return(MagickFalse); 4325 offset+=nexus_info->region.x; 4326 number_channels=cache_info->number_channels; 4327 length=(MagickSizeType) number_channels*nexus_info->region.width* 4328 sizeof(Quantum); 4329 if ((length/number_channels/sizeof(Quantum)) != nexus_info->region.width) 4330 return(MagickFalse); 4331 rows=nexus_info->region.height; 4332 extent=length*rows; 4333 if ((extent == 0) || ((extent/length) != rows)) 4334 return(MagickFalse); 4335 y=0; 4336 q=nexus_info->pixels; 4337 switch (cache_info->type) 4338 { 4339 case MemoryCache: 4340 case MapCache: 4341 { 4342 register Quantum 4343 *magick_restrict p; 4344 4345 /* 4346 Read pixels from memory. 4347 */ 4348 if ((cache_info->columns == nexus_info->region.width) && 4349 (extent == (MagickSizeType) ((size_t) extent))) 4350 { 4351 length=extent; 4352 rows=1UL; 4353 } 4354 p=cache_info->pixels+offset*cache_info->number_channels; 4355 for (y=0; y < (ssize_t) rows; y++) 4356 { 4357 (void) memcpy(q,p,(size_t) length); 4358 p+=cache_info->number_channels*cache_info->columns; 4359 q+=cache_info->number_channels*nexus_info->region.width; 4360 } 4361 break; 4362 } 4363 case DiskCache: 4364 { 4365 /* 4366 Read pixels from disk. 4367 */ 4368 LockSemaphoreInfo(cache_info->file_semaphore); 4369 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse) 4370 { 4371 ThrowFileException(exception,FileOpenError,"UnableToOpenFile", 4372 cache_info->cache_filename); 4373 UnlockSemaphoreInfo(cache_info->file_semaphore); 4374 return(MagickFalse); 4375 } 4376 if ((cache_info->columns == nexus_info->region.width) && 4377 (extent <= MagickMaxBufferExtent)) 4378 { 4379 length=extent; 4380 rows=1UL; 4381 } 4382 for (y=0; y < (ssize_t) rows; y++) 4383 { 4384 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset* 4385 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q); 4386 if (count != (MagickOffsetType) length) 4387 break; 4388 offset+=cache_info->columns; 4389 q+=cache_info->number_channels*nexus_info->region.width; 4390 } 4391 if (IsFileDescriptorLimitExceeded() != MagickFalse) 4392 (void) ClosePixelCacheOnDisk(cache_info); 4393 UnlockSemaphoreInfo(cache_info->file_semaphore); 4394 break; 4395 } 4396 case DistributedCache: 4397 { 4398 RectangleInfo 4399 region; 4400 4401 /* 4402 Read pixels from distributed cache. 4403 */ 4404 LockSemaphoreInfo(cache_info->file_semaphore); 4405 region=nexus_info->region; 4406 if ((cache_info->columns != nexus_info->region.width) || 4407 (extent > MagickMaxBufferExtent)) 4408 region.height=1UL; 4409 else 4410 { 4411 length=extent; 4412 rows=1UL; 4413 } 4414 for (y=0; y < (ssize_t) rows; y++) 4415 { 4416 count=ReadDistributePixelCachePixels((DistributeCacheInfo *) 4417 cache_info->server_info,®ion,length,(unsigned char *) q); 4418 if (count != (MagickOffsetType) length) 4419 break; 4420 q+=cache_info->number_channels*nexus_info->region.width; 4421 region.y++; 4422 } 4423 UnlockSemaphoreInfo(cache_info->file_semaphore); 4424 break; 4425 } 4426 default: 4427 break; 4428 } 4429 if (y < (ssize_t) rows) 4430 { 4431 ThrowFileException(exception,CacheError,"UnableToReadPixelCache", 4432 cache_info->cache_filename); 4433 return(MagickFalse); 4434 } 4435 if ((cache_info->debug != MagickFalse) && 4436 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse)) 4437 (void) LogMagickEvent(CacheEvent,GetMagickModule(), 4438 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double) 4439 nexus_info->region.width,(double) nexus_info->region.height,(double) 4440 nexus_info->region.x,(double) nexus_info->region.y); 4441 return(MagickTrue); 4442} 4443 4444/* 4445%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4446% % 4447% % 4448% % 4449+ R e f e r e n c e P i x e l C a c h e % 4450% % 4451% % 4452% % 4453%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4454% 4455% ReferencePixelCache() increments the reference count associated with the 4456% pixel cache returning a pointer to the cache. 4457% 4458% The format of the ReferencePixelCache method is: 4459% 4460% Cache ReferencePixelCache(Cache cache_info) 4461% 4462% A description of each parameter follows: 4463% 4464% o cache_info: the pixel cache. 4465% 4466*/ 4467MagickPrivate Cache ReferencePixelCache(Cache cache) 4468{ 4469 CacheInfo 4470 *magick_restrict cache_info; 4471 4472 assert(cache != (Cache *) NULL); 4473 cache_info=(CacheInfo *) cache; 4474 assert(cache_info->signature == MagickCoreSignature); 4475 LockSemaphoreInfo(cache_info->semaphore); 4476 cache_info->reference_count++; 4477 UnlockSemaphoreInfo(cache_info->semaphore); 4478 return(cache_info); 4479} 4480 4481/* 4482%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4483% % 4484% % 4485% % 4486+ R e s e t P i x e l C a c h e E p o c h e % 4487% % 4488% % 4489% % 4490%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4491% 4492% ResetPixelCacheEpoch() resets the pixel cache epoch. 4493% 4494% The format of the ResetPixelCacheEpoch method is: 4495% 4496% void ResetPixelCacheEpoch(void) 4497% 4498*/ 4499MagickPrivate void ResetPixelCacheEpoch(void) 4500{ 4501 cache_epoch=0; 4502} 4503 4504/* 4505%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4506% % 4507% % 4508% % 4509+ S e t P i x e l C a c h e M e t h o d s % 4510% % 4511% % 4512% % 4513%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4514% 4515% SetPixelCacheMethods() sets the image pixel methods to the specified ones. 4516% 4517% The format of the SetPixelCacheMethods() method is: 4518% 4519% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods) 4520% 4521% A description of each parameter follows: 4522% 4523% o cache: the pixel cache. 4524% 4525% o cache_methods: Specifies a pointer to a CacheMethods structure. 4526% 4527*/ 4528MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods) 4529{ 4530 CacheInfo 4531 *magick_restrict cache_info; 4532 4533 GetOneAuthenticPixelFromHandler 4534 get_one_authentic_pixel_from_handler; 4535 4536 GetOneVirtualPixelFromHandler 4537 get_one_virtual_pixel_from_handler; 4538 4539 /* 4540 Set cache pixel methods. 4541 */ 4542 assert(cache != (Cache) NULL); 4543 assert(cache_methods != (CacheMethods *) NULL); 4544 cache_info=(CacheInfo *) cache; 4545 assert(cache_info->signature == MagickCoreSignature); 4546 if (cache_info->debug != MagickFalse) 4547 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 4548 cache_info->filename); 4549 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL) 4550 cache_info->methods.get_virtual_pixel_handler= 4551 cache_methods->get_virtual_pixel_handler; 4552 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL) 4553 cache_info->methods.destroy_pixel_handler= 4554 cache_methods->destroy_pixel_handler; 4555 if (cache_methods->get_virtual_metacontent_from_handler != 4556 (GetVirtualMetacontentFromHandler) NULL) 4557 cache_info->methods.get_virtual_metacontent_from_handler= 4558 cache_methods->get_virtual_metacontent_from_handler; 4559 if (cache_methods->get_authentic_pixels_handler != 4560 (GetAuthenticPixelsHandler) NULL) 4561 cache_info->methods.get_authentic_pixels_handler= 4562 cache_methods->get_authentic_pixels_handler; 4563 if (cache_methods->queue_authentic_pixels_handler != 4564 (QueueAuthenticPixelsHandler) NULL) 4565 cache_info->methods.queue_authentic_pixels_handler= 4566 cache_methods->queue_authentic_pixels_handler; 4567 if (cache_methods->sync_authentic_pixels_handler != 4568 (SyncAuthenticPixelsHandler) NULL) 4569 cache_info->methods.sync_authentic_pixels_handler= 4570 cache_methods->sync_authentic_pixels_handler; 4571 if (cache_methods->get_authentic_pixels_from_handler != 4572 (GetAuthenticPixelsFromHandler) NULL) 4573 cache_info->methods.get_authentic_pixels_from_handler= 4574 cache_methods->get_authentic_pixels_from_handler; 4575 if (cache_methods->get_authentic_metacontent_from_handler != 4576 (GetAuthenticMetacontentFromHandler) NULL) 4577 cache_info->methods.get_authentic_metacontent_from_handler= 4578 cache_methods->get_authentic_metacontent_from_handler; 4579 get_one_virtual_pixel_from_handler= 4580 cache_info->methods.get_one_virtual_pixel_from_handler; 4581 if (get_one_virtual_pixel_from_handler != 4582 (GetOneVirtualPixelFromHandler) NULL) 4583 cache_info->methods.get_one_virtual_pixel_from_handler= 4584 cache_methods->get_one_virtual_pixel_from_handler; 4585 get_one_authentic_pixel_from_handler= 4586 cache_methods->get_one_authentic_pixel_from_handler; 4587 if (get_one_authentic_pixel_from_handler != 4588 (GetOneAuthenticPixelFromHandler) NULL) 4589 cache_info->methods.get_one_authentic_pixel_from_handler= 4590 cache_methods->get_one_authentic_pixel_from_handler; 4591} 4592 4593/* 4594%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4595% % 4596% % 4597% % 4598+ S e t P i x e l C a c h e N e x u s P i x e l s % 4599% % 4600% % 4601% % 4602%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4603% 4604% SetPixelCacheNexusPixels() defines the region of the cache for the 4605% specified cache nexus. 4606% 4607% The format of the SetPixelCacheNexusPixels() method is: 4608% 4609% Quantum SetPixelCacheNexusPixels(const CacheInfo *cache_info, 4610% const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info, 4611% ExceptionInfo *exception) 4612% 4613% A description of each parameter follows: 4614% 4615% o cache_info: the pixel cache. 4616% 4617% o mode: ReadMode, WriteMode, or IOMode. 4618% 4619% o region: A pointer to the RectangleInfo structure that defines the 4620% region of this particular cache nexus. 4621% 4622% o nexus_info: the cache nexus to set. 4623% 4624% o exception: return any errors or warnings in this structure. 4625% 4626*/ 4627 4628static inline MagickBooleanType AcquireCacheNexusPixels( 4629 const CacheInfo *magick_restrict cache_info,NexusInfo *nexus_info, 4630 ExceptionInfo *exception) 4631{ 4632 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length)) 4633 return(MagickFalse); 4634 nexus_info->mapped=MagickFalse; 4635 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1, 4636 (size_t) nexus_info->length)); 4637 if (nexus_info->cache == (Quantum *) NULL) 4638 { 4639 nexus_info->mapped=MagickTrue; 4640 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t) 4641 nexus_info->length); 4642 } 4643 if (nexus_info->cache == (Quantum *) NULL) 4644 { 4645 (void) ThrowMagickException(exception,GetMagickModule(), 4646 ResourceLimitError,"MemoryAllocationFailed","`%s'", 4647 cache_info->filename); 4648 return(MagickFalse); 4649 } 4650 return(MagickTrue); 4651} 4652 4653static inline MagickBooleanType IsPixelCacheAuthentic( 4654 const CacheInfo *magick_restrict cache_info, 4655 const NexusInfo *magick_restrict nexus_info) 4656{ 4657 MagickBooleanType 4658 status; 4659 4660 MagickOffsetType 4661 offset; 4662 4663 /* 4664 Does nexus pixels point directly to in-core cache pixels or is it buffered? 4665 */ 4666 if (cache_info->type == PingCache) 4667 return(MagickTrue); 4668 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+ 4669 nexus_info->region.x; 4670 status=nexus_info->pixels == (cache_info->pixels+offset* 4671 cache_info->number_channels) ? MagickTrue : MagickFalse; 4672 return(status); 4673} 4674 4675static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info, 4676 const MapMode mode) 4677{ 4678 if (mode == ReadMode) 4679 { 4680 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1); 4681 return; 4682 } 4683 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1); 4684} 4685 4686static Quantum *SetPixelCacheNexusPixels(const CacheInfo *cache_info, 4687 const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info, 4688 ExceptionInfo *exception) 4689{ 4690 MagickBooleanType 4691 status; 4692 4693 MagickSizeType 4694 length, 4695 number_pixels; 4696 4697 assert(cache_info != (const CacheInfo *) NULL); 4698 assert(cache_info->signature == MagickCoreSignature); 4699 if (cache_info->type == UndefinedCache) 4700 return((Quantum *) NULL); 4701 nexus_info->region=(*region); 4702 if ((cache_info->type == MemoryCache) || (cache_info->type == MapCache)) 4703 { 4704 ssize_t 4705 x, 4706 y; 4707 4708 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1; 4709 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1; 4710 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) && 4711 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) && 4712 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) && 4713 ((nexus_info->region.width == cache_info->columns) || 4714 ((nexus_info->region.width % cache_info->columns) == 0))))) 4715 { 4716 MagickOffsetType 4717 offset; 4718 4719 /* 4720 Pixels are accessed directly from memory. 4721 */ 4722 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+ 4723 nexus_info->region.x; 4724 nexus_info->pixels=cache_info->pixels+cache_info->number_channels* 4725 offset; 4726 nexus_info->metacontent=(void *) NULL; 4727 if (cache_info->metacontent_extent != 0) 4728 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+ 4729 offset*cache_info->metacontent_extent; 4730 PrefetchPixelCacheNexusPixels(nexus_info,mode); 4731 nexus_info->authentic_pixel_cache=IsPixelCacheAuthentic(cache_info, 4732 nexus_info); 4733 return(nexus_info->pixels); 4734 } 4735 } 4736 /* 4737 Pixels are stored in a staging region until they are synced to the cache. 4738 */ 4739 number_pixels=(MagickSizeType) nexus_info->region.width* 4740 nexus_info->region.height; 4741 length=number_pixels*cache_info->number_channels*sizeof(Quantum); 4742 if (cache_info->metacontent_extent != 0) 4743 length+=number_pixels*cache_info->metacontent_extent; 4744 if (nexus_info->cache == (Quantum *) NULL) 4745 { 4746 nexus_info->length=length; 4747 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception); 4748 if (status == MagickFalse) 4749 { 4750 nexus_info->length=0; 4751 return((Quantum *) NULL); 4752 } 4753 } 4754 else 4755 if (nexus_info->length < length) 4756 { 4757 RelinquishCacheNexusPixels(nexus_info); 4758 nexus_info->length=length; 4759 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception); 4760 if (status == MagickFalse) 4761 { 4762 nexus_info->length=0; 4763 return((Quantum *) NULL); 4764 } 4765 } 4766 nexus_info->pixels=nexus_info->cache; 4767 nexus_info->metacontent=(void *) NULL; 4768 if (cache_info->metacontent_extent != 0) 4769 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels* 4770 cache_info->number_channels); 4771 PrefetchPixelCacheNexusPixels(nexus_info,mode); 4772 nexus_info->authentic_pixel_cache=IsPixelCacheAuthentic(cache_info, 4773 nexus_info); 4774 return(nexus_info->pixels); 4775} 4776 4777/* 4778%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4779% % 4780% % 4781% % 4782% S e t P i x e l C a c h e V i r t u a l M e t h o d % 4783% % 4784% % 4785% % 4786%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4787% 4788% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the 4789% pixel cache and returns the previous setting. A virtual pixel is any pixel 4790% access that is outside the boundaries of the image cache. 4791% 4792% The format of the SetPixelCacheVirtualMethod() method is: 4793% 4794% VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image, 4795% const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception) 4796% 4797% A description of each parameter follows: 4798% 4799% o image: the image. 4800% 4801% o virtual_pixel_method: choose the type of virtual pixel. 4802% 4803% o exception: return any errors or warnings in this structure. 4804% 4805*/ 4806 4807static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha, 4808 ExceptionInfo *exception) 4809{ 4810 CacheInfo 4811 *magick_restrict cache_info; 4812 4813 CacheView 4814 *magick_restrict image_view; 4815 4816 MagickBooleanType 4817 status; 4818 4819 ssize_t 4820 y; 4821 4822 assert(image != (Image *) NULL); 4823 assert(image->signature == MagickCoreSignature); 4824 if (image->debug != MagickFalse) 4825 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 4826 assert(image->cache != (Cache) NULL); 4827 cache_info=(CacheInfo *) image->cache; 4828 assert(cache_info->signature == MagickCoreSignature); 4829 image->alpha_trait=BlendPixelTrait; 4830 status=MagickTrue; 4831 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */ 4832#if defined(MAGICKCORE_OPENMP_SUPPORT) 4833 #pragma omp parallel for schedule(static,4) shared(status) \ 4834 magick_threads(image,image,1,1) 4835#endif 4836 for (y=0; y < (ssize_t) image->rows; y++) 4837 { 4838 register Quantum 4839 *magick_restrict q; 4840 4841 register ssize_t 4842 x; 4843 4844 if (status == MagickFalse) 4845 continue; 4846 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception); 4847 if (q == (Quantum *) NULL) 4848 { 4849 status=MagickFalse; 4850 continue; 4851 } 4852 for (x=0; x < (ssize_t) image->columns; x++) 4853 { 4854 SetPixelAlpha(image,alpha,q); 4855 q+=GetPixelChannels(image); 4856 } 4857 status=SyncCacheViewAuthenticPixels(image_view,exception); 4858 } 4859 image_view=DestroyCacheView(image_view); 4860 return(status); 4861} 4862 4863MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image, 4864 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception) 4865{ 4866 CacheInfo 4867 *magick_restrict cache_info; 4868 4869 VirtualPixelMethod 4870 method; 4871 4872 assert(image != (Image *) NULL); 4873 assert(image->signature == MagickCoreSignature); 4874 if (image->debug != MagickFalse) 4875 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 4876 assert(image->cache != (Cache) NULL); 4877 cache_info=(CacheInfo *) image->cache; 4878 assert(cache_info->signature == MagickCoreSignature); 4879 method=cache_info->virtual_pixel_method; 4880 cache_info->virtual_pixel_method=virtual_pixel_method; 4881 if ((image->columns != 0) && (image->rows != 0)) 4882 switch (virtual_pixel_method) 4883 { 4884 case BackgroundVirtualPixelMethod: 4885 { 4886 if ((image->background_color.alpha_trait != UndefinedPixelTrait) && 4887 (image->alpha_trait == UndefinedPixelTrait)) 4888 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception); 4889 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) && 4890 (IsGrayColorspace(image->colorspace) != MagickFalse)) 4891 (void) SetImageColorspace(image,sRGBColorspace,exception); 4892 break; 4893 } 4894 case TransparentVirtualPixelMethod: 4895 { 4896 if (image->alpha_trait == UndefinedPixelTrait) 4897 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception); 4898 break; 4899 } 4900 default: 4901 break; 4902 } 4903 return(method); 4904} 4905 4906#if defined(MAGICKCORE_OPENCL_SUPPORT) 4907/* 4908%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4909% % 4910% % 4911% % 4912+ S y n c A u t h e n t i c O p e n C L B u f f e r % 4913% % 4914% % 4915% % 4916%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4917% 4918% SyncAuthenticOpenCLBuffer() makes sure that all the OpenCL operations have 4919% been completed and updates the host memory. 4920% 4921% The format of the SyncAuthenticOpenCLBuffer() method is: 4922% 4923% void SyncAuthenticOpenCLBuffer(const Image *image) 4924% 4925% A description of each parameter follows: 4926% 4927% o image: the image. 4928% 4929*/ 4930static void CopyOpenCLBuffer(CacheInfo *magick_restrict cache_info) 4931{ 4932 assert(cache_info != (CacheInfo *) NULL); 4933 assert(cache_info->signature == MagickCoreSignature); 4934 if ((cache_info->type != MemoryCache) || 4935 (cache_info->opencl == (MagickCLCacheInfo) NULL)) 4936 return; 4937 /* 4938 Ensure single threaded access to OpenCL environment. 4939 */ 4940 LockSemaphoreInfo(cache_info->semaphore); 4941 cache_info->opencl=(MagickCLCacheInfo) CopyMagickCLCacheInfo( 4942 cache_info->opencl); 4943 UnlockSemaphoreInfo(cache_info->semaphore); 4944} 4945 4946MagickPrivate void SyncAuthenticOpenCLBuffer(const Image *image) 4947{ 4948 CacheInfo 4949 *magick_restrict cache_info; 4950 4951 assert(image != (const Image *) NULL); 4952 cache_info=(CacheInfo *) image->cache; 4953 CopyOpenCLBuffer(cache_info); 4954} 4955#endif 4956 4957/* 4958%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4959% % 4960% % 4961% % 4962+ S y n c A u t h e n t i c P i x e l C a c h e N e x u s % 4963% % 4964% % 4965% % 4966%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4967% 4968% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the 4969% in-memory or disk cache. The method returns MagickTrue if the pixel region 4970% is synced, otherwise MagickFalse. 4971% 4972% The format of the SyncAuthenticPixelCacheNexus() method is: 4973% 4974% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image, 4975% NexusInfo *nexus_info,ExceptionInfo *exception) 4976% 4977% A description of each parameter follows: 4978% 4979% o image: the image. 4980% 4981% o nexus_info: the cache nexus to sync. 4982% 4983% o exception: return any errors or warnings in this structure. 4984% 4985*/ 4986MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image, 4987 NexusInfo *magick_restrict nexus_info,ExceptionInfo *exception) 4988{ 4989 CacheInfo 4990 *magick_restrict cache_info; 4991 4992 MagickBooleanType 4993 status; 4994 4995 /* 4996 Transfer pixels to the cache. 4997 */ 4998 assert(image != (Image *) NULL); 4999 assert(image->signature == MagickCoreSignature); 5000 if (image->cache == (Cache) NULL) 5001 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename); 5002 cache_info=(CacheInfo *) image->cache; 5003 assert(cache_info->signature == MagickCoreSignature); 5004 if (cache_info->type == UndefinedCache) 5005 return(MagickFalse); 5006 if (nexus_info->authentic_pixel_cache != MagickFalse) 5007 { 5008 image->taint=MagickTrue; 5009 return(MagickTrue); 5010 } 5011 assert(cache_info->signature == MagickCoreSignature); 5012 status=WritePixelCachePixels(cache_info,nexus_info,exception); 5013 if ((cache_info->metacontent_extent != 0) && 5014 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)) 5015 return(MagickFalse); 5016 if (status != MagickFalse) 5017 image->taint=MagickTrue; 5018 return(status); 5019} 5020 5021/* 5022%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5023% % 5024% % 5025% % 5026+ S y n c A u t h e n t i c P i x e l C a c h e % 5027% % 5028% % 5029% % 5030%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5031% 5032% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory 5033% or disk cache. The method returns MagickTrue if the pixel region is synced, 5034% otherwise MagickFalse. 5035% 5036% The format of the SyncAuthenticPixelsCache() method is: 5037% 5038% MagickBooleanType SyncAuthenticPixelsCache(Image *image, 5039% ExceptionInfo *exception) 5040% 5041% A description of each parameter follows: 5042% 5043% o image: the image. 5044% 5045% o exception: return any errors or warnings in this structure. 5046% 5047*/ 5048static MagickBooleanType SyncAuthenticPixelsCache(Image *image, 5049 ExceptionInfo *exception) 5050{ 5051 CacheInfo 5052 *magick_restrict cache_info; 5053 5054 const int 5055 id = GetOpenMPThreadId(); 5056 5057 MagickBooleanType 5058 status; 5059 5060 assert(image != (Image *) NULL); 5061 assert(image->signature == MagickCoreSignature); 5062 assert(image->cache != (Cache) NULL); 5063 cache_info=(CacheInfo *) image->cache; 5064 assert(cache_info->signature == MagickCoreSignature); 5065 assert(id < (int) cache_info->number_threads); 5066 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id], 5067 exception); 5068 return(status); 5069} 5070 5071/* 5072%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5073% % 5074% % 5075% % 5076% S y n c A u t h e n t i c P i x e l s % 5077% % 5078% % 5079% % 5080%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5081% 5082% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache. 5083% The method returns MagickTrue if the pixel region is flushed, otherwise 5084% MagickFalse. 5085% 5086% The format of the SyncAuthenticPixels() method is: 5087% 5088% MagickBooleanType SyncAuthenticPixels(Image *image, 5089% ExceptionInfo *exception) 5090% 5091% A description of each parameter follows: 5092% 5093% o image: the image. 5094% 5095% o exception: return any errors or warnings in this structure. 5096% 5097*/ 5098MagickExport MagickBooleanType SyncAuthenticPixels(Image *image, 5099 ExceptionInfo *exception) 5100{ 5101 CacheInfo 5102 *magick_restrict cache_info; 5103 5104 const int 5105 id = GetOpenMPThreadId(); 5106 5107 MagickBooleanType 5108 status; 5109 5110 assert(image != (Image *) NULL); 5111 assert(image->signature == MagickCoreSignature); 5112 assert(image->cache != (Cache) NULL); 5113 cache_info=(CacheInfo *) image->cache; 5114 assert(cache_info->signature == MagickCoreSignature); 5115 if (cache_info->methods.sync_authentic_pixels_handler != 5116 (SyncAuthenticPixelsHandler) NULL) 5117 { 5118 status=cache_info->methods.sync_authentic_pixels_handler(image, 5119 exception); 5120 return(status); 5121 } 5122 assert(id < (int) cache_info->number_threads); 5123 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id], 5124 exception); 5125 return(status); 5126} 5127 5128/* 5129%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5130% % 5131% % 5132% % 5133+ S y n c I m a g e P i x e l C a c h e % 5134% % 5135% % 5136% % 5137%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5138% 5139% SyncImagePixelCache() saves the image pixels to the in-memory or disk cache. 5140% The method returns MagickTrue if the pixel region is flushed, otherwise 5141% MagickFalse. 5142% 5143% The format of the SyncImagePixelCache() method is: 5144% 5145% MagickBooleanType SyncImagePixelCache(Image *image, 5146% ExceptionInfo *exception) 5147% 5148% A description of each parameter follows: 5149% 5150% o image: the image. 5151% 5152% o exception: return any errors or warnings in this structure. 5153% 5154*/ 5155MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image, 5156 ExceptionInfo *exception) 5157{ 5158 CacheInfo 5159 *magick_restrict cache_info; 5160 5161 assert(image != (Image *) NULL); 5162 assert(exception != (ExceptionInfo *) NULL); 5163 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception); 5164 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue); 5165} 5166 5167/* 5168%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5169% % 5170% % 5171% % 5172+ W r i t e P i x e l C a c h e M e t a c o n t e n t % 5173% % 5174% % 5175% % 5176%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5177% 5178% WritePixelCacheMetacontent() writes the meta-content to the specified region 5179% of the pixel cache. 5180% 5181% The format of the WritePixelCacheMetacontent() method is: 5182% 5183% MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info, 5184% NexusInfo *nexus_info,ExceptionInfo *exception) 5185% 5186% A description of each parameter follows: 5187% 5188% o cache_info: the pixel cache. 5189% 5190% o nexus_info: the cache nexus to write the meta-content. 5191% 5192% o exception: return any errors or warnings in this structure. 5193% 5194*/ 5195static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info, 5196 NexusInfo *magick_restrict nexus_info,ExceptionInfo *exception) 5197{ 5198 MagickOffsetType 5199 count, 5200 offset; 5201 5202 MagickSizeType 5203 extent, 5204 length; 5205 5206 register const unsigned char 5207 *magick_restrict p; 5208 5209 register ssize_t 5210 y; 5211 5212 size_t 5213 rows; 5214 5215 if (cache_info->metacontent_extent == 0) 5216 return(MagickFalse); 5217 if (nexus_info->authentic_pixel_cache != MagickFalse) 5218 return(MagickTrue); 5219 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+ 5220 nexus_info->region.x; 5221 length=(MagickSizeType) nexus_info->region.width* 5222 cache_info->metacontent_extent; 5223 extent=(MagickSizeType) length*nexus_info->region.height; 5224 rows=nexus_info->region.height; 5225 y=0; 5226 p=(unsigned char *) nexus_info->metacontent; 5227 switch (cache_info->type) 5228 { 5229 case MemoryCache: 5230 case MapCache: 5231 { 5232 register unsigned char 5233 *magick_restrict q; 5234 5235 /* 5236 Write associated pixels to memory. 5237 */ 5238 if ((cache_info->columns == nexus_info->region.width) && 5239 (extent == (MagickSizeType) ((size_t) extent))) 5240 { 5241 length=extent; 5242 rows=1UL; 5243 } 5244 q=(unsigned char *) cache_info->metacontent+offset* 5245 cache_info->metacontent_extent; 5246 for (y=0; y < (ssize_t) rows; y++) 5247 { 5248 (void) memcpy(q,p,(size_t) length); 5249 p+=nexus_info->region.width*cache_info->metacontent_extent; 5250 q+=cache_info->columns*cache_info->metacontent_extent; 5251 } 5252 break; 5253 } 5254 case DiskCache: 5255 { 5256 /* 5257 Write associated pixels to disk. 5258 */ 5259 LockSemaphoreInfo(cache_info->file_semaphore); 5260 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse) 5261 { 5262 ThrowFileException(exception,FileOpenError,"UnableToOpenFile", 5263 cache_info->cache_filename); 5264 UnlockSemaphoreInfo(cache_info->file_semaphore); 5265 return(MagickFalse); 5266 } 5267 if ((cache_info->columns == nexus_info->region.width) && 5268 (extent <= MagickMaxBufferExtent)) 5269 { 5270 length=extent; 5271 rows=1UL; 5272 } 5273 extent=(MagickSizeType) cache_info->columns*cache_info->rows; 5274 for (y=0; y < (ssize_t) rows; y++) 5275 { 5276 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent* 5277 cache_info->number_channels*sizeof(Quantum)+offset* 5278 cache_info->metacontent_extent,length,(const unsigned char *) p); 5279 if (count != (MagickOffsetType) length) 5280 break; 5281 p+=cache_info->metacontent_extent*nexus_info->region.width; 5282 offset+=cache_info->columns; 5283 } 5284 if (IsFileDescriptorLimitExceeded() != MagickFalse) 5285 (void) ClosePixelCacheOnDisk(cache_info); 5286 UnlockSemaphoreInfo(cache_info->file_semaphore); 5287 break; 5288 } 5289 case DistributedCache: 5290 { 5291 RectangleInfo 5292 region; 5293 5294 /* 5295 Write metacontent to distributed cache. 5296 */ 5297 LockSemaphoreInfo(cache_info->file_semaphore); 5298 region=nexus_info->region; 5299 if ((cache_info->columns != nexus_info->region.width) || 5300 (extent > MagickMaxBufferExtent)) 5301 region.height=1UL; 5302 else 5303 { 5304 length=extent; 5305 rows=1UL; 5306 } 5307 for (y=0; y < (ssize_t) rows; y++) 5308 { 5309 count=WriteDistributePixelCacheMetacontent((DistributeCacheInfo *) 5310 cache_info->server_info,®ion,length,(const unsigned char *) p); 5311 if (count != (MagickOffsetType) length) 5312 break; 5313 p+=cache_info->metacontent_extent*nexus_info->region.width; 5314 region.y++; 5315 } 5316 UnlockSemaphoreInfo(cache_info->file_semaphore); 5317 break; 5318 } 5319 default: 5320 break; 5321 } 5322 if (y < (ssize_t) rows) 5323 { 5324 ThrowFileException(exception,CacheError,"UnableToWritePixelCache", 5325 cache_info->cache_filename); 5326 return(MagickFalse); 5327 } 5328 if ((cache_info->debug != MagickFalse) && 5329 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse)) 5330 (void) LogMagickEvent(CacheEvent,GetMagickModule(), 5331 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double) 5332 nexus_info->region.width,(double) nexus_info->region.height,(double) 5333 nexus_info->region.x,(double) nexus_info->region.y); 5334 return(MagickTrue); 5335} 5336 5337/* 5338%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5339% % 5340% % 5341% % 5342+ W r i t e C a c h e P i x e l s % 5343% % 5344% % 5345% % 5346%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5347% 5348% WritePixelCachePixels() writes image pixels to the specified region of the 5349% pixel cache. 5350% 5351% The format of the WritePixelCachePixels() method is: 5352% 5353% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info, 5354% NexusInfo *nexus_info,ExceptionInfo *exception) 5355% 5356% A description of each parameter follows: 5357% 5358% o cache_info: the pixel cache. 5359% 5360% o nexus_info: the cache nexus to write the pixels. 5361% 5362% o exception: return any errors or warnings in this structure. 5363% 5364*/ 5365static MagickBooleanType WritePixelCachePixels( 5366 CacheInfo *magick_restrict cache_info,NexusInfo *magick_restrict nexus_info, 5367 ExceptionInfo *exception) 5368{ 5369 MagickOffsetType 5370 count, 5371 offset; 5372 5373 MagickSizeType 5374 extent, 5375 length; 5376 5377 register const Quantum 5378 *magick_restrict p; 5379 5380 register ssize_t 5381 y; 5382 5383 size_t 5384 rows; 5385 5386 if (nexus_info->authentic_pixel_cache != MagickFalse) 5387 return(MagickTrue); 5388 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+ 5389 nexus_info->region.x; 5390 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width* 5391 sizeof(Quantum); 5392 extent=length*nexus_info->region.height; 5393 rows=nexus_info->region.height; 5394 y=0; 5395 p=nexus_info->pixels; 5396 switch (cache_info->type) 5397 { 5398 case MemoryCache: 5399 case MapCache: 5400 { 5401 register Quantum 5402 *magick_restrict q; 5403 5404 /* 5405 Write pixels to memory. 5406 */ 5407 if ((cache_info->columns == nexus_info->region.width) && 5408 (extent == (MagickSizeType) ((size_t) extent))) 5409 { 5410 length=extent; 5411 rows=1UL; 5412 } 5413 q=cache_info->pixels+offset*cache_info->number_channels; 5414 for (y=0; y < (ssize_t) rows; y++) 5415 { 5416 (void) memcpy(q,p,(size_t) length); 5417 p+=cache_info->number_channels*nexus_info->region.width; 5418 q+=cache_info->columns*cache_info->number_channels; 5419 } 5420 break; 5421 } 5422 case DiskCache: 5423 { 5424 /* 5425 Write pixels to disk. 5426 */ 5427 LockSemaphoreInfo(cache_info->file_semaphore); 5428 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse) 5429 { 5430 ThrowFileException(exception,FileOpenError,"UnableToOpenFile", 5431 cache_info->cache_filename); 5432 UnlockSemaphoreInfo(cache_info->file_semaphore); 5433 return(MagickFalse); 5434 } 5435 if ((cache_info->columns == nexus_info->region.width) && 5436 (extent <= MagickMaxBufferExtent)) 5437 { 5438 length=extent; 5439 rows=1UL; 5440 } 5441 for (y=0; y < (ssize_t) rows; y++) 5442 { 5443 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset* 5444 cache_info->number_channels*sizeof(*p),length,(const unsigned char *) 5445 p); 5446 if (count != (MagickOffsetType) length) 5447 break; 5448 p+=cache_info->number_channels*nexus_info->region.width; 5449 offset+=cache_info->columns; 5450 } 5451 if (IsFileDescriptorLimitExceeded() != MagickFalse) 5452 (void) ClosePixelCacheOnDisk(cache_info); 5453 UnlockSemaphoreInfo(cache_info->file_semaphore); 5454 break; 5455 } 5456 case DistributedCache: 5457 { 5458 RectangleInfo 5459 region; 5460 5461 /* 5462 Write pixels to distributed cache. 5463 */ 5464 LockSemaphoreInfo(cache_info->file_semaphore); 5465 region=nexus_info->region; 5466 if ((cache_info->columns != nexus_info->region.width) || 5467 (extent > MagickMaxBufferExtent)) 5468 region.height=1UL; 5469 else 5470 { 5471 length=extent; 5472 rows=1UL; 5473 } 5474 for (y=0; y < (ssize_t) rows; y++) 5475 { 5476 count=WriteDistributePixelCachePixels((DistributeCacheInfo *) 5477 cache_info->server_info,®ion,length,(const unsigned char *) p); 5478 if (count != (MagickOffsetType) length) 5479 break; 5480 p+=cache_info->number_channels*nexus_info->region.width; 5481 region.y++; 5482 } 5483 UnlockSemaphoreInfo(cache_info->file_semaphore); 5484 break; 5485 } 5486 default: 5487 break; 5488 } 5489 if (y < (ssize_t) rows) 5490 { 5491 ThrowFileException(exception,CacheError,"UnableToWritePixelCache", 5492 cache_info->cache_filename); 5493 return(MagickFalse); 5494 } 5495 if ((cache_info->debug != MagickFalse) && 5496 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse)) 5497 (void) LogMagickEvent(CacheEvent,GetMagickModule(), 5498 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double) 5499 nexus_info->region.width,(double) nexus_info->region.height,(double) 5500 nexus_info->region.x,(double) nexus_info->region.y); 5501 return(MagickTrue); 5502} 5503