2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7 % W W W AAAAA N N N D D %
11 % V V IIIII EEEEE W W %
18 % MagickWand Wand View Methods %
25 % Copyright 1999-2018 ImageMagick Studio LLC, a non-profit organization %
26 % dedicated to making software imaging solutions freely available. %
28 % You may not use this file except in compliance with the License. You may %
29 % obtain a copy of the License at %
31 % https://www.imagemagick.org/script/license.php %
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. %
39 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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"
57 #define WandViewId "WandView"
68 name[MagickPathExtent],
97 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
101 % C l o n e W a n d V i e w %
105 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
107 % CloneWandView() makes a copy of the specified wand view.
109 % The format of the CloneWandView method is:
111 % WandView *CloneWandView(const WandView *wand_view)
113 % A description of each parameter follows:
115 % o wand_view: the wand view.
118 WandExport WandView *CloneWandView(const WandView *wand_view)
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",
134 (void) memset(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;
156 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
160 % D e s t r o y W a n d V i e w %
164 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
166 % DestroyWandView() deallocates memory associated with a wand view.
168 % The format of the DestroyWandView method is:
170 % WandView *DestroyWandView(WandView *wand_view)
172 % A description of each parameter follows:
174 % o wand_view: the wand view.
178 static PixelWand ***DestroyPixelsThreadSet(PixelWand ***pixel_wands,
179 const size_t number_wands)
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);
192 WandExport WandView *DestroyWandView(WandView *wand_view)
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);
208 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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 %
216 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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.
226 % The callback signature is:
228 % MagickBooleanType DuplexTransferImageViewMethod(const WandView *source,
229 % const WandView *duplex,WandView *destination,const ssize_t y,
230 % const int thread_id,void *context)
232 % Use this pragma if the view is not single threaded:
234 % #pragma omp critical
236 % to define a section of code in your callback transfer method that must be
237 % executed by a single thread at a time.
239 % The format of the DuplexTransferWandViewIterator method is:
241 % MagickBooleanType DuplexTransferWandViewIterator(WandView *source,
242 % WandView *duplex,WandView *destination,
243 % DuplexTransferWandViewMethod transfer,void *context)
245 % A description of each parameter follows:
247 % o source: the source wand view.
249 % o duplex: the duplex wand view.
251 % o destination: the destination wand view.
253 % o transfer: the transfer callback method.
255 % o context: the user defined context.
258 WandExport MagickBooleanType DuplexTransferWandViewIterator(WandView *source,
259 WandView *duplex,WandView *destination,DuplexTransferWandViewMethod transfer,
272 #if defined(MAGICKCORE_OPENMP_SUPPORT)
280 assert(source != (WandView *) NULL);
281 assert(source->signature == MagickWandSignature);
282 if (transfer == (DuplexTransferWandViewMethod) NULL)
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)
292 #if defined(MAGICKCORE_OPENMP_SUPPORT)
293 height=source->extent.height-source->extent.y;
294 #pragma omp parallel for schedule(static) shared(progress,status) \
295 magick_number_threads(source_image,destination_image,height,1)
297 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
300 id = GetOpenMPThreadId();
305 register const Quantum
306 *magick_restrict duplex_pixels,
307 *magick_restrict pixels;
313 *magick_restrict destination_pixels;
315 if (status == MagickFalse)
317 pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y,
318 source->extent.width,1,source->exception);
319 if (pixels == (const Quantum *) NULL)
324 for (x=0; x < (ssize_t) source->extent.width; x++)
326 PixelSetQuantumPixel(source->image,pixels,source->pixel_wands[id][x]);
327 pixels+=GetPixelChannels(source->image);
329 duplex_pixels=GetCacheViewVirtualPixels(duplex->view,duplex->extent.x,y,
330 duplex->extent.width,1,duplex->exception);
331 if (duplex_pixels == (const Quantum *) NULL)
336 for (x=0; x < (ssize_t) duplex->extent.width; x++)
338 PixelSetQuantumPixel(duplex->image,duplex_pixels,
339 duplex->pixel_wands[id][x]);
340 duplex_pixels+=GetPixelChannels(duplex->image);
342 destination_pixels=GetCacheViewAuthenticPixels(destination->view,
343 destination->extent.x,y,destination->extent.width,1,
344 destination->exception);
345 if (destination_pixels == (Quantum *) NULL)
350 for (x=0; x < (ssize_t) destination->extent.width; x++)
352 PixelSetQuantumPixel(destination->image,destination_pixels,
353 destination->pixel_wands[id][x]);
354 destination_pixels+=GetPixelChannels(destination->image);
356 if (transfer(source,duplex,destination,y,id,context) == 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++)
363 PixelGetQuantumPixel(destination->image,destination->pixel_wands[id][x],
365 destination_pixels+=GetPixelChannels(destination->image);
367 sync=SyncCacheViewAuthenticPixels(destination->view,destination->exception);
368 if (sync == MagickFalse)
370 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
375 #if defined(MAGICKCORE_OPENMP_SUPPORT)
376 #pragma omp critical (MagickWand_DuplexTransferWandViewIterator)
378 proceed=SetImageProgress(source_image,source->description,progress++,
379 source->extent.height);
380 if (proceed == MagickFalse)
388 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
392 % G e t W a n d V i e w E x c e p t i o n %
396 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
398 % GetWandViewException() returns the severity, reason, and description of any
399 % error that occurs when utilizing a wand view.
401 % The format of the GetWandViewException method is:
403 % char *GetWandViewException(const WandView *wand_view,
404 % ExceptionType *severity)
406 % A description of each parameter follows:
408 % o wand_view: the pixel wand_view.
410 % o severity: the severity of the error is returned here.
413 WandExport char *GetWandViewException(const WandView *wand_view,
414 ExceptionType *severity)
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",
431 if (wand_view->exception->reason != (char *) NULL)
432 (void) CopyMagickString(description,GetLocaleExceptionMessage(
433 wand_view->exception->severity,wand_view->exception->reason),
435 if (wand_view->exception->description != (char *) NULL)
437 (void) ConcatenateMagickString(description," (",MagickPathExtent);
438 (void) ConcatenateMagickString(description,GetLocaleExceptionMessage(
439 wand_view->exception->severity,wand_view->exception->description),
441 (void) ConcatenateMagickString(description,")",MagickPathExtent);
447 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
451 % G e t W a n d V i e w E x t e n t %
455 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
457 % GetWandViewExtent() returns the wand view extent.
459 % The format of the GetWandViewExtent method is:
461 % RectangleInfo GetWandViewExtent(const WandView *wand_view)
463 % A description of each parameter follows:
465 % o wand_view: the wand view.
468 WandExport RectangleInfo GetWandViewExtent(const WandView *wand_view)
470 assert(wand_view != (WandView *) NULL);
471 assert(wand_view->signature == MagickWandSignature);
472 return(wand_view->extent);
476 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
480 % G e t W a n d V i e w I t e r a t o r %
484 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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.
492 % The callback signature is:
494 % MagickBooleanType GetImageViewMethod(const WandView *source,
495 % const ssize_t y,const int thread_id,void *context)
497 % Use this pragma if the view is not single threaded:
499 % #pragma omp critical
501 % to define a section of code in your callback get method that must be
502 % executed by a single thread at a time.
504 % The format of the GetWandViewIterator method is:
506 % MagickBooleanType GetWandViewIterator(WandView *source,
507 % GetWandViewMethod get,void *context)
509 % A description of each parameter follows:
511 % o source: the source wand view.
513 % o get: the get callback method.
515 % o context: the user defined context.
518 WandExport MagickBooleanType GetWandViewIterator(WandView *source,
519 GetWandViewMethod get,void *context)
530 #if defined(MAGICKCORE_OPENMP_SUPPORT)
538 assert(source != (WandView *) NULL);
539 assert(source->signature == MagickWandSignature);
540 if (get == (GetWandViewMethod) NULL)
542 source_image=source->wand->images;
545 #if defined(MAGICKCORE_OPENMP_SUPPORT)
546 height=source->extent.height-source->extent.y;
547 #pragma omp parallel for schedule(static) shared(progress,status) \
548 magick_number_threads(source_image,source_image,height,1)
550 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
553 id = GetOpenMPThreadId();
555 register const Quantum
561 if (status == MagickFalse)
563 pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y,
564 source->extent.width,1,source->exception);
565 if (pixels == (const Quantum *) NULL)
570 for (x=0; x < (ssize_t) source->extent.width; x++)
572 PixelSetQuantumPixel(source->image,pixels,source->pixel_wands[id][x]);
573 pixels+=GetPixelChannels(source->image);
575 if (get(source,y,id,context) == MagickFalse)
577 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
582 #if defined(MAGICKCORE_OPENMP_SUPPORT)
583 #pragma omp critical (MagickWand_GetWandViewIterator)
585 proceed=SetImageProgress(source_image,source->description,progress++,
586 source->extent.height);
587 if (proceed == MagickFalse)
595 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
599 % G e t W a n d V i e w P i x e l s %
603 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
605 % GetWandViewPixels() returns the wand view pixel_wands.
607 % The format of the GetWandViewPixels method is:
609 % PixelWand *GetWandViewPixels(const WandView *wand_view)
611 % A description of each parameter follows:
613 % o wand_view: the wand view.
616 WandExport PixelWand **GetWandViewPixels(const WandView *wand_view)
619 id = GetOpenMPThreadId();
621 assert(wand_view != (WandView *) NULL);
622 assert(wand_view->signature == MagickWandSignature);
623 return(wand_view->pixel_wands[id]);
627 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
631 % G e t W a n d V i e w W a n d %
635 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
637 % GetWandViewWand() returns the magick wand associated with the wand view.
639 % The format of the GetWandViewWand method is:
641 % MagickWand *GetWandViewWand(const WandView *wand_view)
643 % A description of each parameter follows:
645 % o wand_view: the wand view.
648 WandExport MagickWand *GetWandViewWand(const WandView *wand_view)
650 assert(wand_view != (WandView *) NULL);
651 assert(wand_view->signature == MagickWandSignature);
652 return(wand_view->wand);
656 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
660 % I s W a n d V i e w %
664 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
666 % IsWandView() returns MagickTrue if the the parameter is verified as a wand
669 % The format of the IsWandView method is:
671 % MagickBooleanType IsWandView(const WandView *wand_view)
673 % A description of each parameter follows:
675 % o wand_view: the wand view.
678 WandExport MagickBooleanType IsWandView(const WandView *wand_view)
683 if (wand_view == (const WandView *) NULL)
685 if (wand_view->signature != MagickWandSignature)
687 length=strlen(WandViewId);
688 if (LocaleNCompare(wand_view->name,WandViewId,length) != 0)
694 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
698 % N e w W a n d V i e w %
702 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
704 % NewWandView() returns a wand view required for all other methods in the
707 % The format of the NewWandView method is:
709 % WandView *NewWandView(MagickWand *wand)
711 % A description of each parameter follows:
717 static PixelWand ***AcquirePixelsThreadSet(const size_t number_wands)
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) memset(pixel_wands,0,number_threads*sizeof(*pixel_wands));
734 for (i=0; i < (ssize_t) number_threads; i++)
736 pixel_wands[i]=NewPixelWands(number_wands);
737 if (pixel_wands[i] == (PixelWand **) NULL)
738 return(DestroyPixelsThreadSet(pixel_wands,number_wands));
743 WandExport WandView *NewWandView(MagickWand *wand)
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) memset(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;
778 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
782 % N e w W a n d V i e w E x t e n t %
786 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
788 % NewWandViewExtent() returns a wand view required for all other methods
789 % in the Wand View API.
791 % The format of the NewWandViewExtent method is:
793 % WandView *NewWandViewExtent(MagickWand *wand,const ssize_t x,
794 % const ssize_t y,const size_t width,const size_t height)
796 % A description of each parameter follows:
798 % o wand: the magick wand.
800 % o x,y,columns,rows: These values define the perimeter of a extent of
804 WandExport WandView *NewWandViewExtent(MagickWand *wand,const ssize_t x,
805 const ssize_t y,const size_t width,const size_t height)
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) memset(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;
842 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
846 % S e t W a n d V i e w D e s c r i p t i o n %
850 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
852 % SetWandViewDescription() associates a description with an image view.
854 % The format of the SetWandViewDescription method is:
856 % void SetWandViewDescription(WandView *image_view,const char *description)
858 % A description of each parameter follows:
860 % o wand_view: the wand view.
862 % o description: the wand view description.
865 MagickExport void SetWandViewDescription(WandView *wand_view,
866 const char *description)
868 assert(wand_view != (WandView *) NULL);
869 assert(wand_view->signature == MagickWandSignature);
870 wand_view->description=ConstantString(description);
874 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
878 % S e t W a n d V i e w I t e r a t o r %
882 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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.
891 % The callback signature is:
893 % MagickBooleanType SetImageViewMethod(ImageView *destination,
894 % const ssize_t y,const int thread_id,void *context)
896 % Use this pragma if the view is not single threaded:
898 % #pragma omp critical
900 % to define a section of code in your callback set method that must be
901 % executed by a single thread at a time.
903 % The format of the SetWandViewIterator method is:
905 % MagickBooleanType SetWandViewIterator(WandView *destination,
906 % SetWandViewMethod set,void *context)
908 % A description of each parameter follows:
910 % o destination: the wand view.
912 % o set: the set callback method.
914 % o context: the user defined context.
917 WandExport MagickBooleanType SetWandViewIterator(WandView *destination,
918 SetWandViewMethod set,void *context)
929 #if defined(MAGICKCORE_OPENMP_SUPPORT)
937 assert(destination != (WandView *) NULL);
938 assert(destination->signature == MagickWandSignature);
939 if (set == (SetWandViewMethod) NULL)
941 destination_image=destination->wand->images;
942 status=SetImageStorageClass(destination_image,DirectClass,
943 destination->exception);
944 if (status == MagickFalse)
948 #if defined(MAGICKCORE_OPENMP_SUPPORT)
949 height=destination->extent.height-destination->extent.y;
950 #pragma omp parallel for schedule(static) shared(progress,status) \
951 magick_number_threads(destination_image,destination_image,height,1)
953 for (y=destination->extent.y; y < (ssize_t) destination->extent.height; y++)
956 id = GetOpenMPThreadId();
965 *magick_restrict pixels;
967 if (status == MagickFalse)
969 pixels=GetCacheViewAuthenticPixels(destination->view,destination->extent.x,
970 y,destination->extent.width,1,destination->exception);
971 if (pixels == (Quantum *) NULL)
976 if (set(destination,y,id,context) == MagickFalse)
978 for (x=0; x < (ssize_t) destination->extent.width; x++)
980 PixelGetQuantumPixel(destination->image,destination->pixel_wands[id][x],
982 pixels+=GetPixelChannels(destination->image);
984 sync=SyncCacheViewAuthenticPixels(destination->view,destination->exception);
985 if (sync == MagickFalse)
987 if (destination_image->progress_monitor != (MagickProgressMonitor) NULL)
992 #if defined(MAGICKCORE_OPENMP_SUPPORT)
993 #pragma omp critical (MagickWand_SetWandViewIterator)
995 proceed=SetImageProgress(destination_image,destination->description,
996 progress++,destination->extent.height);
997 if (proceed == MagickFalse)
1005 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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 %
1013 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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
1023 % The callback signature is:
1025 % MagickBooleanType TransferImageViewMethod(const WandView *source,
1026 % WandView *destination,const ssize_t y,const int thread_id,
1029 % Use this pragma if the view is not single threaded:
1031 % #pragma omp critical
1033 % to define a section of code in your callback transfer method that must be
1034 % executed by a single thread at a time.
1036 % The format of the TransferWandViewIterator method is:
1038 % MagickBooleanType TransferWandViewIterator(WandView *source,
1039 % WandView *destination,TransferWandViewMethod transfer,void *context)
1041 % A description of each parameter follows:
1043 % o source: the source wand view.
1045 % o destination: the destination wand view.
1047 % o transfer: the transfer callback method.
1049 % o context: the user defined context.
1052 WandExport MagickBooleanType TransferWandViewIterator(WandView *source,
1053 WandView *destination,TransferWandViewMethod transfer,void *context)
1065 #if defined(MAGICKCORE_OPENMP_SUPPORT)
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);
1085 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1086 height=source->extent.height-source->extent.y;
1087 #pragma omp parallel for schedule(static) shared(progress,status) \
1088 magick_number_threads(source_image,destination_image,height,1)
1090 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
1093 id = GetOpenMPThreadId();
1098 register const Quantum
1099 *magick_restrict pixels;
1105 *magick_restrict destination_pixels;
1107 if (status == MagickFalse)
1109 pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y,
1110 source->extent.width,1,source->exception);
1111 if (pixels == (const Quantum *) NULL)
1116 for (x=0; x < (ssize_t) source->extent.width; x++)
1118 PixelSetQuantumPixel(source->image,pixels,source->pixel_wands[id][x]);
1119 pixels+=GetPixelChannels(source->image);
1121 destination_pixels=GetCacheViewAuthenticPixels(destination->view,
1122 destination->extent.x,y,destination->extent.width,1,
1123 destination->exception);
1124 if (destination_pixels == (Quantum *) NULL)
1129 for (x=0; x < (ssize_t) destination->extent.width; x++)
1131 PixelSetQuantumPixel(destination->image,destination_pixels,
1132 destination->pixel_wands[id][x]);
1133 destination_pixels+=GetPixelChannels(destination->image);
1135 if (transfer(source,destination,y,id,context) == 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++)
1142 PixelGetQuantumPixel(destination->image,destination->pixel_wands[id][x],
1143 destination_pixels);
1144 destination_pixels+=GetPixelChannels(destination->image);
1146 sync=SyncCacheViewAuthenticPixels(destination->view,destination->exception);
1147 if (sync == MagickFalse)
1149 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
1154 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1155 #pragma omp critical (MagickWand_TransferWandViewIterator)
1157 proceed=SetImageProgress(source_image,source->description,progress++,
1158 source->extent.height);
1159 if (proceed == MagickFalse)
1167 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1171 % U p d a t e W a n d V i e w I t e r a t o r %
1175 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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.
1183 % The callback signature is:
1185 % MagickBooleanType UpdateImageViewMethod(WandView *source,const ssize_t y,
1186 % const int thread_id,void *context)
1188 % Use this pragma if the view is not single threaded:
1190 % #pragma omp critical
1192 % to define a section of code in your callback update method that must be
1193 % executed by a single thread at a time.
1195 % The format of the UpdateWandViewIterator method is:
1197 % MagickBooleanType UpdateWandViewIterator(WandView *source,
1198 % UpdateWandViewMethod update,void *context)
1200 % A description of each parameter follows:
1202 % o source: the source wand view.
1204 % o update: the update callback method.
1206 % o context: the user defined context.
1209 WandExport MagickBooleanType UpdateWandViewIterator(WandView *source,
1210 UpdateWandViewMethod update,void *context)
1221 #if defined(MAGICKCORE_OPENMP_SUPPORT)
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);
1239 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1240 height=source->extent.height-source->extent.y;
1241 #pragma omp parallel for schedule(static) shared(progress,status) \
1242 magick_number_threads(source_image,source_image,height,1)
1244 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
1247 id = GetOpenMPThreadId();
1256 *magick_restrict pixels;
1258 if (status == MagickFalse)
1260 pixels=GetCacheViewAuthenticPixels(source->view,source->extent.x,y,
1261 source->extent.width,1,source->exception);
1262 if (pixels == (Quantum *) NULL)
1267 for (x=0; x < (ssize_t) source->extent.width; x++)
1269 PixelSetQuantumPixel(source->image,pixels,source->pixel_wands[id][x]);
1270 pixels+=GetPixelChannels(source->image);
1272 if (update(source,y,id,context) == MagickFalse)
1274 for (x=0; x < (ssize_t) source->extent.width; x++)
1276 PixelGetQuantumPixel(source->image,source->pixel_wands[id][x],pixels);
1277 pixels+=GetPixelChannels(source->image);
1279 sync=SyncCacheViewAuthenticPixels(source->view,source->exception);
1280 if (sync == MagickFalse)
1282 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
1287 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1288 #pragma omp critical (MagickWand_UpdateWandViewIterator)
1290 proceed=SetImageProgress(source_image,source->description,progress++,
1291 source->extent.height);
1292 if (proceed == MagickFalse)