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"
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 == WandSignature);
128 if (wand_view->debug != MagickFalse)
129 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",wand_view->name);
130 clone_view=(WandView *) AcquireAlignedMemory(1,sizeof(*clone_view));
131 if (clone_view == (WandView *) NULL)
132 ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
134 (void) ResetMagickMemory(clone_view,0,sizeof(*clone_view));
135 clone_view->id=AcquireWandId();
136 (void) FormatMagickString(clone_view->name,MaxTextExtent,"%s-%.20g",
137 WandViewId,(double) clone_view->id);
138 clone_view->description=ConstantString(wand_view->description);
139 clone_view->view=CloneCacheView(wand_view->view);
140 clone_view->extent=wand_view->extent;
141 clone_view->number_threads=wand_view->number_threads;
142 clone_view->exception=AcquireExceptionInfo();
143 InheritException(clone_view->exception,wand_view->exception);
144 for (i=0; i < (ssize_t) wand_view->number_threads; i++)
145 clone_view->pixel_wands[i]=ClonePixelWands((const PixelWand **)
146 wand_view->pixel_wands[i],wand_view->extent.width);
147 clone_view->debug=wand_view->debug;
148 if (clone_view->debug != MagickFalse)
149 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",clone_view->name);
150 clone_view->signature=WandSignature;
155 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
159 % D e s t r o y W a n d V i e w %
163 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
165 % DestroyWandView() deallocates memory associated with a wand view.
167 % The format of the DestroyWandView method is:
169 % WandView *DestroyWandView(WandView *wand_view)
171 % A description of each parameter follows:
173 % o wand_view: the wand view.
177 static PixelWand ***DestroyPixelsThreadSet(PixelWand ***pixel_wands,
178 const size_t number_wands,const size_t number_threads)
183 assert(pixel_wands != (PixelWand ***) NULL);
184 for (i=0; i < (ssize_t) number_threads; i++)
185 if (pixel_wands[i] != (PixelWand **) NULL)
186 pixel_wands[i]=DestroyPixelWands(pixel_wands[i],number_wands);
187 pixel_wands=(PixelWand ***) RelinquishAlignedMemory(pixel_wands);
191 WandExport WandView *DestroyWandView(WandView *wand_view)
193 assert(wand_view != (WandView *) NULL);
194 assert(wand_view->signature == WandSignature);
195 wand_view->pixel_wands=DestroyPixelsThreadSet(wand_view->pixel_wands,
196 wand_view->extent.width,wand_view->number_threads);
197 wand_view->view=DestroyCacheView(wand_view->view);
198 wand_view->exception=DestroyExceptionInfo(wand_view->exception);
199 wand_view->signature=(~WandSignature);
200 RelinquishWandId(wand_view->id);
201 wand_view=(WandView *) RelinquishMagickMemory(wand_view);
206 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
210 % 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 %
214 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
216 % DuplexTransferWandViewIterator() iterates over three wand views in
217 % parallel and calls your transfer method for each scanline of the view. The
218 % source and duplex pixel extent is not confined to the image canvas-- that is
219 % you can include negative offsets or widths or heights that exceed the image
220 % dimension. However, the destination wand view is confined to the image
221 % canvas-- that is no negative offsets or widths or heights that exceed the
222 % image dimension are permitted.
224 % The callback signature is:
226 % MagickBooleanType DuplexTransferImageViewMethod(const WandView *source,
227 % const WandView *duplex,WandView *destination,const ssize_t y,
228 % const int thread_id,void *context)
230 % Use this pragma if the view is not single threaded:
232 % #pragma omp critical
234 % to define a section of code in your callback transfer method that must be
235 % executed by a single thread at a time.
237 % The format of the DuplexTransferWandViewIterator method is:
239 % MagickBooleanType DuplexTransferWandViewIterator(WandView *source,
240 % WandView *duplex,WandView *destination,
241 % DuplexTransferWandViewMethod transfer,void *context)
243 % A description of each parameter follows:
245 % o source: the source wand view.
247 % o duplex: the duplex wand view.
249 % o destination: the destination wand view.
251 % o transfer: the transfer callback method.
253 % o context: the user defined context.
256 WandExport MagickBooleanType DuplexTransferWandViewIterator(WandView *source,
257 WandView *duplex,WandView *destination,DuplexTransferWandViewMethod transfer,
277 assert(source != (WandView *) NULL);
278 assert(source->signature == WandSignature);
279 if (transfer == (DuplexTransferWandViewMethod) NULL)
281 source_image=source->wand->images;
282 duplex_image=duplex->wand->images;
283 destination_image=destination->wand->images;
284 if (SetImageStorageClass(destination_image,DirectClass) == MagickFalse)
288 exception=destination->exception;
289 #if defined(MAGICKCORE_OPENMP_SUPPORT)
290 #pragma omp parallel for schedule(static,1) shared(progress,status)
292 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
300 register const IndexPacket
301 *restrict duplex_indexes,
304 register const PixelPacket
305 *restrict duplex_pixels,
309 *restrict destination_indexes;
315 *restrict destination_pixels;
317 if (status == MagickFalse)
319 id=GetOpenMPThreadId();
320 pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y,
321 source->extent.width,1,source->exception);
322 if (pixels == (const PixelPacket *) NULL)
327 indexes=GetCacheViewVirtualIndexQueue(source->view);
328 for (x=0; x < (ssize_t) source->extent.width; x++)
329 PixelSetQuantumColor(source->pixel_wands[id][x],pixels+x);
330 if (source_image->colorspace == CMYKColorspace)
331 for (x=0; x < (ssize_t) source->extent.width; x++)
332 PixelSetBlackQuantum(source->pixel_wands[id][x],indexes[x]);
333 if (source_image->storage_class == PseudoClass)
334 for (x=0; x < (ssize_t) source->extent.width; x++)
335 PixelSetIndex(source->pixel_wands[id][x],indexes[x]);
336 duplex_pixels=GetCacheViewVirtualPixels(duplex->view,duplex->extent.x,y,
337 duplex->extent.width,1,duplex->exception);
338 if (duplex_pixels == (const PixelPacket *) NULL)
343 duplex_indexes=GetCacheViewVirtualIndexQueue(duplex->view);
344 for (x=0; x < (ssize_t) duplex->extent.width; x++)
345 PixelSetQuantumColor(duplex->pixel_wands[id][x],duplex_pixels+x);
346 if (duplex_image->colorspace == CMYKColorspace)
347 for (x=0; x < (ssize_t) duplex->extent.width; x++)
348 PixelSetBlackQuantum(duplex->pixel_wands[id][x],duplex_indexes[x]);
349 if (duplex_image->storage_class == PseudoClass)
350 for (x=0; x < (ssize_t) duplex->extent.width; x++)
351 PixelSetIndex(duplex->pixel_wands[id][x],duplex_indexes[x]);
352 destination_pixels=GetCacheViewAuthenticPixels(destination->view,
353 destination->extent.x,y,destination->extent.width,1,exception);
354 if (destination_pixels == (PixelPacket *) NULL)
359 destination_indexes=GetCacheViewAuthenticIndexQueue(destination->view);
360 for (x=0; x < (ssize_t) destination->extent.width; x++)
361 PixelSetQuantumColor(destination->pixel_wands[id][x],
362 destination_pixels+x);
363 if (destination_image->colorspace == CMYKColorspace)
364 for (x=0; x < (ssize_t) destination->extent.width; x++)
365 PixelSetBlackQuantum(destination->pixel_wands[id][x],
366 destination_indexes[x]);
367 if (destination_image->storage_class == PseudoClass)
368 for (x=0; x < (ssize_t) destination->extent.width; x++)
369 PixelSetIndex(destination->pixel_wands[id][x],destination_indexes[x]);
370 if (transfer(source,duplex,destination,y,id,context) == MagickFalse)
372 for (x=0; x < (ssize_t) destination->extent.width; x++)
373 PixelGetQuantumColor(destination->pixel_wands[id][x],
374 destination_pixels+x);
375 if (destination_image->colorspace == CMYKColorspace)
376 for (x=0; x < (ssize_t) destination->extent.width; x++)
377 destination_indexes[x]=PixelGetBlackQuantum(
378 destination->pixel_wands[id][x]);
379 sync=SyncCacheViewAuthenticPixels(destination->view,exception);
380 if (sync == MagickFalse)
382 InheritException(destination->exception,GetCacheViewException(
386 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
391 #if defined(MAGICKCORE_OPENMP_SUPPORT)
392 #pragma omp critical (MagickWand_DuplexTransferWandViewIterator)
394 proceed=SetImageProgress(source_image,source->description,progress++,
395 source->extent.height);
396 if (proceed == MagickFalse)
404 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
408 % G e t W a n d V i e w E x c e p t i o n %
412 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
414 % GetWandViewException() returns the severity, reason, and description of any
415 % error that occurs when utilizing a wand view.
417 % The format of the GetWandViewException method is:
419 % char *GetWandViewException(const PixelWand *wand_view,
420 % ExceptionType *severity)
422 % A description of each parameter follows:
424 % o wand_view: the pixel wand_view.
426 % o severity: the severity of the error is returned here.
429 WandExport char *GetWandViewException(const WandView *wand_view,
430 ExceptionType *severity)
435 assert(wand_view != (const WandView *) NULL);
436 assert(wand_view->signature == WandSignature);
437 if (wand_view->debug != MagickFalse)
438 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",wand_view->name);
439 assert(severity != (ExceptionType *) NULL);
440 *severity=wand_view->exception->severity;
441 description=(char *) AcquireQuantumMemory(2UL*MaxTextExtent,
442 sizeof(*description));
443 if (description == (char *) NULL)
444 ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
447 if (wand_view->exception->reason != (char *) NULL)
448 (void) CopyMagickString(description,GetLocaleExceptionMessage(
449 wand_view->exception->severity,wand_view->exception->reason),
451 if (wand_view->exception->description != (char *) NULL)
453 (void) ConcatenateMagickString(description," (",MaxTextExtent);
454 (void) ConcatenateMagickString(description,GetLocaleExceptionMessage(
455 wand_view->exception->severity,wand_view->exception->description),
457 (void) ConcatenateMagickString(description,")",MaxTextExtent);
463 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
467 % G e t W a n d V i e w E x t e n t %
471 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
473 % GetWandViewExtent() returns the wand view extent.
475 % The format of the GetWandViewExtent method is:
477 % RectangleInfo GetWandViewExtent(const WandView *wand_view)
479 % A description of each parameter follows:
481 % o wand_view: the wand view.
484 WandExport RectangleInfo GetWandViewExtent(const WandView *wand_view)
486 assert(wand_view != (WandView *) NULL);
487 assert(wand_view->signature == WandSignature);
488 return(wand_view->extent);
492 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
496 % G e t W a n d V i e w I t e r a t o r %
500 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
502 % GetWandViewIterator() iterates over the wand view in parallel and calls
503 % your get method for each scanline of the view. The pixel extent is
504 % not confined to the image canvas-- that is you can include negative offsets
505 % or widths or heights that exceed the image dimension. Any updates to
506 % the pixels in your callback are ignored.
508 % The callback signature is:
510 % MagickBooleanType GetImageViewMethod(const WandView *source,
511 % const ssize_t y,const int thread_id,void *context)
513 % Use this pragma if the view is not single threaded:
515 % #pragma omp critical
517 % to define a section of code in your callback get method that must be
518 % executed by a single thread at a time.
520 % The format of the GetWandViewIterator method is:
522 % MagickBooleanType GetWandViewIterator(WandView *source,
523 % GetWandViewMethod get,void *context)
525 % A description of each parameter follows:
527 % o source: the source wand view.
529 % o get: the get callback method.
531 % o context: the user defined context.
534 WandExport MagickBooleanType GetWandViewIterator(WandView *source,
535 GetWandViewMethod get,void *context)
549 assert(source != (WandView *) NULL);
550 assert(source->signature == WandSignature);
551 if (get == (GetWandViewMethod) NULL)
553 source_image=source->wand->images;
556 #if defined(MAGICKCORE_OPENMP_SUPPORT)
557 #pragma omp parallel for schedule(static,1) shared(progress,status)
559 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
564 register const IndexPacket
567 register const PixelPacket
573 if (status == MagickFalse)
575 id=GetOpenMPThreadId();
576 pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y,
577 source->extent.width,1,source->exception);
578 if (pixels == (const PixelPacket *) NULL)
583 indexes=GetCacheViewVirtualIndexQueue(source->view);
584 for (x=0; x < (ssize_t) source->extent.width; x++)
585 PixelSetQuantumColor(source->pixel_wands[id][x],pixels+x);
586 if (source_image->colorspace == CMYKColorspace)
587 for (x=0; x < (ssize_t) source->extent.width; x++)
588 PixelSetBlackQuantum(source->pixel_wands[id][x],indexes[x]);
589 if (source_image->storage_class == PseudoClass)
590 for (x=0; x < (ssize_t) source->extent.width; x++)
591 PixelSetIndex(source->pixel_wands[id][x],indexes[x]);
592 if (get(source,y,id,context) == MagickFalse)
594 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
599 #if defined(MAGICKCORE_OPENMP_SUPPORT)
600 #pragma omp critical (MagickWand_GetWandViewIterator)
602 proceed=SetImageProgress(source_image,source->description,progress++,
603 source->extent.height);
604 if (proceed == MagickFalse)
612 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
616 % G e t W a n d V i e w P i x e l s %
620 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
622 % GetWandViewPixels() returns the wand view pixel_wands.
624 % The format of the GetWandViewPixels method is:
626 % PixelWand *GetWandViewPixels(const WandView *wand_view)
628 % A description of each parameter follows:
630 % o wand_view: the wand view.
633 WandExport PixelWand **GetWandViewPixels(const WandView *wand_view)
638 assert(wand_view != (WandView *) NULL);
639 assert(wand_view->signature == WandSignature);
640 id=GetOpenMPThreadId();
641 return(wand_view->pixel_wands[id]);
645 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
649 % G e t W a n d V i e w W a n d %
653 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
655 % GetWandViewWand() returns the magick wand associated with the wand view.
657 % The format of the GetWandViewWand method is:
659 % MagickWand *GetWandViewWand(const WandView *wand_view)
661 % A description of each parameter follows:
663 % o wand_view: the wand view.
666 WandExport MagickWand *GetWandViewWand(const WandView *wand_view)
668 assert(wand_view != (WandView *) NULL);
669 assert(wand_view->signature == WandSignature);
670 return(wand_view->wand);
674 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
678 % I s W a n d V i e w %
682 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
684 % IsWandView() returns MagickTrue if the the parameter is verified as a wand
687 % The format of the IsWandView method is:
689 % MagickBooleanType IsWandView(const WandView *wand_view)
691 % A description of each parameter follows:
693 % o wand_view: the wand view.
696 WandExport MagickBooleanType IsWandView(const WandView *wand_view)
701 if (wand_view == (const WandView *) NULL)
703 if (wand_view->signature != WandSignature)
705 length=strlen(WandViewId);
706 if (LocaleNCompare(wand_view->name,WandViewId,length) != 0)
712 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
716 % N e w W a n d V i e w %
720 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
722 % NewWandView() returns a wand view required for all other methods in the
725 % The format of the NewWandView method is:
727 % WandView *NewWandView(MagickWand *wand)
729 % A description of each parameter follows:
735 static PixelWand ***AcquirePixelsThreadSet(const size_t number_wands,
736 const size_t number_threads)
744 pixel_wands=(PixelWand ***) AcquireAlignedMemory(number_threads,
745 sizeof(*pixel_wands));
746 if (pixel_wands == (PixelWand ***) NULL)
747 return((PixelWand ***) NULL);
748 (void) ResetMagickMemory(pixel_wands,0,number_threads*sizeof(*pixel_wands));
749 for (i=0; i < (ssize_t) number_threads; i++)
751 pixel_wands[i]=NewPixelWands(number_wands);
752 if (pixel_wands[i] == (PixelWand **) NULL)
753 return(DestroyPixelsThreadSet(pixel_wands,number_wands,number_threads));
758 WandExport WandView *NewWandView(MagickWand *wand)
763 assert(wand != (MagickWand *) NULL);
764 assert(wand->signature == WandSignature);
765 wand_view=(WandView *) AcquireAlignedMemory(1,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) FormatMagickString(wand_view->name,MaxTextExtent,"%s-%.20g",
772 WandViewId,(double) wand_view->id);
773 wand_view->description=ConstantString("WandView");
774 wand_view->wand=wand;
775 wand_view->view=AcquireCacheView(wand_view->wand->images);
776 wand_view->extent.width=wand->images->columns;
777 wand_view->extent.height=wand->images->rows;
778 wand_view->number_threads=GetOpenMPMaximumThreads();
779 wand_view->pixel_wands=AcquirePixelsThreadSet(wand_view->extent.width,
780 wand_view->number_threads);
781 wand_view->exception=AcquireExceptionInfo();
782 if (wand_view->pixel_wands == (PixelWand ***) NULL)
783 ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
784 GetExceptionMessage(errno));
785 wand_view->debug=IsEventLogging();
786 wand_view->signature=WandSignature;
791 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
795 % N e w W a n d V i e w E x t e n t %
799 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
801 % NewWandViewExtent() returns a wand view required for all other methods
802 % in the Wand View API.
804 % The format of the NewWandViewExtent method is:
806 % WandView *NewWandViewExtent(MagickWand *wand,const ssize_t x,
807 % const ssize_t y,const size_t width,const size_t height)
809 % A description of each parameter follows:
811 % o wand: the magick wand.
813 % o x,y,columns,rows: These values define the perimeter of a extent of
817 WandExport WandView *NewWandViewExtent(MagickWand *wand,const ssize_t x,
818 const ssize_t y,const size_t width,const size_t height)
823 assert(wand != (MagickWand *) NULL);
824 assert(wand->signature == WandSignature);
825 wand_view=(WandView *) AcquireAlignedMemory(1,sizeof(*wand_view));
826 if (wand_view == (WandView *) NULL)
827 ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
828 GetExceptionMessage(errno));
829 (void) ResetMagickMemory(wand_view,0,sizeof(*wand_view));
830 wand_view->id=AcquireWandId();
831 (void) FormatMagickString(wand_view->name,MaxTextExtent,"%s-%.20g",
832 WandViewId,(double) wand_view->id);
833 wand_view->description=ConstantString("WandView");
834 wand_view->view=AcquireCacheView(wand_view->wand->images);
835 wand_view->wand=wand;
836 wand_view->extent.width=width;
837 wand_view->extent.height=height;
838 wand_view->extent.x=x;
839 wand_view->extent.y=y;
840 wand_view->number_threads=GetOpenMPMaximumThreads();
841 wand_view->exception=AcquireExceptionInfo();
842 wand_view->pixel_wands=AcquirePixelsThreadSet(wand_view->extent.width,
843 wand_view->number_threads);
844 if (wand_view->pixel_wands == (PixelWand ***) NULL)
845 ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
846 GetExceptionMessage(errno));
847 wand_view->debug=IsEventLogging();
848 wand_view->signature=WandSignature;
853 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
857 % S e t W a n d V i e w D e s c r i p t i o n %
861 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
863 % SetWandViewDescription() associates a description with an image view.
865 % The format of the SetWandViewDescription method is:
867 % void SetWandViewDescription(WandView *image_view,const char *description)
869 % A description of each parameter follows:
871 % o wand_view: the wand view.
873 % o description: the wand view description.
876 MagickExport void SetWandViewDescription(WandView *wand_view,
877 const char *description)
879 assert(wand_view != (WandView *) NULL);
880 assert(wand_view->signature == WandSignature);
881 wand_view->description=ConstantString(description);
885 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
889 % S e t W a n d V i e w I t e r a t o r %
893 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
895 % SetWandViewIterator() iterates over the wand view in parallel and calls
896 % your set method for each scanline of the view. The pixel extent is
897 % confined to the image canvas-- that is no negative offsets or widths or
898 % heights that exceed the image dimension. The pixels are initiallly
899 % undefined and any settings you make in the callback method are automagically
900 % synced back to your image.
902 % The callback signature is:
904 % MagickBooleanType SetImageViewMethod(ImageView *destination,
905 % const ssize_t y,const int thread_id,void *context)
907 % Use this pragma if the view is not single threaded:
909 % #pragma omp critical
911 % to define a section of code in your callback set method that must be
912 % executed by a single thread at a time.
914 % The format of the SetWandViewIterator method is:
916 % MagickBooleanType SetWandViewIterator(WandView *destination,
917 % SetWandViewMethod set,void *context)
919 % A description of each parameter follows:
921 % o destination: the wand view.
923 % o set: the set callback method.
925 % o context: the user defined context.
928 WandExport MagickBooleanType SetWandViewIterator(WandView *destination,
929 SetWandViewMethod set,void *context)
946 assert(destination != (WandView *) NULL);
947 assert(destination->signature == WandSignature);
948 if (set == (SetWandViewMethod) NULL)
950 destination_image=destination->wand->images;
951 if (SetImageStorageClass(destination_image,DirectClass) == MagickFalse)
955 exception=destination->exception;
956 #if defined(MAGICKCORE_OPENMP_SUPPORT)
957 #pragma omp parallel for schedule(static,1) shared(progress,status)
959 for (y=destination->extent.y; y < (ssize_t) destination->extent.height; y++)
976 if (status == MagickFalse)
978 id=GetOpenMPThreadId();
979 pixels=GetCacheViewAuthenticPixels(destination->view,destination->extent.x,
980 y,destination->extent.width,1,exception);
981 if (pixels == (PixelPacket *) NULL)
983 InheritException(destination->exception,GetCacheViewException(
988 indexes=GetCacheViewAuthenticIndexQueue(destination->view);
989 if (set(destination,y,id,context) == MagickFalse)
991 for (x=0; x < (ssize_t) destination->extent.width; x++)
992 PixelGetQuantumColor(destination->pixel_wands[id][x],pixels+x);
993 if (destination_image->colorspace == CMYKColorspace)
994 for (x=0; x < (ssize_t) destination->extent.width; x++)
995 indexes[x]=PixelGetBlackQuantum(destination->pixel_wands[id][x]);
996 sync=SyncCacheViewAuthenticPixels(destination->view,exception);
997 if (sync == MagickFalse)
999 InheritException(destination->exception,GetCacheViewException(
1000 destination->view));
1003 if (destination_image->progress_monitor != (MagickProgressMonitor) NULL)
1008 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1009 #pragma omp critical (MagickWand_SetWandViewIterator)
1011 proceed=SetImageProgress(destination_image,destination->description,
1012 progress++,destination->extent.height);
1013 if (proceed == MagickFalse)
1021 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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 %
1029 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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
1039 % The callback signature is:
1041 % MagickBooleanType TransferImageViewMethod(const WandView *source,
1042 % WandView *destination,const ssize_t y,const int thread_id,
1045 % Use this pragma if the view is not single threaded:
1047 % #pragma omp critical
1049 % to define a section of code in your callback transfer method that must be
1050 % executed by a single thread at a time.
1052 % The format of the TransferWandViewIterator method is:
1054 % MagickBooleanType TransferWandViewIterator(WandView *source,
1055 % WandView *destination,TransferWandViewMethod transfer,void *context)
1057 % A description of each parameter follows:
1059 % o source: the source wand view.
1061 % o destination: the destination wand view.
1063 % o transfer: the transfer callback method.
1065 % o context: the user defined context.
1068 WandExport MagickBooleanType TransferWandViewIterator(WandView *source,
1069 WandView *destination,TransferWandViewMethod transfer,void *context)
1087 assert(source != (WandView *) NULL);
1088 assert(source->signature == WandSignature);
1089 if (transfer == (TransferWandViewMethod) NULL)
1090 return(MagickFalse);
1091 source_image=source->wand->images;
1092 destination_image=destination->wand->images;
1093 if (SetImageStorageClass(destination_image,DirectClass) == MagickFalse)
1094 return(MagickFalse);
1097 exception=destination->exception;
1098 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1099 #pragma omp parallel for schedule(static,1) shared(progress,status)
1101 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
1109 register const IndexPacket
1112 register const PixelPacket
1115 register IndexPacket
1116 *restrict destination_indexes;
1121 register PixelPacket
1122 *restrict destination_pixels;
1124 if (status == MagickFalse)
1126 id=GetOpenMPThreadId();
1127 pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y,
1128 source->extent.width,1,source->exception);
1129 if (pixels == (const PixelPacket *) NULL)
1134 indexes=GetCacheViewVirtualIndexQueue(source->view);
1135 for (x=0; x < (ssize_t) source->extent.width; x++)
1136 PixelSetQuantumColor(source->pixel_wands[id][x],pixels+x);
1137 if (source_image->colorspace == CMYKColorspace)
1138 for (x=0; x < (ssize_t) source->extent.width; x++)
1139 PixelSetBlackQuantum(source->pixel_wands[id][x],indexes[x]);
1140 if (source_image->storage_class == PseudoClass)
1141 for (x=0; x < (ssize_t) source->extent.width; x++)
1142 PixelSetIndex(source->pixel_wands[id][x],indexes[x]);
1143 destination_pixels=GetCacheViewAuthenticPixels(destination->view,
1144 destination->extent.x,y,destination->extent.width,1,exception);
1145 if (destination_pixels == (PixelPacket *) NULL)
1150 destination_indexes=GetCacheViewAuthenticIndexQueue(destination->view);
1151 for (x=0; x < (ssize_t) destination->extent.width; x++)
1152 PixelSetQuantumColor(destination->pixel_wands[id][x],pixels+x);
1153 if (destination_image->colorspace == CMYKColorspace)
1154 for (x=0; x < (ssize_t) destination->extent.width; x++)
1155 PixelSetBlackQuantum(destination->pixel_wands[id][x],indexes[x]);
1156 if (destination_image->storage_class == PseudoClass)
1157 for (x=0; x < (ssize_t) destination->extent.width; x++)
1158 PixelSetIndex(destination->pixel_wands[id][x],indexes[x]);
1159 if (transfer(source,destination,y,id,context) == MagickFalse)
1161 for (x=0; x < (ssize_t) destination->extent.width; x++)
1162 PixelGetQuantumColor(destination->pixel_wands[id][x],
1163 destination_pixels+x);
1164 if (destination_image->colorspace == CMYKColorspace)
1165 for (x=0; x < (ssize_t) destination->extent.width; x++)
1166 destination_indexes[x]=PixelGetBlackQuantum(
1167 destination->pixel_wands[id][x]);
1168 sync=SyncCacheViewAuthenticPixels(destination->view,exception);
1169 if (sync == MagickFalse)
1171 InheritException(destination->exception,GetCacheViewException(
1175 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
1180 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1181 #pragma omp critical (MagickWand_TransferWandViewIterator)
1183 proceed=SetImageProgress(source_image,source->description,progress++,
1184 source->extent.height);
1185 if (proceed == MagickFalse)
1193 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1197 % U p d a t e W a n d V i e w I t e r a t o r %
1201 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1203 % UpdateWandViewIterator() iterates over the wand view in parallel and calls
1204 % your update method for each scanline of the view. The pixel extent is
1205 % confined to the image canvas-- that is no negative offsets or widths or
1206 % heights that exceed the image dimension are permitted. Updates to pixels
1207 % in your callback are automagically synced back to the image.
1209 % The callback signature is:
1211 % MagickBooleanType UpdateImageViewMethod(WandView *source,const ssize_t y,
1212 % const int thread_id,void *context)
1214 % Use this pragma if the view is not single threaded:
1216 % #pragma omp critical
1218 % to define a section of code in your callback update method that must be
1219 % executed by a single thread at a time.
1221 % The format of the UpdateWandViewIterator method is:
1223 % MagickBooleanType UpdateWandViewIterator(WandView *source,
1224 % UpdateWandViewMethod update,void *context)
1226 % A description of each parameter follows:
1228 % o source: the source wand view.
1230 % o update: the update callback method.
1232 % o context: the user defined context.
1235 WandExport MagickBooleanType UpdateWandViewIterator(WandView *source,
1236 UpdateWandViewMethod update,void *context)
1253 assert(source != (WandView *) NULL);
1254 assert(source->signature == WandSignature);
1255 if (update == (UpdateWandViewMethod) NULL)
1256 return(MagickFalse);
1257 source_image=source->wand->images;
1258 if (SetImageStorageClass(source_image,DirectClass) == MagickFalse)
1259 return(MagickFalse);
1262 exception=source->exception;
1263 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1264 #pragma omp parallel for schedule(static,1) shared(progress,status)
1266 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
1271 register IndexPacket
1277 register PixelPacket
1280 if (status == MagickFalse)
1282 id=GetOpenMPThreadId();
1283 pixels=GetCacheViewAuthenticPixels(source->view,source->extent.x,y,
1284 source->extent.width,1,exception);
1285 if (pixels == (PixelPacket *) NULL)
1287 InheritException(source->exception,GetCacheViewException(
1292 indexes=GetCacheViewAuthenticIndexQueue(source->view);
1293 for (x=0; x < (ssize_t) source->extent.width; x++)
1294 PixelSetQuantumColor(source->pixel_wands[id][x],pixels+x);
1295 if (source_image->colorspace == CMYKColorspace)
1296 for (x=0; x < (ssize_t) source->extent.width; x++)
1297 PixelSetBlackQuantum(source->pixel_wands[id][x],indexes[x]);
1298 if (update(source,y,id,context) == MagickFalse)
1300 for (x=0; x < (ssize_t) source->extent.width; x++)
1301 PixelGetQuantumColor(source->pixel_wands[id][x],pixels+x);
1302 if (source_image->colorspace == CMYKColorspace)
1303 for (x=0; x < (ssize_t) source->extent.width; x++)
1304 indexes[x]=PixelGetBlackQuantum(source->pixel_wands[id][x]);
1305 if (SyncCacheViewAuthenticPixels(source->view,exception) == MagickFalse)
1307 InheritException(source->exception,GetCacheViewException(source->view));
1310 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
1315 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1316 #pragma omp critical (MagickWand_UpdateWandViewIterator)
1318 proceed=SetImageProgress(source_image,source->description,progress++,
1319 source->extent.height);
1320 if (proceed == MagickFalse)