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-2010 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 % http://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 "wand/studio.h"
49 #include "wand/MagickWand.h"
50 #include "wand/magick-wand-private.h"
51 #include "wand/wand.h"
52 #include "magick/monitor-private.h"
53 #include "magick/thread-private.h"
57 #define WandViewId "WandView"
96 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
100 % C l o n e W a n d V i e w %
104 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
106 % CloneWandView() makes a copy of the specified wand view.
108 % The format of the CloneWandView method is:
110 % WandView *CloneWandView(const WandView *wand_view)
112 % A description of each parameter follows:
114 % o wand_view: the wand view.
117 WandExport WandView *CloneWandView(const WandView *wand_view)
125 assert(wand_view != (WandView *) NULL);
126 assert(wand_view->signature == WandSignature);
127 if (wand_view->debug != MagickFalse)
128 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",wand_view->name);
129 clone_view=(WandView *) AcquireAlignedMemory(1,sizeof(*clone_view));
130 if (clone_view == (WandView *) NULL)
131 ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
133 (void) ResetMagickMemory(clone_view,0,sizeof(*clone_view));
134 clone_view->id=AcquireWandId();
135 (void) FormatMagickString(clone_view->name,MaxTextExtent,"%s-%.20g",
136 WandViewId,(double) clone_view->id);
137 clone_view->exception=AcquireExceptionInfo();
138 InheritException(clone_view->exception,wand_view->exception);
139 clone_view->view=CloneCacheView(wand_view->view);
140 clone_view->region=wand_view->region;
141 clone_view->number_threads=wand_view->number_threads;
142 for (i=0; i < (ssize_t) wand_view->number_threads; i++)
143 clone_view->pixel_wands[i]=ClonePixelWands((const PixelWand **)
144 wand_view->pixel_wands[i],wand_view->region.width);
145 clone_view->debug=wand_view->debug;
146 if (clone_view->debug != MagickFalse)
147 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",clone_view->name);
148 clone_view->signature=WandSignature;
153 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
157 % D e s t r o y W a n d V i e w %
161 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
163 % DestroyWandView() deallocates memory associated with a wand view.
165 % The format of the DestroyWandView method is:
167 % WandView *DestroyWandView(WandView *wand_view)
169 % A description of each parameter follows:
171 % o wand_view: the wand view.
175 static PixelWand ***DestroyPixelsThreadSet(PixelWand ***pixel_wands,
176 const size_t number_wands,const size_t number_threads)
181 assert(pixel_wands != (PixelWand ***) NULL);
182 for (i=0; i < (ssize_t) number_threads; i++)
183 if (pixel_wands[i] != (PixelWand **) NULL)
184 pixel_wands[i]=DestroyPixelWands(pixel_wands[i],number_wands);
185 pixel_wands=(PixelWand ***) RelinquishAlignedMemory(pixel_wands);
189 WandExport WandView *DestroyWandView(WandView *wand_view)
191 assert(wand_view != (WandView *) NULL);
192 assert(wand_view->signature == WandSignature);
193 wand_view->pixel_wands=DestroyPixelsThreadSet(wand_view->pixel_wands,
194 wand_view->region.width,wand_view->number_threads);
195 wand_view->view=DestroyCacheView(wand_view->view);
196 wand_view->exception=DestroyExceptionInfo(wand_view->exception);
197 wand_view->signature=(~WandSignature);
198 RelinquishWandId(wand_view->id);
199 wand_view=(WandView *) RelinquishMagickMemory(wand_view);
204 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
208 % 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 %
212 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
214 % DuplexTransferWandViewIterator() iterates over three wand views in
215 % parallel and calls your transfer method for each scanline of the view. The
216 % source and duplex pixel region is not confined to the image canvas-- that is
217 % you can include negative offsets or widths or heights that exceed the image
218 % dimension. However, the destination wand view is confined to the image
219 % canvas-- that is no negative offsets or widths or heights that exceed the
220 % image dimension are permitted.
222 % Use this pragma if the view is not single threaded:
224 % #pragma omp critical
226 % to define a section of code in your callback transfer method that must be
227 % executed by a single thread at a time.
229 % The format of the DuplexTransferWandViewIterator method is:
231 % MagickBooleanType DuplexTransferWandViewIterator(WandView *source,
232 % WandView *duplex,WandView *destination,
233 % DuplexTransferWandViewMethod transfer,void *context)
235 % A description of each parameter follows:
237 % o source: the source wand view.
239 % o duplex: the duplex wand view.
241 % o destination: the destination wand view.
243 % o transfer: the transfer callback method.
245 % o context: the user defined context.
248 WandExport MagickBooleanType DuplexTransferWandViewIterator(WandView *source,
249 WandView *duplex,WandView *destination,DuplexTransferWandViewMethod transfer,
252 #define DuplexTransferWandViewTag "WandView/DuplexTransfer"
271 assert(source != (WandView *) NULL);
272 assert(source->signature == WandSignature);
273 if (transfer == (DuplexTransferWandViewMethod) NULL)
275 source_image=source->wand->images;
276 duplex_image=duplex->wand->images;
277 destination_image=destination->wand->images;
278 if (SetImageStorageClass(destination_image,DirectClass) == MagickFalse)
282 exception=destination->exception;
283 #if defined(MAGICKCORE_OPENMP_SUPPORT)
284 #pragma omp parallel for schedule(static,1) shared(progress,status)
286 for (y=source->region.y; y < (ssize_t) source->region.height; y++)
291 register const IndexPacket
292 *restrict duplex_indexes,
295 register const PixelPacket
296 *restrict duplex_pixels,
300 *restrict destination_indexes;
307 *restrict destination_pixels;
309 if (status == MagickFalse)
311 id=GetOpenMPThreadId();
312 pixels=GetCacheViewVirtualPixels(source->view,source->region.x,y,
313 source->region.width,1,source->exception);
314 if (pixels == (const PixelPacket *) NULL)
319 indexes=GetCacheViewVirtualIndexQueue(source->view);
320 for (x=0; x < (ssize_t) source->region.width; x++)
321 PixelSetQuantumColor(source->pixel_wands[id][x],pixels+x);
322 if (source_image->colorspace == CMYKColorspace)
323 for (x=0; x < (ssize_t) source->region.width; x++)
324 PixelSetBlackQuantum(source->pixel_wands[id][x],indexes[x]);
325 if (source_image->storage_class == PseudoClass)
326 for (x=0; x < (ssize_t) source->region.width; x++)
327 PixelSetIndex(source->pixel_wands[id][x],indexes[x]);
328 duplex_pixels=GetCacheViewVirtualPixels(duplex->view,duplex->region.x,y,
329 duplex->region.width,1,duplex->exception);
330 if (duplex_pixels == (const PixelPacket *) NULL)
335 duplex_indexes=GetCacheViewVirtualIndexQueue(duplex->view);
336 for (x=0; x < (ssize_t) duplex->region.width; x++)
337 PixelSetQuantumColor(duplex->pixel_wands[id][x],duplex_pixels+x);
338 if (duplex_image->colorspace == CMYKColorspace)
339 for (x=0; x < (ssize_t) duplex->region.width; x++)
340 PixelSetBlackQuantum(duplex->pixel_wands[id][x],duplex_indexes[x]);
341 if (duplex_image->storage_class == PseudoClass)
342 for (x=0; x < (ssize_t) duplex->region.width; x++)
343 PixelSetIndex(duplex->pixel_wands[id][x],duplex_indexes[x]);
344 destination_pixels=GetCacheViewAuthenticPixels(destination->view,
345 destination->region.x,y,destination->region.width,1,exception);
346 if (destination_pixels == (PixelPacket *) NULL)
351 destination_indexes=GetCacheViewAuthenticIndexQueue(destination->view);
352 for (x=0; x < (ssize_t) destination->region.width; x++)
353 PixelSetQuantumColor(destination->pixel_wands[id][x],
354 destination_pixels+x);
355 if (destination_image->colorspace == CMYKColorspace)
356 for (x=0; x < (ssize_t) destination->region.width; x++)
357 PixelSetBlackQuantum(destination->pixel_wands[id][x],
358 destination_indexes[x]);
359 if (destination_image->storage_class == PseudoClass)
360 for (x=0; x < (ssize_t) destination->region.width; x++)
361 PixelSetIndex(destination->pixel_wands[id][x],destination_indexes[x]);
362 if (transfer(source,duplex,destination,context) == MagickFalse)
364 for (x=0; x < (ssize_t) destination->region.width; x++)
365 PixelGetQuantumColor(destination->pixel_wands[id][x],
366 destination_pixels+x);
367 if (destination_image->colorspace == CMYKColorspace)
368 for (x=0; x < (ssize_t) destination->region.width; x++)
369 destination_indexes[x]=PixelGetBlackQuantum(
370 destination->pixel_wands[id][x]);
371 sync=SyncCacheViewAuthenticPixels(destination->view,exception);
372 if (sync == MagickFalse)
374 InheritException(destination->exception,GetCacheViewException(
378 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
383 #if defined(MAGICKCORE_OPENMP_SUPPORT)
384 #pragma omp critical (MagickWand_DuplexTransferWandViewIterator)
386 proceed=SetImageProgress(source_image,DuplexTransferWandViewTag,
387 progress++,source->region.height);
388 if (proceed == MagickFalse)
396 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
400 % G e t W a n d V i e w E x c e p t i o n %
404 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
406 % GetWandViewException() returns the severity, reason, and description of any
407 % error that occurs when utilizing a wand view.
409 % The format of the GetWandViewException method is:
411 % char *GetWandViewException(const PixelWand *wand_view,
412 % ExceptionType *severity)
414 % A description of each parameter follows:
416 % o wand_view: the pixel wand_view.
418 % o severity: the severity of the error is returned here.
421 WandExport char *GetWandViewException(const WandView *wand_view,
422 ExceptionType *severity)
427 assert(wand_view != (const WandView *) NULL);
428 assert(wand_view->signature == WandSignature);
429 if (wand_view->debug != MagickFalse)
430 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",wand_view->name);
431 assert(severity != (ExceptionType *) NULL);
432 *severity=wand_view->exception->severity;
433 description=(char *) AcquireQuantumMemory(2UL*MaxTextExtent,
434 sizeof(*description));
435 if (description == (char *) NULL)
436 ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
439 if (wand_view->exception->reason != (char *) NULL)
440 (void) CopyMagickString(description,GetLocaleExceptionMessage(
441 wand_view->exception->severity,wand_view->exception->reason),
443 if (wand_view->exception->description != (char *) NULL)
445 (void) ConcatenateMagickString(description," (",MaxTextExtent);
446 (void) ConcatenateMagickString(description,GetLocaleExceptionMessage(
447 wand_view->exception->severity,wand_view->exception->description),
449 (void) ConcatenateMagickString(description,")",MaxTextExtent);
455 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
459 % G e t W a n d V i e w H e i g h t %
463 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
465 % GetWandViewHeight() returns the wand view height.
467 % The format of the GetWandViewHeight method is:
469 % size_t GetWandViewHeight(const WandView *wand_view)
471 % A description of each parameter follows:
473 % o wand_view: the wand view.
476 WandExport size_t GetWandViewHeight(const WandView *wand_view)
478 assert(wand_view != (WandView *) NULL);
479 assert(wand_view->signature == WandSignature);
480 return(wand_view->region.height);
484 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
488 % G e t W a n d V i e w I t e r a t o r %
492 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
494 % GetWandViewIterator() iterates over the wand view in parallel and calls
495 % your get method for each scanline of the view. The pixel region 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.
500 % Use this pragma if the view is not single threaded:
502 % #pragma omp critical
504 % to define a section of code in your callback get method that must be
505 % executed by a single thread at a time.
507 % The format of the GetWandViewIterator method is:
509 % MagickBooleanType GetWandViewIterator(WandView *source,
510 % GetWandViewMethod get,void *context)
512 % A description of each parameter follows:
514 % o source: the source wand view.
516 % o get: the get callback method.
518 % o context: the user defined context.
521 WandExport MagickBooleanType GetWandViewIterator(WandView *source,
522 GetWandViewMethod get,void *context)
524 #define GetWandViewTag "WandView/Get"
538 assert(source != (WandView *) NULL);
539 assert(source->signature == WandSignature);
540 if (get == (GetWandViewMethod) NULL)
542 source_image=source->wand->images;
545 #if defined(MAGICKCORE_OPENMP_SUPPORT)
546 #pragma omp parallel for schedule(static,1) shared(progress,status)
548 for (y=source->region.y; y < (ssize_t) source->region.height; y++)
550 register const IndexPacket
553 register const PixelPacket
560 if (status == MagickFalse)
562 id=GetOpenMPThreadId();
563 pixels=GetCacheViewVirtualPixels(source->view,source->region.x,y,
564 source->region.width,1,source->exception);
565 if (pixels == (const PixelPacket *) NULL)
570 indexes=GetCacheViewVirtualIndexQueue(source->view);
571 for (x=0; x < (ssize_t) source->region.width; x++)
572 PixelSetQuantumColor(source->pixel_wands[id][x],pixels+x);
573 if (source_image->colorspace == CMYKColorspace)
574 for (x=0; x < (ssize_t) source->region.width; x++)
575 PixelSetBlackQuantum(source->pixel_wands[id][x],indexes[x]);
576 if (source_image->storage_class == PseudoClass)
577 for (x=0; x < (ssize_t) source->region.width; x++)
578 PixelSetIndex(source->pixel_wands[id][x],indexes[x]);
579 if (get(source,context) == MagickFalse)
581 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
586 #if defined(MAGICKCORE_OPENMP_SUPPORT)
587 #pragma omp critical (MagickWand_GetWandViewIterator)
589 proceed=SetImageProgress(source_image,GetWandViewTag,progress++,
590 source->region.height);
591 if (proceed == MagickFalse)
599 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
603 % G e t W a n d V i e w P i x e l s %
607 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
609 % GetWandViewPixels() returns the wand view pixel_wands.
611 % The format of the GetWandViewPixels method is:
613 % PixelWand *GetWandViewPixels(const WandView *wand_view)
615 % A description of each parameter follows:
617 % o wand_view: the wand view.
620 WandExport PixelWand **GetWandViewPixels(const WandView *wand_view)
625 assert(wand_view != (WandView *) NULL);
626 assert(wand_view->signature == WandSignature);
627 id=GetOpenMPThreadId();
628 return(wand_view->pixel_wands[id]);
632 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
636 % G e t W a n d V i e w W a n d %
640 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
642 % GetWandViewWand() returns the magick wand associated with the wand view.
644 % The format of the GetWandViewWand method is:
646 % MagickWand *GetWandViewWand(const WandView *wand_view)
648 % A description of each parameter follows:
650 % o wand_view: the wand view.
653 WandExport MagickWand *GetWandViewWand(const WandView *wand_view)
655 assert(wand_view != (WandView *) NULL);
656 assert(wand_view->signature == WandSignature);
657 return(wand_view->wand);
661 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
665 % G e t W a n d V i e w W i d t h %
669 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
671 % GetWandViewWidth() returns the wand view width.
673 % The format of the GetWandViewWidth method is:
675 % size_t GetWandViewWidth(const WandView *wand_view)
677 % A description of each parameter follows:
679 % o wand_view: the wand view.
682 WandExport size_t GetWandViewWidth(const WandView *wand_view)
684 assert(wand_view != (WandView *) NULL);
685 assert(wand_view->signature == WandSignature);
686 return(wand_view->region.width);
690 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
694 % G e t W a n d V i e w X %
698 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
700 % GetWandViewX() returns the wand view x offset.
702 % The format of the GetWandViewX method is:
704 % ssize_t GetWandViewX(const WandView *wand_view)
706 % A description of each parameter follows:
708 % o wand_view: the wand view.
711 WandExport ssize_t GetWandViewX(const WandView *wand_view)
713 assert(wand_view != (WandView *) NULL);
714 assert(wand_view->signature == WandSignature);
715 return(wand_view->region.x);
719 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
723 % G e t W a n d V i e w Y %
727 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
729 % GetWandViewY() returns the wand view y offset.
731 % The format of the GetWandViewY method is:
733 % ssize_t GetWandViewY(const WandView *wand_view)
735 % A description of each parameter follows:
737 % o wand_view: the wand view.
740 WandExport ssize_t GetWandViewY(const WandView *wand_view)
742 assert(wand_view != (WandView *) NULL);
743 assert(wand_view->signature == WandSignature);
744 return(wand_view->region.y);
748 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
752 % I s W a n d V i e w %
756 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
758 % IsWandView() returns MagickTrue if the the parameter is verified as a wand
761 % The format of the IsWandView method is:
763 % MagickBooleanType IsWandView(const WandView *wand_view)
765 % A description of each parameter follows:
767 % o wand_view: the wand view.
770 WandExport MagickBooleanType IsWandView(const WandView *wand_view)
775 if (wand_view == (const WandView *) NULL)
777 if (wand_view->signature != WandSignature)
779 length=strlen(WandViewId);
780 if (LocaleNCompare(wand_view->name,WandViewId,length) != 0)
786 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
790 % N e w W a n d V i e w %
794 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
796 % NewWandView() returns a wand view required for all other methods in the
799 % The format of the NewWandView method is:
801 % WandView *NewWandView(MagickWand *wand)
803 % A description of each parameter follows:
809 static PixelWand ***AcquirePixelsThreadSet(const size_t number_wands,
810 const size_t number_threads)
818 pixel_wands=(PixelWand ***) AcquireAlignedMemory(number_threads,
819 sizeof(*pixel_wands));
820 if (pixel_wands == (PixelWand ***) NULL)
821 return((PixelWand ***) NULL);
822 (void) ResetMagickMemory(pixel_wands,0,number_threads*sizeof(*pixel_wands));
823 for (i=0; i < (ssize_t) number_threads; i++)
825 pixel_wands[i]=NewPixelWands(number_wands);
826 if (pixel_wands[i] == (PixelWand **) NULL)
827 return(DestroyPixelsThreadSet(pixel_wands,number_wands,number_threads));
832 WandExport WandView *NewWandView(MagickWand *wand)
837 assert(wand != (MagickWand *) NULL);
838 assert(wand->signature == MagickSignature);
839 wand_view=(WandView *) AcquireAlignedMemory(1,sizeof(*wand_view));
840 if (wand_view == (WandView *) NULL)
841 ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
842 GetExceptionMessage(errno));
843 (void) ResetMagickMemory(wand_view,0,sizeof(*wand_view));
844 wand_view->id=AcquireWandId();
845 (void) FormatMagickString(wand_view->name,MaxTextExtent,"%s-%.20g",
846 WandViewId,(double) wand_view->id);
847 wand_view->exception=AcquireExceptionInfo();
848 wand_view->wand=wand;
849 wand_view->view=AcquireCacheView(wand_view->wand->images);
850 wand_view->region.width=wand->images->columns;
851 wand_view->region.height=wand->images->rows;
852 wand_view->number_threads=GetOpenMPMaximumThreads();
853 wand_view->pixel_wands=AcquirePixelsThreadSet(wand_view->region.width,
854 wand_view->number_threads);
855 if (wand_view->pixel_wands == (PixelWand ***) NULL)
856 ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
857 GetExceptionMessage(errno));
858 wand_view->debug=IsEventLogging();
859 wand_view->signature=WandSignature;
864 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
868 % N e w W a n d V i e w R e g i o n %
872 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
874 % NewWandViewRegion() returns a wand view required for all other methods
875 % in the Wand View API.
877 % The format of the NewWandViewRegion method is:
879 % WandView *NewWandViewRegion(MagickWand *wand,const ssize_t x,
880 % const ssize_t y,const size_t width,const size_t height)
882 % A description of each parameter follows:
884 % o wand: the magick wand.
886 % o x,y,columns,rows: These values define the perimeter of a region of
890 WandExport WandView *NewWandViewRegion(MagickWand *wand,const ssize_t x,
891 const ssize_t y,const size_t width,const size_t height)
896 assert(wand != (MagickWand *) NULL);
897 assert(wand->signature == MagickSignature);
898 wand_view=(WandView *) AcquireAlignedMemory(1,sizeof(*wand_view));
899 if (wand_view == (WandView *) NULL)
900 ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
901 GetExceptionMessage(errno));
902 (void) ResetMagickMemory(wand_view,0,sizeof(*wand_view));
903 wand_view->id=AcquireWandId();
904 (void) FormatMagickString(wand_view->name,MaxTextExtent,"%s-%.20g",
905 WandViewId,(double) wand_view->id);
906 wand_view->exception=AcquireExceptionInfo();
907 wand_view->view=AcquireCacheView(wand_view->wand->images);
908 wand_view->wand=wand;
909 wand_view->region.width=width;
910 wand_view->region.height=height;
911 wand_view->region.x=x;
912 wand_view->region.y=y;
913 wand_view->number_threads=GetOpenMPMaximumThreads();
914 wand_view->pixel_wands=AcquirePixelsThreadSet(wand_view->region.width,
915 wand_view->number_threads);
916 if (wand_view->pixel_wands == (PixelWand ***) NULL)
917 ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
918 GetExceptionMessage(errno));
919 wand_view->debug=IsEventLogging();
920 wand_view->signature=WandSignature;
925 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
929 % S e t W a n d V i e w I t e r a t o r %
933 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
935 % SetWandViewIterator() iterates over the wand view in parallel and calls
936 % your set method for each scanline of the view. The pixel region is
937 % confined to the image canvas-- that is no negative offsets or widths or
938 % heights that exceed the image dimension. The pixels are initiallly
939 % undefined and any settings you make in the callback method are automagically
940 % synced back to your image.
942 % Use this pragma if the view is not single threaded:
944 % #pragma omp critical
946 % to define a section of code in your callback set method that must be
947 % executed by a single thread at a time.
949 % The format of the SetWandViewIterator method is:
951 % MagickBooleanType SetWandViewIterator(WandView *destination,
952 % SetWandViewMethod set,void *context)
954 % A description of each parameter follows:
956 % o destination: the wand view.
958 % o set: the set callback method.
960 % o context: the user defined context.
963 WandExport MagickBooleanType SetWandViewIterator(WandView *destination,
964 SetWandViewMethod set,void *context)
966 #define SetWandViewTag "WandView/Set"
983 assert(destination != (WandView *) NULL);
984 assert(destination->signature == WandSignature);
985 if (set == (SetWandViewMethod) NULL)
987 destination_image=destination->wand->images;
988 if (SetImageStorageClass(destination_image,DirectClass) == MagickFalse)
992 exception=destination->exception;
993 #if defined(MAGICKCORE_OPENMP_SUPPORT)
994 #pragma omp parallel for schedule(static,1) shared(progress,status)
996 for (y=destination->region.y; y < (ssize_t) destination->region.height; y++)
1001 register IndexPacket
1008 register PixelPacket
1011 if (status == MagickFalse)
1013 id=GetOpenMPThreadId();
1014 pixels=GetCacheViewAuthenticPixels(destination->view,destination->region.x,
1015 y,destination->region.width,1,exception);
1016 if (pixels == (PixelPacket *) NULL)
1018 InheritException(destination->exception,GetCacheViewException(
1019 destination->view));
1023 indexes=GetCacheViewAuthenticIndexQueue(destination->view);
1024 if (set(destination,context) == MagickFalse)
1026 for (x=0; x < (ssize_t) destination->region.width; x++)
1027 PixelGetQuantumColor(destination->pixel_wands[id][x],pixels+x);
1028 if (destination_image->colorspace == CMYKColorspace)
1029 for (x=0; x < (ssize_t) destination->region.width; x++)
1030 indexes[x]=PixelGetBlackQuantum(destination->pixel_wands[id][x]);
1031 sync=SyncCacheViewAuthenticPixels(destination->view,exception);
1032 if (sync == MagickFalse)
1034 InheritException(destination->exception,GetCacheViewException(
1035 destination->view));
1038 if (destination_image->progress_monitor != (MagickProgressMonitor) NULL)
1043 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1044 #pragma omp critical (MagickWand_SetWandViewIterator)
1046 proceed=SetImageProgress(destination_image,SetWandViewTag,progress++,
1047 destination->region.height);
1048 if (proceed == MagickFalse)
1056 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1060 % T r a n s f e r W a n d V i e w I t e r a t o r %
1064 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1066 % TransferWandViewIterator() iterates over two wand views in parallel and
1067 % calls your transfer method for each scanline of the view. The source pixel
1068 % region is not confined to the image canvas-- that is you can include
1069 % negative offsets or widths or heights that exceed the image dimension.
1070 % However, the destination wand view is confined to the image canvas-- that
1071 % is no negative offsets or widths or heights that exceed the image dimension
1074 % Use this pragma if the view is not single threaded:
1076 % #pragma omp critical
1078 % to define a section of code in your callback transfer method that must be
1079 % executed by a single thread at a time.
1081 % The format of the TransferWandViewIterator method is:
1083 % MagickBooleanType TransferWandViewIterator(WandView *source,
1084 % WandView *destination,TransferWandViewMethod transfer,void *context)
1086 % A description of each parameter follows:
1088 % o source: the source wand view.
1090 % o destination: the destination wand view.
1092 % o transfer: the transfer callback method.
1094 % o context: the user defined context.
1097 WandExport MagickBooleanType TransferWandViewIterator(WandView *source,
1098 WandView *destination,TransferWandViewMethod transfer,void *context)
1100 #define TransferWandViewTag "WandView/Transfer"
1118 assert(source != (WandView *) NULL);
1119 assert(source->signature == WandSignature);
1120 if (transfer == (TransferWandViewMethod) NULL)
1121 return(MagickFalse);
1122 source_image=source->wand->images;
1123 destination_image=destination->wand->images;
1124 if (SetImageStorageClass(destination_image,DirectClass) == MagickFalse)
1125 return(MagickFalse);
1128 exception=destination->exception;
1129 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1130 #pragma omp parallel for schedule(static,1) shared(progress,status)
1132 for (y=source->region.y; y < (ssize_t) source->region.height; y++)
1137 register const IndexPacket
1140 register const PixelPacket
1143 register IndexPacket
1144 *restrict destination_indexes;
1150 register PixelPacket
1151 *restrict destination_pixels;
1153 if (status == MagickFalse)
1155 id=GetOpenMPThreadId();
1156 pixels=GetCacheViewVirtualPixels(source->view,source->region.x,y,
1157 source->region.width,1,source->exception);
1158 if (pixels == (const PixelPacket *) NULL)
1163 indexes=GetCacheViewVirtualIndexQueue(source->view);
1164 for (x=0; x < (ssize_t) source->region.width; x++)
1165 PixelSetQuantumColor(source->pixel_wands[id][x],pixels+x);
1166 if (source_image->colorspace == CMYKColorspace)
1167 for (x=0; x < (ssize_t) source->region.width; x++)
1168 PixelSetBlackQuantum(source->pixel_wands[id][x],indexes[x]);
1169 if (source_image->storage_class == PseudoClass)
1170 for (x=0; x < (ssize_t) source->region.width; x++)
1171 PixelSetIndex(source->pixel_wands[id][x],indexes[x]);
1172 destination_pixels=GetCacheViewAuthenticPixels(destination->view,
1173 destination->region.x,y,destination->region.width,1,exception);
1174 if (destination_pixels == (PixelPacket *) NULL)
1179 destination_indexes=GetCacheViewAuthenticIndexQueue(destination->view);
1180 for (x=0; x < (ssize_t) destination->region.width; x++)
1181 PixelSetQuantumColor(destination->pixel_wands[id][x],pixels+x);
1182 if (destination_image->colorspace == CMYKColorspace)
1183 for (x=0; x < (ssize_t) destination->region.width; x++)
1184 PixelSetBlackQuantum(destination->pixel_wands[id][x],indexes[x]);
1185 if (destination_image->storage_class == PseudoClass)
1186 for (x=0; x < (ssize_t) destination->region.width; x++)
1187 PixelSetIndex(destination->pixel_wands[id][x],indexes[x]);
1188 if (transfer(source,destination,context) == MagickFalse)
1190 for (x=0; x < (ssize_t) destination->region.width; x++)
1191 PixelGetQuantumColor(destination->pixel_wands[id][x],
1192 destination_pixels+x);
1193 if (destination_image->colorspace == CMYKColorspace)
1194 for (x=0; x < (ssize_t) destination->region.width; x++)
1195 destination_indexes[x]=PixelGetBlackQuantum(
1196 destination->pixel_wands[id][x]);
1197 sync=SyncCacheViewAuthenticPixels(destination->view,exception);
1198 if (sync == MagickFalse)
1200 InheritException(destination->exception,GetCacheViewException(
1204 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
1209 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1210 #pragma omp critical (MagickWand_TransferWandViewIterator)
1212 proceed=SetImageProgress(source_image,TransferWandViewTag,progress++,
1213 source->region.height);
1214 if (proceed == MagickFalse)
1222 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1226 % U p d a t e W a n d V i e w I t e r a t o r %
1230 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1232 % UpdateWandViewIterator() iterates over the wand view in parallel and calls
1233 % your update method for each scanline of the view. The pixel region is
1234 % confined to the image canvas-- that is no negative offsets or widths or
1235 % heights that exceed the image dimension are permitted. Updates to pixels
1236 % in your callback are automagically synced back to the image.
1238 % Use this pragma if the view is not single threaded:
1240 % #pragma omp critical
1242 % to define a section of code in your callback update method that must be
1243 % executed by a single thread at a time.
1245 % The format of the UpdateWandViewIterator method is:
1247 % MagickBooleanType UpdateWandViewIterator(WandView *source,
1248 % UpdateWandViewMethod update,void *context)
1250 % A description of each parameter follows:
1252 % o source: the source wand view.
1254 % o update: the update callback method.
1256 % o context: the user defined context.
1259 WandExport MagickBooleanType UpdateWandViewIterator(WandView *source,
1260 UpdateWandViewMethod update,void *context)
1262 #define UpdateWandViewTag "WandView/Update"
1279 assert(source != (WandView *) NULL);
1280 assert(source->signature == WandSignature);
1281 if (update == (UpdateWandViewMethod) NULL)
1282 return(MagickFalse);
1283 source_image=source->wand->images;
1284 if (SetImageStorageClass(source_image,DirectClass) == MagickFalse)
1285 return(MagickFalse);
1288 exception=source->exception;
1289 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1290 #pragma omp parallel for schedule(static,1) shared(progress,status)
1292 for (y=source->region.y; y < (ssize_t) source->region.height; y++)
1294 register IndexPacket
1301 register PixelPacket
1304 if (status == MagickFalse)
1306 id=GetOpenMPThreadId();
1307 pixels=GetCacheViewAuthenticPixels(source->view,source->region.x,y,
1308 source->region.width,1,exception);
1309 if (pixels == (PixelPacket *) NULL)
1311 InheritException(source->exception,GetCacheViewException(
1316 indexes=GetCacheViewAuthenticIndexQueue(source->view);
1317 for (x=0; x < (ssize_t) source->region.width; x++)
1318 PixelSetQuantumColor(source->pixel_wands[id][x],pixels+x);
1319 if (source_image->colorspace == CMYKColorspace)
1320 for (x=0; x < (ssize_t) source->region.width; x++)
1321 PixelSetBlackQuantum(source->pixel_wands[id][x],indexes[x]);
1322 if (update(source,context) == MagickFalse)
1324 for (x=0; x < (ssize_t) source->region.width; x++)
1325 PixelGetQuantumColor(source->pixel_wands[id][x],pixels+x);
1326 if (source_image->colorspace == CMYKColorspace)
1327 for (x=0; x < (ssize_t) source->region.width; x++)
1328 indexes[x]=PixelGetBlackQuantum(source->pixel_wands[id][x]);
1329 if (SyncCacheViewAuthenticPixels(source->view,exception) == MagickFalse)
1331 InheritException(source->exception,GetCacheViewException(source->view));
1334 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
1339 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1340 #pragma omp critical (MagickWand_UpdateWandViewIterator)
1342 proceed=SetImageProgress(source_image,UpdateWandViewTag,progress++,
1343 source->region.height);
1344 if (proceed == MagickFalse)