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