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