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 /* 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) ResetMagickMemory(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,4) shared(progress,status) \ 300 magick_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 critical (MagickWand_DuplexTransferWandViewIterator) 382 #endif 383 proceed=SetImageProgress(source_image,source->description,progress++, 384 source->extent.height); 385 if (proceed == MagickFalse) 386 status=MagickFalse; 387 } 388 } 389 return(status); 390 } 391 392 /* 394 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 395 % % 396 % % 397 % % 398 % G e t W a n d V i e w E x c e p t i o n % 399 % % 400 % % 401 % % 402 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 403 % 404 % GetWandViewException() returns the severity, reason, and description of any 405 % error that occurs when utilizing a wand view. 406 % 407 % The format of the GetWandViewException method is: 408 % 409 % char *GetWandViewException(const WandView *wand_view, 410 % ExceptionType *severity) 411 % 412 % A description of each parameter follows: 413 % 414 % o wand_view: the pixel wand_view. 415 % 416 % o severity: the severity of the error is returned here. 417 % 418 */ 419 WandExport char *GetWandViewException(const WandView *wand_view, 420 ExceptionType *severity) 421 { 422 char 423 *description; 424 425 assert(wand_view != (const WandView *) NULL); 426 assert(wand_view->signature == MagickWandSignature); 427 if (wand_view->debug != MagickFalse) 428 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",wand_view->name); 429 assert(severity != (ExceptionType *) NULL); 430 *severity=wand_view->exception->severity; 431 description=(char *) AcquireQuantumMemory(2UL*MagickPathExtent, 432 sizeof(*description)); 433 if (description == (char *) NULL) 434 ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed", 435 wand_view->name); 436 *description='\0'; 437 if (wand_view->exception->reason != (char *) NULL) 438 (void) CopyMagickString(description,GetLocaleExceptionMessage( 439 wand_view->exception->severity,wand_view->exception->reason), 440 MagickPathExtent); 441 if (wand_view->exception->description != (char *) NULL) 442 { 443 (void) ConcatenateMagickString(description," (",MagickPathExtent); 444 (void) ConcatenateMagickString(description,GetLocaleExceptionMessage( 445 wand_view->exception->severity,wand_view->exception->description), 446 MagickPathExtent); 447 (void) ConcatenateMagickString(description,")",MagickPathExtent); 448 } 449 return(description); 450 } 451 452 /* 454 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 455 % % 456 % % 457 % % 458 % G e t W a n d V i e w E x t e n t % 459 % % 460 % % 461 % % 462 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 463 % 464 % GetWandViewExtent() returns the wand view extent. 465 % 466 % The format of the GetWandViewExtent method is: 467 % 468 % RectangleInfo GetWandViewExtent(const WandView *wand_view) 469 % 470 % A description of each parameter follows: 471 % 472 % o wand_view: the wand view. 473 % 474 */ 475 WandExport RectangleInfo GetWandViewExtent(const WandView *wand_view) 476 { 477 assert(wand_view != (WandView *) NULL); 478 assert(wand_view->signature == MagickWandSignature); 479 return(wand_view->extent); 480 } 481 482 /* 484 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 485 % % 486 % % 487 % % 488 % G e t W a n d V i e w I t e r a t o r % 489 % % 490 % % 491 % % 492 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 493 % 494 % GetWandViewIterator() iterates over the wand view in parallel and calls 495 % your get method for each scanline of the view. The pixel extent is 496 % not confined to the image canvas-- that is you can include negative offsets 497 % or widths or heights that exceed the image dimension. Any updates to 498 % the pixels in your callback are ignored. 499 % 500 % The callback signature is: 501 % 502 % MagickBooleanType GetImageViewMethod(const WandView *source, 503 % const ssize_t y,const int thread_id,void *context) 504 % 505 % Use this pragma if the view is not single threaded: 506 % 507 % #pragma omp critical 508 % 509 % to define a section of code in your callback get method that must be 510 % executed by a single thread at a time. 511 % 512 % The format of the GetWandViewIterator method is: 513 % 514 % MagickBooleanType GetWandViewIterator(WandView *source, 515 % GetWandViewMethod get,void *context) 516 % 517 % A description of each parameter follows: 518 % 519 % o source: the source wand view. 520 % 521 % o get: the get callback method. 522 % 523 % o context: the user defined context. 524 % 525 */ 526 WandExport MagickBooleanType GetWandViewIterator(WandView *source, 527 GetWandViewMethod get,void *context) 528 { 529 Image 530 *source_image; 531 532 MagickBooleanType 533 status; 534 535 MagickOffsetType 536 progress; 537 538 #if defined(MAGICKCORE_OPENMP_SUPPORT) 539 size_t 540 height; 541 #endif 542 543 ssize_t 544 y; 545 546 assert(source != (WandView *) NULL); 547 assert(source->signature == MagickWandSignature); 548 if (get == (GetWandViewMethod) NULL) 549 return(MagickFalse); 550 source_image=source->wand->images; 551 status=MagickTrue; 552 progress=0; 553 #if defined(MAGICKCORE_OPENMP_SUPPORT) 554 height=source->extent.height-source->extent.y; 555 #pragma omp parallel for schedule(static,4) shared(progress,status) \ 556 magick_threads(source_image,source_image,height,1) 557 #endif 558 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++) 559 { 560 const int 561 id = GetOpenMPThreadId(); 562 563 register const Quantum 564 *pixels; 565 566 register ssize_t 567 x; 568 569 if (status == MagickFalse) 570 continue; 571 pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y, 572 source->extent.width,1,source->exception); 573 if (pixels == (const Quantum *) NULL) 574 { 575 status=MagickFalse; 576 continue; 577 } 578 for (x=0; x < (ssize_t) source->extent.width; x++) 579 { 580 PixelSetQuantumPixel(source->image,pixels,source->pixel_wands[id][x]); 581 pixels+=GetPixelChannels(source->image); 582 } 583 if (get(source,y,id,context) == MagickFalse) 584 status=MagickFalse; 585 if (source_image->progress_monitor != (MagickProgressMonitor) NULL) 586 { 587 MagickBooleanType 588 proceed; 589 590 #if defined(MAGICKCORE_OPENMP_SUPPORT) 591 #pragma omp critical (MagickWand_GetWandViewIterator) 592 #endif 593 proceed=SetImageProgress(source_image,source->description,progress++, 594 source->extent.height); 595 if (proceed == MagickFalse) 596 status=MagickFalse; 597 } 598 } 599 return(status); 600 } 601 602 /* 604 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 605 % % 606 % % 607 % % 608 % G e t W a n d V i e w P i x e l s % 609 % % 610 % % 611 % % 612 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 613 % 614 % GetWandViewPixels() returns the wand view pixel_wands. 615 % 616 % The format of the GetWandViewPixels method is: 617 % 618 % PixelWand *GetWandViewPixels(const WandView *wand_view) 619 % 620 % A description of each parameter follows: 621 % 622 % o wand_view: the wand view. 623 % 624 */ 625 WandExport PixelWand **GetWandViewPixels(const WandView *wand_view) 626 { 627 const int 628 id = GetOpenMPThreadId(); 629 630 assert(wand_view != (WandView *) NULL); 631 assert(wand_view->signature == MagickWandSignature); 632 return(wand_view->pixel_wands[id]); 633 } 634 635 /* 637 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 638 % % 639 % % 640 % % 641 % G e t W a n d V i e w W a n d % 642 % % 643 % % 644 % % 645 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 646 % 647 % GetWandViewWand() returns the magick wand associated with the wand view. 648 % 649 % The format of the GetWandViewWand method is: 650 % 651 % MagickWand *GetWandViewWand(const WandView *wand_view) 652 % 653 % A description of each parameter follows: 654 % 655 % o wand_view: the wand view. 656 % 657 */ 658 WandExport MagickWand *GetWandViewWand(const WandView *wand_view) 659 { 660 assert(wand_view != (WandView *) NULL); 661 assert(wand_view->signature == MagickWandSignature); 662 return(wand_view->wand); 663 } 664 665 /* 667 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 668 % % 669 % % 670 % % 671 % I s W a n d V i e w % 672 % % 673 % % 674 % % 675 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 676 % 677 % IsWandView() returns MagickTrue if the the parameter is verified as a wand 678 % view object. 679 % 680 % The format of the IsWandView method is: 681 % 682 % MagickBooleanType IsWandView(const WandView *wand_view) 683 % 684 % A description of each parameter follows: 685 % 686 % o wand_view: the wand view. 687 % 688 */ 689 WandExport MagickBooleanType IsWandView(const WandView *wand_view) 690 { 691 size_t 692 length; 693 694 if (wand_view == (const WandView *) NULL) 695 return(MagickFalse); 696 if (wand_view->signature != MagickWandSignature) 697 return(MagickFalse); 698 length=strlen(WandViewId); 699 if (LocaleNCompare(wand_view->name,WandViewId,length) != 0) 700 return(MagickFalse); 701 return(MagickTrue); 702 } 703 704 /* 706 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 707 % % 708 % % 709 % % 710 % N e w W a n d V i e w % 711 % % 712 % % 713 % % 714 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 715 % 716 % NewWandView() returns a wand view required for all other methods in the 717 % Wand View API. 718 % 719 % The format of the NewWandView method is: 720 % 721 % WandView *NewWandView(MagickWand *wand) 722 % 723 % A description of each parameter follows: 724 % 725 % o wand: the wand. 726 % 727 */ 728 729 static PixelWand ***AcquirePixelsThreadSet(const size_t number_wands) 730 { 731 PixelWand 732 ***pixel_wands; 733 734 register ssize_t 735 i; 736 737 size_t 738 number_threads; 739 740 number_threads=GetOpenMPMaximumThreads(); 741 pixel_wands=(PixelWand ***) AcquireQuantumMemory(number_threads, 742 sizeof(*pixel_wands)); 743 if (pixel_wands == (PixelWand ***) NULL) 744 return((PixelWand ***) NULL); 745 (void) ResetMagickMemory(pixel_wands,0,number_threads*sizeof(*pixel_wands)); 746 for (i=0; i < (ssize_t) number_threads; i++) 747 { 748 pixel_wands[i]=NewPixelWands(number_wands); 749 if (pixel_wands[i] == (PixelWand **) NULL) 750 return(DestroyPixelsThreadSet(pixel_wands,number_wands)); 751 } 752 return(pixel_wands); 753 } 754 755 WandExport WandView *NewWandView(MagickWand *wand) 756 { 757 ExceptionInfo 758 *exception; 759 760 WandView 761 *wand_view; 762 763 assert(wand != (MagickWand *) NULL); 764 assert(wand->signature == MagickWandSignature); 765 wand_view=(WandView *) AcquireMagickMemory(sizeof(*wand_view)); 766 if (wand_view == (WandView *) NULL) 767 ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed", 768 GetExceptionMessage(errno)); 769 (void) ResetMagickMemory(wand_view,0,sizeof(*wand_view)); 770 wand_view->id=AcquireWandId(); 771 (void) FormatLocaleString(wand_view->name,MagickPathExtent,"%s-%.20g", 772 WandViewId,(double) wand_view->id); 773 wand_view->description=ConstantString("WandView"); 774 wand_view->wand=wand; 775 exception=AcquireExceptionInfo(); 776 wand_view->view=AcquireVirtualCacheView(wand_view->wand->images,exception); 777 wand_view->extent.width=wand->images->columns; 778 wand_view->extent.height=wand->images->rows; 779 wand_view->pixel_wands=AcquirePixelsThreadSet(wand_view->extent.width); 780 wand_view->exception=exception; 781 if (wand_view->pixel_wands == (PixelWand ***) NULL) 782 ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed", 783 GetExceptionMessage(errno)); 784 wand_view->debug=IsEventLogging(); 785 wand_view->signature=MagickWandSignature; 786 return(wand_view); 787 } 788 789 /* 791 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 792 % % 793 % % 794 % % 795 % N e w W a n d V i e w E x t e n t % 796 % % 797 % % 798 % % 799 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 800 % 801 % NewWandViewExtent() returns a wand view required for all other methods 802 % in the Wand View API. 803 % 804 % The format of the NewWandViewExtent method is: 805 % 806 % WandView *NewWandViewExtent(MagickWand *wand,const ssize_t x, 807 % const ssize_t y,const size_t width,const size_t height) 808 % 809 % A description of each parameter follows: 810 % 811 % o wand: the magick wand. 812 % 813 % o x,y,columns,rows: These values define the perimeter of a extent of 814 % pixel_wands view. 815 % 816 */ 817 WandExport WandView *NewWandViewExtent(MagickWand *wand,const ssize_t x, 818 const ssize_t y,const size_t width,const size_t height) 819 { 820 ExceptionInfo 821 *exception; 822 823 WandView 824 *wand_view; 825 826 assert(wand != (MagickWand *) NULL); 827 assert(wand->signature == MagickWandSignature); 828 wand_view=(WandView *) AcquireMagickMemory(sizeof(*wand_view)); 829 if (wand_view == (WandView *) NULL) 830 ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed", 831 GetExceptionMessage(errno)); 832 (void) ResetMagickMemory(wand_view,0,sizeof(*wand_view)); 833 wand_view->id=AcquireWandId(); 834 (void) FormatLocaleString(wand_view->name,MagickPathExtent,"%s-%.20g", 835 WandViewId,(double) wand_view->id); 836 wand_view->description=ConstantString("WandView"); 837 exception=AcquireExceptionInfo(); 838 wand_view->view=AcquireVirtualCacheView(wand_view->wand->images,exception); 839 wand_view->wand=wand; 840 wand_view->extent.width=width; 841 wand_view->extent.height=height; 842 wand_view->extent.x=x; 843 wand_view->extent.y=y; 844 wand_view->exception=exception; 845 wand_view->pixel_wands=AcquirePixelsThreadSet(wand_view->extent.width); 846 if (wand_view->pixel_wands == (PixelWand ***) NULL) 847 ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed", 848 GetExceptionMessage(errno)); 849 wand_view->debug=IsEventLogging(); 850 wand_view->signature=MagickWandSignature; 851 return(wand_view); 852 } 853 854 /* 856 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 857 % % 858 % % 859 % % 860 % S e t W a n d V i e w D e s c r i p t i o n % 861 % % 862 % % 863 % % 864 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 865 % 866 % SetWandViewDescription() associates a description with an image view. 867 % 868 % The format of the SetWandViewDescription method is: 869 % 870 % void SetWandViewDescription(WandView *image_view,const char *description) 871 % 872 % A description of each parameter follows: 873 % 874 % o wand_view: the wand view. 875 % 876 % o description: the wand view description. 877 % 878 */ 879 MagickExport void SetWandViewDescription(WandView *wand_view, 880 const char *description) 881 { 882 assert(wand_view != (WandView *) NULL); 883 assert(wand_view->signature == MagickWandSignature); 884 wand_view->description=ConstantString(description); 885 } 886 887 /* 889 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 890 % % 891 % % 892 % % 893 % S e t W a n d V i e w I t e r a t o r % 894 % % 895 % % 896 % % 897 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 898 % 899 % SetWandViewIterator() iterates over the wand view in parallel and calls 900 % your set method for each scanline of the view. The pixel extent is 901 % confined to the image canvas-- that is no negative offsets or widths or 902 % heights that exceed the image dimension. The pixels are initiallly 903 % undefined and any settings you make in the callback method are automagically 904 % synced back to your image. 905 % 906 % The callback signature is: 907 % 908 % MagickBooleanType SetImageViewMethod(ImageView *destination, 909 % const ssize_t y,const int thread_id,void *context) 910 % 911 % Use this pragma if the view is not single threaded: 912 % 913 % #pragma omp critical 914 % 915 % to define a section of code in your callback set method that must be 916 % executed by a single thread at a time. 917 % 918 % The format of the SetWandViewIterator method is: 919 % 920 % MagickBooleanType SetWandViewIterator(WandView *destination, 921 % SetWandViewMethod set,void *context) 922 % 923 % A description of each parameter follows: 924 % 925 % o destination: the wand view. 926 % 927 % o set: the set callback method. 928 % 929 % o context: the user defined context. 930 % 931 */ 932 WandExport MagickBooleanType SetWandViewIterator(WandView *destination, 933 SetWandViewMethod set,void *context) 934 { 935 Image 936 *destination_image; 937 938 MagickBooleanType 939 status; 940 941 MagickOffsetType 942 progress; 943 944 #if defined(MAGICKCORE_OPENMP_SUPPORT) 945 size_t 946 height; 947 #endif 948 949 ssize_t 950 y; 951 952 assert(destination != (WandView *) NULL); 953 assert(destination->signature == MagickWandSignature); 954 if (set == (SetWandViewMethod) NULL) 955 return(MagickFalse); 956 destination_image=destination->wand->images; 957 status=SetImageStorageClass(destination_image,DirectClass, 958 destination->exception); 959 if (status == MagickFalse) 960 return(MagickFalse); 961 status=MagickTrue; 962 progress=0; 963 #if defined(MAGICKCORE_OPENMP_SUPPORT) 964 height=destination->extent.height-destination->extent.y; 965 #pragma omp parallel for schedule(static,4) shared(progress,status) \ 966 magick_threads(destination_image,destination_image,height,1) 967 #endif 968 for (y=destination->extent.y; y < (ssize_t) destination->extent.height; y++) 969 { 970 const int 971 id = GetOpenMPThreadId(); 972 973 MagickBooleanType 974 sync; 975 976 register ssize_t 977 x; 978 979 register Quantum 980 *magick_restrict pixels; 981 982 if (status == MagickFalse) 983 continue; 984 pixels=GetCacheViewAuthenticPixels(destination->view,destination->extent.x, 985 y,destination->extent.width,1,destination->exception); 986 if (pixels == (Quantum *) NULL) 987 { 988 status=MagickFalse; 989 continue; 990 } 991 if (set(destination,y,id,context) == MagickFalse) 992 status=MagickFalse; 993 for (x=0; x < (ssize_t) destination->extent.width; x++) 994 { 995 PixelGetQuantumPixel(destination->image,destination->pixel_wands[id][x], 996 pixels); 997 pixels+=GetPixelChannels(destination->image); 998 } 999 sync=SyncCacheViewAuthenticPixels(destination->view,destination->exception); 1000 if (sync == MagickFalse) 1001 status=MagickFalse; 1002 if (destination_image->progress_monitor != (MagickProgressMonitor) NULL) 1003 { 1004 MagickBooleanType 1005 proceed; 1006 1007 #if defined(MAGICKCORE_OPENMP_SUPPORT) 1008 #pragma omp critical (MagickWand_SetWandViewIterator) 1009 #endif 1010 proceed=SetImageProgress(destination_image,destination->description, 1011 progress++,destination->extent.height); 1012 if (proceed == MagickFalse) 1013 status=MagickFalse; 1014 } 1015 } 1016 return(status); 1017 } 1018 1019 /* 1021 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1022 % % 1023 % % 1024 % % 1025 % T r a n s f e r W a n d V i e w I t e r a t o r % 1026 % % 1027 % % 1028 % % 1029 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1030 % 1031 % TransferWandViewIterator() iterates over two wand views in parallel and 1032 % calls your transfer method for each scanline of the view. The source pixel 1033 % extent is not confined to the image canvas-- that is you can include 1034 % negative offsets or widths or heights that exceed the image dimension. 1035 % However, the destination wand view is confined to the image canvas-- that 1036 % is no negative offsets or widths or heights that exceed the image dimension 1037 % are permitted. 1038 % 1039 % The callback signature is: 1040 % 1041 % MagickBooleanType TransferImageViewMethod(const WandView *source, 1042 % WandView *destination,const ssize_t y,const int thread_id, 1043 % void *context) 1044 % 1045 % Use this pragma if the view is not single threaded: 1046 % 1047 % #pragma omp critical 1048 % 1049 % to define a section of code in your callback transfer method that must be 1050 % executed by a single thread at a time. 1051 % 1052 % The format of the TransferWandViewIterator method is: 1053 % 1054 % MagickBooleanType TransferWandViewIterator(WandView *source, 1055 % WandView *destination,TransferWandViewMethod transfer,void *context) 1056 % 1057 % A description of each parameter follows: 1058 % 1059 % o source: the source wand view. 1060 % 1061 % o destination: the destination wand view. 1062 % 1063 % o transfer: the transfer callback method. 1064 % 1065 % o context: the user defined context. 1066 % 1067 */ 1068 WandExport MagickBooleanType TransferWandViewIterator(WandView *source, 1069 WandView *destination,TransferWandViewMethod transfer,void *context) 1070 { 1071 Image 1072 *destination_image, 1073 *source_image; 1074 1075 MagickBooleanType 1076 status; 1077 1078 MagickOffsetType 1079 progress; 1080 1081 #if defined(MAGICKCORE_OPENMP_SUPPORT) 1082 size_t 1083 height; 1084 #endif 1085 1086 ssize_t 1087 y; 1088 1089 assert(source != (WandView *) NULL); 1090 assert(source->signature == MagickWandSignature); 1091 if (transfer == (TransferWandViewMethod) NULL) 1092 return(MagickFalse); 1093 source_image=source->wand->images; 1094 destination_image=destination->wand->images; 1095 status=SetImageStorageClass(destination_image,DirectClass, 1096 destination->exception); 1097 if (status == MagickFalse) 1098 return(MagickFalse); 1099 status=MagickTrue; 1100 progress=0; 1101 #if defined(MAGICKCORE_OPENMP_SUPPORT) 1102 height=source->extent.height-source->extent.y; 1103 #pragma omp parallel for schedule(static,4) shared(progress,status) \ 1104 magick_threads(source_image,destination_image,height,1) 1105 #endif 1106 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++) 1107 { 1108 const int 1109 id = GetOpenMPThreadId(); 1110 1111 MagickBooleanType 1112 sync; 1113 1114 register const Quantum 1115 *magick_restrict pixels; 1116 1117 register ssize_t 1118 x; 1119 1120 register Quantum 1121 *magick_restrict destination_pixels; 1122 1123 if (status == MagickFalse) 1124 continue; 1125 pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y, 1126 source->extent.width,1,source->exception); 1127 if (pixels == (const Quantum *) NULL) 1128 { 1129 status=MagickFalse; 1130 continue; 1131 } 1132 for (x=0; x < (ssize_t) source->extent.width; x++) 1133 { 1134 PixelSetQuantumPixel(source->image,pixels,source->pixel_wands[id][x]); 1135 pixels+=GetPixelChannels(source->image); 1136 } 1137 destination_pixels=GetCacheViewAuthenticPixels(destination->view, 1138 destination->extent.x,y,destination->extent.width,1, 1139 destination->exception); 1140 if (destination_pixels == (Quantum *) NULL) 1141 { 1142 status=MagickFalse; 1143 continue; 1144 } 1145 for (x=0; x < (ssize_t) destination->extent.width; x++) 1146 { 1147 PixelSetQuantumPixel(destination->image,destination_pixels, 1148 destination->pixel_wands[id][x]); 1149 destination_pixels+=GetPixelChannels(destination->image); 1150 } 1151 if (transfer(source,destination,y,id,context) == MagickFalse) 1152 status=MagickFalse; 1153 destination_pixels=GetCacheViewAuthenticPixels(destination->view, 1154 destination->extent.x,y,destination->extent.width,1, 1155 destination->exception); 1156 for (x=0; x < (ssize_t) destination->extent.width; x++) 1157 { 1158 PixelGetQuantumPixel(destination->image,destination->pixel_wands[id][x], 1159 destination_pixels); 1160 destination_pixels+=GetPixelChannels(destination->image); 1161 } 1162 sync=SyncCacheViewAuthenticPixels(destination->view,destination->exception); 1163 if (sync == MagickFalse) 1164 status=MagickFalse; 1165 if (source_image->progress_monitor != (MagickProgressMonitor) NULL) 1166 { 1167 MagickBooleanType 1168 proceed; 1169 1170 #if defined(MAGICKCORE_OPENMP_SUPPORT) 1171 #pragma omp critical (MagickWand_TransferWandViewIterator) 1172 #endif 1173 proceed=SetImageProgress(source_image,source->description,progress++, 1174 source->extent.height); 1175 if (proceed == MagickFalse) 1176 status=MagickFalse; 1177 } 1178 } 1179 return(status); 1180 } 1181 1182 /* 1184 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1185 % % 1186 % % 1187 % % 1188 % U p d a t e W a n d V i e w I t e r a t o r % 1189 % % 1190 % % 1191 % % 1192 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1193 % 1194 % UpdateWandViewIterator() iterates over the wand view in parallel and calls 1195 % your update method for each scanline of the view. The pixel extent is 1196 % confined to the image canvas-- that is no negative offsets or widths or 1197 % heights that exceed the image dimension are permitted. Updates to pixels 1198 % in your callback are automagically synced back to the image. 1199 % 1200 % The callback signature is: 1201 % 1202 % MagickBooleanType UpdateImageViewMethod(WandView *source,const ssize_t y, 1203 % const int thread_id,void *context) 1204 % 1205 % Use this pragma if the view is not single threaded: 1206 % 1207 % #pragma omp critical 1208 % 1209 % to define a section of code in your callback update method that must be 1210 % executed by a single thread at a time. 1211 % 1212 % The format of the UpdateWandViewIterator method is: 1213 % 1214 % MagickBooleanType UpdateWandViewIterator(WandView *source, 1215 % UpdateWandViewMethod update,void *context) 1216 % 1217 % A description of each parameter follows: 1218 % 1219 % o source: the source wand view. 1220 % 1221 % o update: the update callback method. 1222 % 1223 % o context: the user defined context. 1224 % 1225 */ 1226 WandExport MagickBooleanType UpdateWandViewIterator(WandView *source, 1227 UpdateWandViewMethod update,void *context) 1228 { 1229 Image 1230 *source_image; 1231 1232 MagickBooleanType 1233 status; 1234 1235 MagickOffsetType 1236 progress; 1237 1238 #if defined(MAGICKCORE_OPENMP_SUPPORT) 1239 size_t 1240 height; 1241 #endif 1242 1243 ssize_t 1244 y; 1245 1246 assert(source != (WandView *) NULL); 1247 assert(source->signature == MagickWandSignature); 1248 if (update == (UpdateWandViewMethod) NULL) 1249 return(MagickFalse); 1250 source_image=source->wand->images; 1251 status=SetImageStorageClass(source_image,DirectClass,source->exception); 1252 if (status == MagickFalse) 1253 return(MagickFalse); 1254 status=MagickTrue; 1255 progress=0; 1256 #if defined(MAGICKCORE_OPENMP_SUPPORT) 1257 height=source->extent.height-source->extent.y; 1258 #pragma omp parallel for schedule(static,4) shared(progress,status) \ 1259 magick_threads(source_image,source_image,height,1) 1260 #endif 1261 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++) 1262 { 1263 const int 1264 id = GetOpenMPThreadId(); 1265 1266 MagickBooleanType 1267 sync; 1268 1269 register ssize_t 1270 x; 1271 1272 register Quantum 1273 *magick_restrict pixels; 1274 1275 if (status == MagickFalse) 1276 continue; 1277 pixels=GetCacheViewAuthenticPixels(source->view,source->extent.x,y, 1278 source->extent.width,1,source->exception); 1279 if (pixels == (Quantum *) NULL) 1280 { 1281 status=MagickFalse; 1282 continue; 1283 } 1284 for (x=0; x < (ssize_t) source->extent.width; x++) 1285 { 1286 PixelSetQuantumPixel(source->image,pixels,source->pixel_wands[id][x]); 1287 pixels+=GetPixelChannels(source->image); 1288 } 1289 if (update(source,y,id,context) == MagickFalse) 1290 status=MagickFalse; 1291 for (x=0; x < (ssize_t) source->extent.width; x++) 1292 { 1293 PixelGetQuantumPixel(source->image,source->pixel_wands[id][x],pixels); 1294 pixels+=GetPixelChannels(source->image); 1295 } 1296 sync=SyncCacheViewAuthenticPixels(source->view,source->exception); 1297 if (sync == MagickFalse) 1298 status=MagickFalse; 1299 if (source_image->progress_monitor != (MagickProgressMonitor) NULL) 1300 { 1301 MagickBooleanType 1302 proceed; 1303 1304 #if defined(MAGICKCORE_OPENMP_SUPPORT) 1305 #pragma omp critical (MagickWand_UpdateWandViewIterator) 1306 #endif 1307 proceed=SetImageProgress(source_image,source->description,progress++, 1308 source->extent.height); 1309 if (proceed == MagickFalse) 1310 status=MagickFalse; 1311 } 1312 } 1313 return(status); 1314 } 1315