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