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