image-view.c revision 46ff2676b1044ea4101ac7a59b83289cd8f6cfda
1/* 2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3% % 4% % 5% IIIII M M AAA GGGG EEEEE % 6% I MM MM A A G E % 7% I M M M AAAAA G GG EEE % 8% I M M A A G G E % 9% IIIII M M A A GGGG EEEEE % 10% % 11% V V IIIII EEEEE W W % 12% V V I E W W % 13% V V I EEE W W W % 14% V V I E WW WW % 15% V IIIII EEEEE W W % 16% % 17% % 18% MagickCore Image View Methods % 19% % 20% Software Design % 21% John Cristy % 22% March 2003 % 23% % 24% % 25% Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization % 26% dedicated to making software imaging solutions freely available. % 27% % 28% You may not use this file except in compliance with the License. You may % 29% obtain a copy of the License at % 30% % 31% http://www.imagemagick.org/script/license.php % 32% % 33% Unless required by applicable law or agreed to in writing, software % 34% distributed under the License is distributed on an "AS IS" BASIS, % 35% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 36% See the License for the specific language governing permissions and % 37% limitations under the License. % 38% % 39%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 40% 41% 42% 43*/ 44 45/* 46 Include declarations. 47*/ 48#include "MagickCore/studio.h" 49#include "MagickCore/MagickCore.h" 50#include "MagickCore/exception-private.h" 51#include "MagickCore/monitor-private.h" 52#include "MagickCore/thread-private.h" 53 54/* 55 Typedef declarations. 56*/ 57struct _ImageView 58{ 59 char 60 *description; 61 62 RectangleInfo 63 extent; 64 65 Image 66 *image; 67 68 CacheView 69 *view; 70 71 ExceptionInfo 72 *exception; 73 74 MagickBooleanType 75 debug; 76 77 size_t 78 signature; 79}; 80 81/* 82%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 83% % 84% % 85% % 86% C l o n e I m a g e V i e w % 87% % 88% % 89% % 90%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 91% 92% CloneImageView() makes a copy of the specified image view. 93% 94% The format of the CloneImageView method is: 95% 96% ImageView *CloneImageView(const ImageView *image_view) 97% 98% A description of each parameter follows: 99% 100% o image_view: the image view. 101% 102*/ 103MagickExport ImageView *CloneImageView(const ImageView *image_view) 104{ 105 ImageView 106 *clone_view; 107 108 assert(image_view != (ImageView *) NULL); 109 assert(image_view->signature == MagickSignature); 110 clone_view=(ImageView *) AcquireMagickMemory(sizeof(*clone_view)); 111 if (clone_view == (ImageView *) NULL) 112 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 113 (void) ResetMagickMemory(clone_view,0,sizeof(*clone_view)); 114 clone_view->description=ConstantString(image_view->description); 115 clone_view->extent=image_view->extent; 116 clone_view->view=CloneCacheView(image_view->view); 117 clone_view->exception=AcquireExceptionInfo(); 118 InheritException(clone_view->exception,image_view->exception); 119 clone_view->debug=image_view->debug; 120 clone_view->signature=MagickSignature; 121 return(clone_view); 122} 123 124/* 125%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 126% % 127% % 128% % 129% D e s t r o y I m a g e V i e w % 130% % 131% % 132% % 133%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 134% 135% DestroyImageView() deallocates memory associated with a image view. 136% 137% The format of the DestroyImageView method is: 138% 139% ImageView *DestroyImageView(ImageView *image_view) 140% 141% A description of each parameter follows: 142% 143% o image_view: the image view. 144% 145*/ 146MagickExport ImageView *DestroyImageView(ImageView *image_view) 147{ 148 assert(image_view != (ImageView *) NULL); 149 assert(image_view->signature == MagickSignature); 150 if (image_view->description != (char *) NULL) 151 image_view->description=DestroyString(image_view->description); 152 image_view->view=DestroyCacheView(image_view->view); 153 image_view->exception=DestroyExceptionInfo(image_view->exception); 154 image_view->signature=(~MagickSignature); 155 image_view=(ImageView *) RelinquishMagickMemory(image_view); 156 return(image_view); 157} 158 159/* 160%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 161% % 162% % 163% % 164% D u p l e x T r a n s f e r I m a g e V i e w I t e r a t o r % 165% % 166% % 167% % 168%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 169% 170% DuplexTransferImageViewIterator() iterates over three image views in 171% parallel and calls your transfer method for each scanline of the view. The 172% source and duplex pixel extent is not confined to the image canvas-- that is 173% you can include negative offsets or widths or heights that exceed the image 174% dimension. However, the destination image view is confined to the image 175% canvas-- that is no negative offsets or widths or heights that exceed the 176% image dimension are permitted. 177% 178% The callback signature is: 179% 180% MagickBooleanType DuplexTransferImageViewMethod(const ImageView *source, 181% const ImageView *duplex,ImageView *destination,const ssize_t y, 182% const int thread_id,void *context) 183% 184% Use this pragma if the view is not single threaded: 185% 186% #pragma omp critical 187% 188% to define a section of code in your callback transfer method that must be 189% executed by a single thread at a time. 190% 191% The format of the DuplexTransferImageViewIterator method is: 192% 193% MagickBooleanType DuplexTransferImageViewIterator(ImageView *source, 194% ImageView *duplex,ImageView *destination, 195% DuplexTransferImageViewMethod transfer,void *context) 196% 197% A description of each parameter follows: 198% 199% o source: the source image view. 200% 201% o duplex: the duplex image view. 202% 203% o destination: the destination image view. 204% 205% o transfer: the transfer callback method. 206% 207% o context: the user defined context. 208% 209*/ 210MagickExport MagickBooleanType DuplexTransferImageViewIterator( 211 ImageView *source,ImageView *duplex,ImageView *destination, 212 DuplexTransferImageViewMethod transfer,void *context) 213{ 214 Image 215 *destination_image, 216 *source_image; 217 218 MagickBooleanType 219 status; 220 221 MagickOffsetType 222 progress; 223 224#if defined(MAGICKCORE_OPENMP_SUPPORT) 225 size_t 226 height, 227 width; 228#endif 229 230 ssize_t 231 y; 232 233 assert(source != (ImageView *) NULL); 234 assert(source->signature == MagickSignature); 235 if (transfer == (DuplexTransferImageViewMethod) NULL) 236 return(MagickFalse); 237 source_image=source->image; 238 destination_image=destination->image; 239 status=SetImageStorageClass(destination_image,DirectClass, 240 destination->exception); 241 if (status == MagickFalse) 242 return(MagickFalse); 243 status=MagickTrue; 244 progress=0; 245#if defined(MAGICKCORE_OPENMP_SUPPORT) 246 height=source->extent.height-source->extent.y; 247 width=source->extent.width-source->extent.x; 248 #pragma omp parallel for schedule(static,4) shared(progress,status) \ 249 dynamic_number_threads(source_image,width,height,1) 250#endif 251 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++) 252 { 253 const int 254 id = GetOpenMPThreadId(); 255 256 MagickBooleanType 257 sync; 258 259 register const Quantum 260 *restrict duplex_pixels, 261 *restrict pixels; 262 263 register Quantum 264 *restrict destination_pixels; 265 266 if (status == MagickFalse) 267 continue; 268 pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y, 269 source->extent.width,1,source->exception); 270 if (pixels == (const Quantum *) NULL) 271 { 272 status=MagickFalse; 273 continue; 274 } 275 duplex_pixels=GetCacheViewVirtualPixels(duplex->view,duplex->extent.x,y, 276 duplex->extent.width,1,duplex->exception); 277 if (duplex_pixels == (const Quantum *) NULL) 278 { 279 status=MagickFalse; 280 continue; 281 } 282 destination_pixels=GetCacheViewAuthenticPixels(destination->view, 283 destination->extent.x,y,destination->extent.width,1, 284 destination->exception); 285 if (destination_pixels == (Quantum *) NULL) 286 { 287 status=MagickFalse; 288 continue; 289 } 290 if (transfer(source,duplex,destination,y,id,context) == MagickFalse) 291 status=MagickFalse; 292 sync=SyncCacheViewAuthenticPixels(destination->view,destination->exception); 293 if (sync == MagickFalse) 294 status=MagickFalse; 295 if (source_image->progress_monitor != (MagickProgressMonitor) NULL) 296 { 297 MagickBooleanType 298 proceed; 299 300#if defined(MAGICKCORE_OPENMP_SUPPORT) 301 #pragma omp critical (MagickCore_DuplexTransferImageViewIterator) 302#endif 303 proceed=SetImageProgress(source_image,source->description,progress++, 304 source->extent.height); 305 if (proceed == MagickFalse) 306 status=MagickFalse; 307 } 308 } 309 return(status); 310} 311 312/* 313%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 314% % 315% % 316% % 317% G e t I m a g e V i e w A u t h e n t i c M e t a c o n t e n t % 318% % 319% % 320% % 321%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 322% 323% GetImageViewAuthenticMetacontent() returns the image view authentic 324% meta-content. 325% 326% The format of the GetImageViewAuthenticPixels method is: 327% 328% void *GetImageViewAuthenticMetacontent( 329% const ImageView *image_view) 330% 331% A description of each parameter follows: 332% 333% o image_view: the image view. 334% 335*/ 336MagickExport void *GetImageViewAuthenticMetacontent( 337 const ImageView *image_view) 338{ 339 assert(image_view != (ImageView *) NULL); 340 assert(image_view->signature == MagickSignature); 341 return(GetCacheViewAuthenticMetacontent(image_view->view)); 342} 343 344/* 345%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 346% % 347% % 348% % 349% G e t I m a g e V i e w A u t h e n t i c P i x e l s % 350% % 351% % 352% % 353%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 354% 355% GetImageViewAuthenticPixels() returns the image view authentic pixels. 356% 357% The format of the GetImageViewAuthenticPixels method is: 358% 359% Quantum *GetImageViewAuthenticPixels(const ImageView *image_view) 360% 361% A description of each parameter follows: 362% 363% o image_view: the image view. 364% 365*/ 366MagickExport Quantum *GetImageViewAuthenticPixels( 367 const ImageView *image_view) 368{ 369 assert(image_view != (ImageView *) NULL); 370 assert(image_view->signature == MagickSignature); 371 return(GetCacheViewAuthenticPixelQueue(image_view->view)); 372} 373 374/* 375%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 376% % 377% % 378% % 379% G e t I m a g e V i e w E x c e p t i o n % 380% % 381% % 382% % 383%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 384% 385% GetImageViewException() returns the severity, reason, and description of any 386% error that occurs when utilizing a image view. 387% 388% The format of the GetImageViewException method is: 389% 390% char *GetImageViewException(const PixelImage *image_view, 391% ExceptionType *severity) 392% 393% A description of each parameter follows: 394% 395% o image_view: the pixel image_view. 396% 397% o severity: the severity of the error is returned here. 398% 399*/ 400MagickExport char *GetImageViewException(const ImageView *image_view, 401 ExceptionType *severity) 402{ 403 char 404 *description; 405 406 assert(image_view != (const ImageView *) NULL); 407 assert(image_view->signature == MagickSignature); 408 assert(severity != (ExceptionType *) NULL); 409 *severity=image_view->exception->severity; 410 description=(char *) AcquireQuantumMemory(2UL*MaxTextExtent, 411 sizeof(*description)); 412 if (description == (char *) NULL) 413 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 414 *description='\0'; 415 if (image_view->exception->reason != (char *) NULL) 416 (void) CopyMagickString(description,GetLocaleExceptionMessage( 417 image_view->exception->severity,image_view->exception->reason), 418 MaxTextExtent); 419 if (image_view->exception->description != (char *) NULL) 420 { 421 (void) ConcatenateMagickString(description," (",MaxTextExtent); 422 (void) ConcatenateMagickString(description,GetLocaleExceptionMessage( 423 image_view->exception->severity,image_view->exception->description), 424 MaxTextExtent); 425 (void) ConcatenateMagickString(description,")",MaxTextExtent); 426 } 427 return(description); 428} 429 430/* 431%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 432% % 433% % 434% % 435% G e t I m a g e V i e w E x t e n t % 436% % 437% % 438% % 439%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 440% 441% GetImageViewExtent() returns the image view extent. 442% 443% The format of the GetImageViewExtent method is: 444% 445% RectangleInfo GetImageViewExtent(const ImageView *image_view) 446% 447% A description of each parameter follows: 448% 449% o image_view: the image view. 450% 451*/ 452MagickExport RectangleInfo GetImageViewExtent(const ImageView *image_view) 453{ 454 assert(image_view != (ImageView *) NULL); 455 assert(image_view->signature == MagickSignature); 456 return(image_view->extent); 457} 458 459/* 460%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 461% % 462% % 463% % 464% G e t I m a g e V i e w I m a g e % 465% % 466% % 467% % 468%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 469% 470% GetImageViewImage() returns the image associated with the image view. 471% 472% The format of the GetImageViewImage method is: 473% 474% MagickCore *GetImageViewImage(const ImageView *image_view) 475% 476% A description of each parameter follows: 477% 478% o image_view: the image view. 479% 480*/ 481MagickExport Image *GetImageViewImage(const ImageView *image_view) 482{ 483 assert(image_view != (ImageView *) NULL); 484 assert(image_view->signature == MagickSignature); 485 return(image_view->image); 486} 487 488/* 489%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 490% % 491% % 492% % 493% G e t I m a g e V i e w I t e r a t o r % 494% % 495% % 496% % 497%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 498% 499% GetImageViewIterator() iterates over the image view in parallel and calls 500% your get method for each scanline of the view. The pixel extent is 501% not confined to the image canvas-- that is you can include negative offsets 502% or widths or heights that exceed the image dimension. Any updates to 503% the pixels in your callback are ignored. 504% 505% The callback signature is: 506% 507% MagickBooleanType GetImageViewMethod(const ImageView *source, 508% const ssize_t y,const int thread_id,void *context) 509% 510% Use this pragma if the view is not single threaded: 511% 512% #pragma omp critical 513% 514% to define a section of code in your callback get method that must be 515% executed by a single thread at a time. 516% 517% The format of the GetImageViewIterator method is: 518% 519% MagickBooleanType GetImageViewIterator(ImageView *source, 520% GetImageViewMethod get,void *context) 521% 522% A description of each parameter follows: 523% 524% o source: the source image view. 525% 526% o get: the get callback method. 527% 528% o context: the user defined context. 529% 530*/ 531MagickExport MagickBooleanType GetImageViewIterator(ImageView *source, 532 GetImageViewMethod get,void *context) 533{ 534 Image 535 *source_image; 536 537 MagickBooleanType 538 status; 539 540 MagickOffsetType 541 progress; 542 543#if defined(MAGICKCORE_OPENMP_SUPPORT) 544 size_t 545 height, 546 width; 547#endif 548 549 ssize_t 550 y; 551 552 assert(source != (ImageView *) NULL); 553 assert(source->signature == MagickSignature); 554 if (get == (GetImageViewMethod) NULL) 555 return(MagickFalse); 556 source_image=source->image; 557 status=MagickTrue; 558 progress=0; 559#if defined(MAGICKCORE_OPENMP_SUPPORT) 560 height=source->extent.height-source->extent.y; 561 width=source->extent.width-source->extent.x; 562 #pragma omp parallel for schedule(static,4) shared(progress,status) \ 563 dynamic_number_threads(source_image,width,height,1) 564#endif 565 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++) 566 { 567 const int 568 id = GetOpenMPThreadId(); 569 570 register const Quantum 571 *pixels; 572 573 if (status == MagickFalse) 574 continue; 575 pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y, 576 source->extent.width,1,source->exception); 577 if (pixels == (const Quantum *) NULL) 578 { 579 status=MagickFalse; 580 continue; 581 } 582 if (get(source,y,id,context) == MagickFalse) 583 status=MagickFalse; 584 if (source_image->progress_monitor != (MagickProgressMonitor) NULL) 585 { 586 MagickBooleanType 587 proceed; 588 589#if defined(MAGICKCORE_OPENMP_SUPPORT) 590 #pragma omp critical (MagickCore_GetImageViewIterator) 591#endif 592 proceed=SetImageProgress(source_image,source->description,progress++, 593 source->extent.height); 594 if (proceed == MagickFalse) 595 status=MagickFalse; 596 } 597 } 598 return(status); 599} 600 601/* 602%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 603% % 604% % 605% % 606% G e t I m a g e V i e w V i r t u a l M e t a c o n t e n t % 607% % 608% % 609% % 610%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 611% 612% GetImageViewVirtualMetacontent() returns the image view virtual 613% meta-content. 614% 615% The format of the GetImageViewVirtualMetacontent method is: 616% 617% const void *GetImageViewVirtualMetacontent( 618% const ImageView *image_view) 619% 620% A description of each parameter follows: 621% 622% o image_view: the image view. 623% 624*/ 625MagickExport const void *GetImageViewVirtualMetacontent( 626 const ImageView *image_view) 627{ 628 assert(image_view != (ImageView *) NULL); 629 assert(image_view->signature == MagickSignature); 630 return(GetCacheViewVirtualMetacontent(image_view->view)); 631} 632 633/* 634%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 635% % 636% % 637% % 638% G e t I m a g e V i e w V i r t u a l P i x e l s % 639% % 640% % 641% % 642%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 643% 644% GetImageViewVirtualPixels() returns the image view virtual pixels. 645% 646% The format of the GetImageViewVirtualPixels method is: 647% 648% const Quantum *GetImageViewVirtualPixels(const ImageView *image_view) 649% 650% A description of each parameter follows: 651% 652% o image_view: the image view. 653% 654*/ 655MagickExport const Quantum *GetImageViewVirtualPixels( 656 const ImageView *image_view) 657{ 658 assert(image_view != (ImageView *) NULL); 659 assert(image_view->signature == MagickSignature); 660 return(GetCacheViewVirtualPixelQueue(image_view->view)); 661} 662 663/* 664%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 665% % 666% % 667% % 668% I s I m a g e V i e w % 669% % 670% % 671% % 672%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 673% 674% IsImageView() returns MagickTrue if the the parameter is verified as a image 675% view object. 676% 677% The format of the IsImageView method is: 678% 679% MagickBooleanType IsImageView(const ImageView *image_view) 680% 681% A description of each parameter follows: 682% 683% o image_view: the image view. 684% 685*/ 686MagickExport MagickBooleanType IsImageView(const ImageView *image_view) 687{ 688 if (image_view == (const ImageView *) NULL) 689 return(MagickFalse); 690 if (image_view->signature != MagickSignature) 691 return(MagickFalse); 692 return(MagickTrue); 693} 694 695/* 696%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 697% % 698% % 699% % 700% N e w I m a g e V i e w % 701% % 702% % 703% % 704%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 705% 706% NewImageView() returns a image view required for all other methods in the 707% Image View API. 708% 709% The format of the NewImageView method is: 710% 711% ImageView *NewImageView(MagickCore *wand,ExceptionInfo *exception) 712% 713% A description of each parameter follows: 714% 715% o image: the image. 716% 717% o exception: return any errors or warnings in this structure. 718% 719*/ 720MagickExport ImageView *NewImageView(Image *image,ExceptionInfo *exception) 721{ 722 ImageView 723 *image_view; 724 725 assert(image != (Image *) NULL); 726 assert(image->signature == MagickSignature); 727 image_view=(ImageView *) AcquireMagickMemory(sizeof(*image_view)); 728 if (image_view == (ImageView *) NULL) 729 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 730 (void) ResetMagickMemory(image_view,0,sizeof(*image_view)); 731 image_view->description=ConstantString("ImageView"); 732 image_view->image=image; 733 image_view->view=AcquireVirtualCacheView(image_view->image,exception); 734 image_view->extent.width=image->columns; 735 image_view->extent.height=image->rows; 736 image_view->extent.x=0; 737 image_view->extent.y=0; 738 image_view->exception=AcquireExceptionInfo(); 739 image_view->debug=IsEventLogging(); 740 image_view->signature=MagickSignature; 741 return(image_view); 742} 743 744/* 745%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 746% % 747% % 748% % 749% N e w I m a g e V i e w R e g i o n % 750% % 751% % 752% % 753%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 754% 755% NewImageViewRegion() returns a image view required for all other methods 756% in the Image View API. 757% 758% The format of the NewImageViewRegion method is: 759% 760% ImageView *NewImageViewRegion(MagickCore *wand,const ssize_t x, 761% const ssize_t y,const size_t width,const size_t height, 762% ExceptionInfo *exception) 763% 764% A description of each parameter follows: 765% 766% o wand: the magick wand. 767% 768% o x,y,columns,rows: These values define the perimeter of a extent of 769% pixel_wands view. 770% 771% o exception: return any errors or warnings in this structure. 772% 773*/ 774MagickExport ImageView *NewImageViewRegion(Image *image,const ssize_t x, 775 const ssize_t y,const size_t width,const size_t height, 776 ExceptionInfo *exception) 777{ 778 ImageView 779 *image_view; 780 781 assert(image != (Image *) NULL); 782 assert(image->signature == MagickSignature); 783 image_view=(ImageView *) AcquireMagickMemory(sizeof(*image_view)); 784 if (image_view == (ImageView *) NULL) 785 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 786 (void) ResetMagickMemory(image_view,0,sizeof(*image_view)); 787 image_view->description=ConstantString("ImageView"); 788 image_view->view=AcquireVirtualCacheView(image_view->image,exception); 789 image_view->image=image; 790 image_view->extent.width=width; 791 image_view->extent.height=height; 792 image_view->extent.x=x; 793 image_view->extent.y=y; 794 image_view->exception=AcquireExceptionInfo(); 795 image_view->debug=IsEventLogging(); 796 image_view->signature=MagickSignature; 797 return(image_view); 798} 799 800/* 801%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 802% % 803% % 804% % 805% S e t I m a g e V i e w D e s c r i p t i o n % 806% % 807% % 808% % 809%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 810% 811% SetImageViewDescription() associates a description with an image view. 812% 813% The format of the SetImageViewDescription method is: 814% 815% void SetImageViewDescription(ImageView *image_view, 816% const char *description) 817% 818% A description of each parameter follows: 819% 820% o image_view: the image view. 821% 822% o description: the image view description. 823% 824*/ 825MagickExport void SetImageViewDescription(ImageView *image_view, 826 const char *description) 827{ 828 assert(image_view != (ImageView *) NULL); 829 assert(image_view->signature == MagickSignature); 830 image_view->description=ConstantString(description); 831} 832 833/* 834%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 835% % 836% % 837% % 838% S e t I m a g e V i e w I t e r a t o r % 839% % 840% % 841% % 842%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 843% 844% SetImageViewIterator() iterates over the image view in parallel and calls 845% your set method for each scanline of the view. The pixel extent is 846% confined to the image canvas-- that is no negative offsets or widths or 847% heights that exceed the image dimension. The pixels are initiallly 848% undefined and any settings you make in the callback method are automagically 849% synced back to your image. 850% 851% The callback signature is: 852% 853% MagickBooleanType SetImageViewMethod(ImageView *destination, 854% const ssize_t y,const int thread_id,void *context) 855% 856% Use this pragma if the view is not single threaded: 857% 858% #pragma omp critical 859% 860% to define a section of code in your callback set method that must be 861% executed by a single thread at a time. 862% 863% The format of the SetImageViewIterator method is: 864% 865% MagickBooleanType SetImageViewIterator(ImageView *destination, 866% SetImageViewMethod set,void *context) 867% 868% A description of each parameter follows: 869% 870% o destination: the image view. 871% 872% o set: the set callback method. 873% 874% o context: the user defined context. 875% 876*/ 877MagickExport MagickBooleanType SetImageViewIterator(ImageView *destination, 878 SetImageViewMethod set,void *context) 879{ 880 Image 881 *destination_image; 882 883 MagickBooleanType 884 status; 885 886 MagickOffsetType 887 progress; 888 889#if defined(MAGICKCORE_OPENMP_SUPPORT) 890 size_t 891 height, 892 width; 893#endif 894 895 ssize_t 896 y; 897 898 assert(destination != (ImageView *) NULL); 899 assert(destination->signature == MagickSignature); 900 if (set == (SetImageViewMethod) NULL) 901 return(MagickFalse); 902 destination_image=destination->image; 903 status=SetImageStorageClass(destination_image,DirectClass, 904 destination->exception); 905 if (status == MagickFalse) 906 return(MagickFalse); 907 status=MagickTrue; 908 progress=0; 909#if defined(MAGICKCORE_OPENMP_SUPPORT) 910 height=destination->extent.height-destination->extent.y; 911 width=destination->extent.width-destination->extent.x; 912 #pragma omp parallel for schedule(static,4) shared(progress,status) \ 913 dynamic_number_threads(destination_image,width,height,1) 914#endif 915 for (y=destination->extent.y; y < (ssize_t) destination->extent.height; y++) 916 { 917 const int 918 id = GetOpenMPThreadId(); 919 920 MagickBooleanType 921 sync; 922 923 register Quantum 924 *restrict pixels; 925 926 if (status == MagickFalse) 927 continue; 928 pixels=GetCacheViewAuthenticPixels(destination->view,destination->extent.x, 929 y,destination->extent.width,1,destination->exception); 930 if (pixels == (Quantum *) NULL) 931 { 932 status=MagickFalse; 933 continue; 934 } 935 if (set(destination,y,id,context) == MagickFalse) 936 status=MagickFalse; 937 sync=SyncCacheViewAuthenticPixels(destination->view,destination->exception); 938 if (sync == MagickFalse) 939 status=MagickFalse; 940 if (destination_image->progress_monitor != (MagickProgressMonitor) NULL) 941 { 942 MagickBooleanType 943 proceed; 944 945#if defined(MAGICKCORE_OPENMP_SUPPORT) 946 #pragma omp critical (MagickCore_SetImageViewIterator) 947#endif 948 proceed=SetImageProgress(destination_image,destination->description, 949 progress++,destination->extent.height); 950 if (proceed == MagickFalse) 951 status=MagickFalse; 952 } 953 } 954 return(status); 955} 956 957/* 958%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 959% % 960% % 961% % 962% T r a n s f e r I m a g e V i e w I t e r a t o r % 963% % 964% % 965% % 966%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 967% 968% TransferImageViewIterator() iterates over two image views in parallel and 969% calls your transfer method for each scanline of the view. The source pixel 970% extent is not confined to the image canvas-- that is you can include 971% negative offsets or widths or heights that exceed the image dimension. 972% However, the destination image view is confined to the image canvas-- that 973% is no negative offsets or widths or heights that exceed the image dimension 974% are permitted. 975% 976% The callback signature is: 977% 978% MagickBooleanType TransferImageViewMethod(const ImageView *source, 979% ImageView *destination,const ssize_t y,const int thread_id, 980% void *context) 981% 982% Use this pragma if the view is not single threaded: 983% 984% #pragma omp critical 985% 986% to define a section of code in your callback transfer method that must be 987% executed by a single thread at a time. 988% 989% The format of the TransferImageViewIterator method is: 990% 991% MagickBooleanType TransferImageViewIterator(ImageView *source, 992% ImageView *destination,TransferImageViewMethod transfer,void *context) 993% 994% A description of each parameter follows: 995% 996% o source: the source image view. 997% 998% o destination: the destination image view. 999% 1000% o transfer: the transfer callback method. 1001% 1002% o context: the user defined context. 1003% 1004*/ 1005MagickExport MagickBooleanType TransferImageViewIterator(ImageView *source, 1006 ImageView *destination,TransferImageViewMethod transfer,void *context) 1007{ 1008 Image 1009 *destination_image, 1010 *source_image; 1011 1012 MagickBooleanType 1013 status; 1014 1015 MagickOffsetType 1016 progress; 1017 1018#if defined(MAGICKCORE_OPENMP_SUPPORT) 1019 size_t 1020 height, 1021 width; 1022#endif 1023 1024 ssize_t 1025 y; 1026 1027 assert(source != (ImageView *) NULL); 1028 assert(source->signature == MagickSignature); 1029 if (transfer == (TransferImageViewMethod) NULL) 1030 return(MagickFalse); 1031 source_image=source->image; 1032 destination_image=destination->image; 1033 status=SetImageStorageClass(destination_image,DirectClass, 1034 destination->exception); 1035 if (status == MagickFalse) 1036 return(MagickFalse); 1037 status=MagickTrue; 1038 progress=0; 1039#if defined(MAGICKCORE_OPENMP_SUPPORT) 1040 height=source->extent.height-source->extent.y; 1041 width=source->extent.width-source->extent.x; 1042 #pragma omp parallel for schedule(static,4) shared(progress,status) \ 1043 dynamic_number_threads(source_image,width,height,1) 1044#endif 1045 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++) 1046 { 1047 const int 1048 id = GetOpenMPThreadId(); 1049 1050 MagickBooleanType 1051 sync; 1052 1053 register const Quantum 1054 *restrict pixels; 1055 1056 register Quantum 1057 *restrict destination_pixels; 1058 1059 if (status == MagickFalse) 1060 continue; 1061 pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y, 1062 source->extent.width,1,source->exception); 1063 if (pixels == (const Quantum *) NULL) 1064 { 1065 status=MagickFalse; 1066 continue; 1067 } 1068 destination_pixels=GetCacheViewAuthenticPixels(destination->view, 1069 destination->extent.x,y,destination->extent.width,1, 1070 destination->exception); 1071 if (destination_pixels == (Quantum *) NULL) 1072 { 1073 status=MagickFalse; 1074 continue; 1075 } 1076 if (transfer(source,destination,y,id,context) == MagickFalse) 1077 status=MagickFalse; 1078 sync=SyncCacheViewAuthenticPixels(destination->view,destination->exception); 1079 if (sync == MagickFalse) 1080 status=MagickFalse; 1081 if (source_image->progress_monitor != (MagickProgressMonitor) NULL) 1082 { 1083 MagickBooleanType 1084 proceed; 1085 1086#if defined(MAGICKCORE_OPENMP_SUPPORT) 1087 #pragma omp critical (MagickCore_TransferImageViewIterator) 1088#endif 1089 proceed=SetImageProgress(source_image,source->description,progress++, 1090 source->extent.height); 1091 if (proceed == MagickFalse) 1092 status=MagickFalse; 1093 } 1094 } 1095 return(status); 1096} 1097 1098/* 1099%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1100% % 1101% % 1102% % 1103% U p d a t e I m a g e V i e w I t e r a t o r % 1104% % 1105% % 1106% % 1107%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1108% 1109% UpdateImageViewIterator() iterates over the image view in parallel and calls 1110% your update method for each scanline of the view. The pixel extent is 1111% confined to the image canvas-- that is no negative offsets or widths or 1112% heights that exceed the image dimension are permitted. Updates to pixels 1113% in your callback are automagically synced back to the image. 1114% 1115% The callback signature is: 1116% 1117% MagickBooleanType UpdateImageViewMethod(ImageView *source, 1118% const ssize_t y,const int thread_id,void *context) 1119% 1120% Use this pragma if the view is not single threaded: 1121% 1122% #pragma omp critical 1123% 1124% to define a section of code in your callback update method that must be 1125% executed by a single thread at a time. 1126% 1127% The format of the UpdateImageViewIterator method is: 1128% 1129% MagickBooleanType UpdateImageViewIterator(ImageView *source, 1130% UpdateImageViewMethod update,void *context) 1131% 1132% A description of each parameter follows: 1133% 1134% o source: the source image view. 1135% 1136% o update: the update callback method. 1137% 1138% o context: the user defined context. 1139% 1140*/ 1141MagickExport MagickBooleanType UpdateImageViewIterator(ImageView *source, 1142 UpdateImageViewMethod update,void *context) 1143{ 1144 Image 1145 *source_image; 1146 1147 MagickBooleanType 1148 status; 1149 1150 MagickOffsetType 1151 progress; 1152 1153#if defined(MAGICKCORE_OPENMP_SUPPORT) 1154 size_t 1155 height, 1156 width; 1157#endif 1158 1159 ssize_t 1160 y; 1161 1162 assert(source != (ImageView *) NULL); 1163 assert(source->signature == MagickSignature); 1164 if (update == (UpdateImageViewMethod) NULL) 1165 return(MagickFalse); 1166 source_image=source->image; 1167 status=SetImageStorageClass(source_image,DirectClass,source->exception); 1168 if (status == MagickFalse) 1169 return(MagickFalse); 1170 status=MagickTrue; 1171 progress=0; 1172#if defined(MAGICKCORE_OPENMP_SUPPORT) 1173 height=source->extent.height-source->extent.y; 1174 width=source->extent.width-source->extent.x; 1175 #pragma omp parallel for schedule(static,4) shared(progress,status) \ 1176 dynamic_number_threads(source_image,width,height,1) 1177#endif 1178 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++) 1179 { 1180 const int 1181 id = GetOpenMPThreadId(); 1182 1183 register Quantum 1184 *restrict pixels; 1185 1186 if (status == MagickFalse) 1187 continue; 1188 pixels=GetCacheViewAuthenticPixels(source->view,source->extent.x,y, 1189 source->extent.width,1,source->exception); 1190 if (pixels == (Quantum *) NULL) 1191 { 1192 status=MagickFalse; 1193 continue; 1194 } 1195 if (update(source,y,id,context) == MagickFalse) 1196 status=MagickFalse; 1197 status=SyncCacheViewAuthenticPixels(source->view,source->exception); 1198 if (status == MagickFalse) 1199 status=MagickFalse; 1200 if (source_image->progress_monitor != (MagickProgressMonitor) NULL) 1201 { 1202 MagickBooleanType 1203 proceed; 1204 1205#if defined(MAGICKCORE_OPENMP_SUPPORT) 1206 #pragma omp critical (MagickCore_UpdateImageViewIterator) 1207#endif 1208 proceed=SetImageProgress(source_image,source->description,progress++, 1209 source->extent.height); 1210 if (proceed == MagickFalse) 1211 status=MagickFalse; 1212 } 1213 } 1214 return(status); 1215} 1216