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 *) AcquireMagickMemory(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 ***) RelinquishMagickMemory(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++)
295 id = GetOpenMPThreadId();
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 pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y,
320 source->extent.width,1,source->exception);
321 if (pixels == (const PixelPacket *) NULL)
326 indexes=GetCacheViewVirtualIndexQueue(source->view);
327 for (x=0; x < (ssize_t) source->extent.width; x++)
328 PixelSetQuantumColor(source->pixel_wands[id][x],pixels+x);
329 if (source_image->colorspace == CMYKColorspace)
330 for (x=0; x < (ssize_t) source->extent.width; x++)
331 PixelSetBlackQuantum(source->pixel_wands[id][x],indexes[x]);
332 if (source_image->storage_class == PseudoClass)
333 for (x=0; x < (ssize_t) source->extent.width; x++)
334 PixelSetIndex(source->pixel_wands[id][x],indexes[x]);
335 duplex_pixels=GetCacheViewVirtualPixels(duplex->view,duplex->extent.x,y,
336 duplex->extent.width,1,duplex->exception);
337 if (duplex_pixels == (const PixelPacket *) NULL)
342 duplex_indexes=GetCacheViewVirtualIndexQueue(duplex->view);
343 for (x=0; x < (ssize_t) duplex->extent.width; x++)
344 PixelSetQuantumColor(duplex->pixel_wands[id][x],duplex_pixels+x);
345 if (duplex_image->colorspace == CMYKColorspace)
346 for (x=0; x < (ssize_t) duplex->extent.width; x++)
347 PixelSetBlackQuantum(duplex->pixel_wands[id][x],duplex_indexes[x]);
348 if (duplex_image->storage_class == PseudoClass)
349 for (x=0; x < (ssize_t) duplex->extent.width; x++)
350 PixelSetIndex(duplex->pixel_wands[id][x],duplex_indexes[x]);
351 destination_pixels=GetCacheViewAuthenticPixels(destination->view,
352 destination->extent.x,y,destination->extent.width,1,exception);
353 if (destination_pixels == (PixelPacket *) NULL)
358 destination_indexes=GetCacheViewAuthenticIndexQueue(destination->view);
359 for (x=0; x < (ssize_t) destination->extent.width; x++)
360 PixelSetQuantumColor(destination->pixel_wands[id][x],
361 destination_pixels+x);
362 if (destination_image->colorspace == CMYKColorspace)
363 for (x=0; x < (ssize_t) destination->extent.width; x++)
364 PixelSetBlackQuantum(destination->pixel_wands[id][x],
365 destination_indexes[x]);
366 if (destination_image->storage_class == PseudoClass)
367 for (x=0; x < (ssize_t) destination->extent.width; x++)
368 PixelSetIndex(destination->pixel_wands[id][x],destination_indexes[x]);
369 if (transfer(source,duplex,destination,y,id,context) == MagickFalse)
371 for (x=0; x < (ssize_t) destination->extent.width; x++)
372 PixelGetQuantumColor(destination->pixel_wands[id][x],
373 destination_pixels+x);
374 if (destination_image->colorspace == CMYKColorspace)
375 for (x=0; x < (ssize_t) destination->extent.width; x++)
376 destination_indexes[x]=PixelGetBlackQuantum(
377 destination->pixel_wands[id][x]);
378 sync=SyncCacheViewAuthenticPixels(destination->view,exception);
379 if (sync == MagickFalse)
381 InheritException(destination->exception,GetCacheViewException(
385 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
390 #if defined(MAGICKCORE_OPENMP_SUPPORT)
391 #pragma omp critical (MagickWand_DuplexTransferWandViewIterator)
393 proceed=SetImageProgress(source_image,source->description,progress++,
394 source->extent.height);
395 if (proceed == MagickFalse)
403 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
407 % G e t W a n d V i e w E x c e p t i o n %
411 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
413 % GetWandViewException() returns the severity, reason, and description of any
414 % error that occurs when utilizing a wand view.
416 % The format of the GetWandViewException method is:
418 % char *GetWandViewException(const PixelWand *wand_view,
419 % ExceptionType *severity)
421 % A description of each parameter follows:
423 % o wand_view: the pixel wand_view.
425 % o severity: the severity of the error is returned here.
428 WandExport char *GetWandViewException(const WandView *wand_view,
429 ExceptionType *severity)
434 assert(wand_view != (const WandView *) NULL);
435 assert(wand_view->signature == WandSignature);
436 if (wand_view->debug != MagickFalse)
437 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",wand_view->name);
438 assert(severity != (ExceptionType *) NULL);
439 *severity=wand_view->exception->severity;
440 description=(char *) AcquireQuantumMemory(2UL*MaxTextExtent,
441 sizeof(*description));
442 if (description == (char *) NULL)
443 ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
446 if (wand_view->exception->reason != (char *) NULL)
447 (void) CopyMagickString(description,GetLocaleExceptionMessage(
448 wand_view->exception->severity,wand_view->exception->reason),
450 if (wand_view->exception->description != (char *) NULL)
452 (void) ConcatenateMagickString(description," (",MaxTextExtent);
453 (void) ConcatenateMagickString(description,GetLocaleExceptionMessage(
454 wand_view->exception->severity,wand_view->exception->description),
456 (void) ConcatenateMagickString(description,")",MaxTextExtent);
462 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
466 % G e t W a n d V i e w E x t e n t %
470 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
472 % GetWandViewExtent() returns the wand view extent.
474 % The format of the GetWandViewExtent method is:
476 % RectangleInfo GetWandViewExtent(const WandView *wand_view)
478 % A description of each parameter follows:
480 % o wand_view: the wand view.
483 WandExport RectangleInfo GetWandViewExtent(const WandView *wand_view)
485 assert(wand_view != (WandView *) NULL);
486 assert(wand_view->signature == WandSignature);
487 return(wand_view->extent);
491 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
495 % G e t W a n d V i e w I t e r a t o r %
499 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
501 % GetWandViewIterator() iterates over the wand view in parallel and calls
502 % your get method for each scanline of the view. The pixel extent is
503 % not confined to the image canvas-- that is you can include negative offsets
504 % or widths or heights that exceed the image dimension. Any updates to
505 % the pixels in your callback are ignored.
507 % The callback signature is:
509 % MagickBooleanType GetImageViewMethod(const WandView *source,
510 % const ssize_t y,const int thread_id,void *context)
512 % Use this pragma if the view is not single threaded:
514 % #pragma omp critical
516 % to define a section of code in your callback get method that must be
517 % executed by a single thread at a time.
519 % The format of the GetWandViewIterator method is:
521 % MagickBooleanType GetWandViewIterator(WandView *source,
522 % GetWandViewMethod get,void *context)
524 % A description of each parameter follows:
526 % o source: the source wand view.
528 % o get: the get callback method.
530 % o context: the user defined context.
533 WandExport MagickBooleanType GetWandViewIterator(WandView *source,
534 GetWandViewMethod get,void *context)
548 assert(source != (WandView *) NULL);
549 assert(source->signature == WandSignature);
550 if (get == (GetWandViewMethod) NULL)
552 source_image=source->wand->images;
555 #if defined(MAGICKCORE_OPENMP_SUPPORT)
556 #pragma omp parallel for schedule(static,1) shared(progress,status)
558 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
561 id = GetOpenMPThreadId();
563 register const IndexPacket
566 register const PixelPacket
572 if (status == MagickFalse)
574 pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y,
575 source->extent.width,1,source->exception);
576 if (pixels == (const PixelPacket *) NULL)
581 indexes=GetCacheViewVirtualIndexQueue(source->view);
582 for (x=0; x < (ssize_t) source->extent.width; x++)
583 PixelSetQuantumColor(source->pixel_wands[id][x],pixels+x);
584 if (source_image->colorspace == CMYKColorspace)
585 for (x=0; x < (ssize_t) source->extent.width; x++)
586 PixelSetBlackQuantum(source->pixel_wands[id][x],indexes[x]);
587 if (source_image->storage_class == PseudoClass)
588 for (x=0; x < (ssize_t) source->extent.width; x++)
589 PixelSetIndex(source->pixel_wands[id][x],indexes[x]);
590 if (get(source,y,id,context) == MagickFalse)
592 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
597 #if defined(MAGICKCORE_OPENMP_SUPPORT)
598 #pragma omp critical (MagickWand_GetWandViewIterator)
600 proceed=SetImageProgress(source_image,source->description,progress++,
601 source->extent.height);
602 if (proceed == MagickFalse)
610 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
614 % G e t W a n d V i e w P i x e l s %
618 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
620 % GetWandViewPixels() returns the wand view pixel_wands.
622 % The format of the GetWandViewPixels method is:
624 % PixelWand *GetWandViewPixels(const WandView *wand_view)
626 % A description of each parameter follows:
628 % o wand_view: the wand view.
631 WandExport PixelWand **GetWandViewPixels(const WandView *wand_view)
634 id = GetOpenMPThreadId();
636 assert(wand_view != (WandView *) NULL);
637 assert(wand_view->signature == WandSignature);
638 return(wand_view->pixel_wands[id]);
642 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
646 % G e t W a n d V i e w W a n d %
650 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
652 % GetWandViewWand() returns the magick wand associated with the wand view.
654 % The format of the GetWandViewWand method is:
656 % MagickWand *GetWandViewWand(const WandView *wand_view)
658 % A description of each parameter follows:
660 % o wand_view: the wand view.
663 WandExport MagickWand *GetWandViewWand(const WandView *wand_view)
665 assert(wand_view != (WandView *) NULL);
666 assert(wand_view->signature == WandSignature);
667 return(wand_view->wand);
671 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
675 % I s W a n d V i e w %
679 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
681 % IsWandView() returns MagickTrue if the the parameter is verified as a wand
684 % The format of the IsWandView method is:
686 % MagickBooleanType IsWandView(const WandView *wand_view)
688 % A description of each parameter follows:
690 % o wand_view: the wand view.
693 WandExport MagickBooleanType IsWandView(const WandView *wand_view)
698 if (wand_view == (const WandView *) NULL)
700 if (wand_view->signature != WandSignature)
702 length=strlen(WandViewId);
703 if (LocaleNCompare(wand_view->name,WandViewId,length) != 0)
709 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
713 % N e w W a n d V i e w %
717 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
719 % NewWandView() returns a wand view required for all other methods in the
722 % The format of the NewWandView method is:
724 % WandView *NewWandView(MagickWand *wand)
726 % A description of each parameter follows:
732 static PixelWand ***AcquirePixelsThreadSet(const size_t number_wands,
733 const size_t number_threads)
741 pixel_wands=(PixelWand ***) AcquireQuantumMemory(number_threads,
742 sizeof(*pixel_wands));
743 if (pixel_wands == (PixelWand ***) NULL)
744 return((PixelWand ***) NULL);
745 (void) ResetMagickMemory(pixel_wands,0,number_threads*sizeof(*pixel_wands));
746 for (i=0; i < (ssize_t) number_threads; i++)
748 pixel_wands[i]=NewPixelWands(number_wands);
749 if (pixel_wands[i] == (PixelWand **) NULL)
750 return(DestroyPixelsThreadSet(pixel_wands,number_wands,number_threads));
755 WandExport WandView *NewWandView(MagickWand *wand)
760 assert(wand != (MagickWand *) NULL);
761 assert(wand->signature == WandSignature);
762 wand_view=(WandView *) AcquireMagickMemory(sizeof(*wand_view));
763 if (wand_view == (WandView *) NULL)
764 ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
765 GetExceptionMessage(errno));
766 (void) ResetMagickMemory(wand_view,0,sizeof(*wand_view));
767 wand_view->id=AcquireWandId();
768 (void) FormatMagickString(wand_view->name,MaxTextExtent,"%s-%.20g",
769 WandViewId,(double) wand_view->id);
770 wand_view->description=ConstantString("WandView");
771 wand_view->wand=wand;
772 wand_view->view=AcquireCacheView(wand_view->wand->images);
773 wand_view->extent.width=wand->images->columns;
774 wand_view->extent.height=wand->images->rows;
775 wand_view->number_threads=GetOpenMPMaximumThreads();
776 wand_view->pixel_wands=AcquirePixelsThreadSet(wand_view->extent.width,
777 wand_view->number_threads);
778 wand_view->exception=AcquireExceptionInfo();
779 if (wand_view->pixel_wands == (PixelWand ***) NULL)
780 ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
781 GetExceptionMessage(errno));
782 wand_view->debug=IsEventLogging();
783 wand_view->signature=WandSignature;
788 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
792 % N e w W a n d V i e w E x t e n t %
796 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
798 % NewWandViewExtent() returns a wand view required for all other methods
799 % in the Wand View API.
801 % The format of the NewWandViewExtent method is:
803 % WandView *NewWandViewExtent(MagickWand *wand,const ssize_t x,
804 % const ssize_t y,const size_t width,const size_t height)
806 % A description of each parameter follows:
808 % o wand: the magick wand.
810 % o x,y,columns,rows: These values define the perimeter of a extent of
814 WandExport WandView *NewWandViewExtent(MagickWand *wand,const ssize_t x,
815 const ssize_t y,const size_t width,const size_t height)
820 assert(wand != (MagickWand *) NULL);
821 assert(wand->signature == WandSignature);
822 wand_view=(WandView *) AcquireMagickMemory(sizeof(*wand_view));
823 if (wand_view == (WandView *) NULL)
824 ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
825 GetExceptionMessage(errno));
826 (void) ResetMagickMemory(wand_view,0,sizeof(*wand_view));
827 wand_view->id=AcquireWandId();
828 (void) FormatMagickString(wand_view->name,MaxTextExtent,"%s-%.20g",
829 WandViewId,(double) wand_view->id);
830 wand_view->description=ConstantString("WandView");
831 wand_view->view=AcquireCacheView(wand_view->wand->images);
832 wand_view->wand=wand;
833 wand_view->extent.width=width;
834 wand_view->extent.height=height;
835 wand_view->extent.x=x;
836 wand_view->extent.y=y;
837 wand_view->number_threads=GetOpenMPMaximumThreads();
838 wand_view->exception=AcquireExceptionInfo();
839 wand_view->pixel_wands=AcquirePixelsThreadSet(wand_view->extent.width,
840 wand_view->number_threads);
841 if (wand_view->pixel_wands == (PixelWand ***) NULL)
842 ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
843 GetExceptionMessage(errno));
844 wand_view->debug=IsEventLogging();
845 wand_view->signature=WandSignature;
850 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
854 % S e t W a n d V i e w D e s c r i p t i o n %
858 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
860 % SetWandViewDescription() associates a description with an image view.
862 % The format of the SetWandViewDescription method is:
864 % void SetWandViewDescription(WandView *image_view,const char *description)
866 % A description of each parameter follows:
868 % o wand_view: the wand view.
870 % o description: the wand view description.
873 MagickExport void SetWandViewDescription(WandView *wand_view,
874 const char *description)
876 assert(wand_view != (WandView *) NULL);
877 assert(wand_view->signature == WandSignature);
878 wand_view->description=ConstantString(description);
882 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
886 % S e t W a n d V i e w I t e r a t o r %
890 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
892 % SetWandViewIterator() iterates over the wand view in parallel and calls
893 % your set method for each scanline of the view. The pixel extent is
894 % confined to the image canvas-- that is no negative offsets or widths or
895 % heights that exceed the image dimension. The pixels are initiallly
896 % undefined and any settings you make in the callback method are automagically
897 % synced back to your image.
899 % The callback signature is:
901 % MagickBooleanType SetImageViewMethod(ImageView *destination,
902 % const ssize_t y,const int thread_id,void *context)
904 % Use this pragma if the view is not single threaded:
906 % #pragma omp critical
908 % to define a section of code in your callback set method that must be
909 % executed by a single thread at a time.
911 % The format of the SetWandViewIterator method is:
913 % MagickBooleanType SetWandViewIterator(WandView *destination,
914 % SetWandViewMethod set,void *context)
916 % A description of each parameter follows:
918 % o destination: the wand view.
920 % o set: the set callback method.
922 % o context: the user defined context.
925 WandExport MagickBooleanType SetWandViewIterator(WandView *destination,
926 SetWandViewMethod set,void *context)
943 assert(destination != (WandView *) NULL);
944 assert(destination->signature == WandSignature);
945 if (set == (SetWandViewMethod) NULL)
947 destination_image=destination->wand->images;
948 if (SetImageStorageClass(destination_image,DirectClass) == MagickFalse)
952 exception=destination->exception;
953 #if defined(MAGICKCORE_OPENMP_SUPPORT)
954 #pragma omp parallel for schedule(static,1) shared(progress,status)
956 for (y=destination->extent.y; y < (ssize_t) destination->extent.height; y++)
959 id = GetOpenMPThreadId();
973 if (status == MagickFalse)
975 pixels=GetCacheViewAuthenticPixels(destination->view,destination->extent.x,
976 y,destination->extent.width,1,exception);
977 if (pixels == (PixelPacket *) NULL)
979 InheritException(destination->exception,GetCacheViewException(
984 indexes=GetCacheViewAuthenticIndexQueue(destination->view);
985 if (set(destination,y,id,context) == MagickFalse)
987 for (x=0; x < (ssize_t) destination->extent.width; x++)
988 PixelGetQuantumColor(destination->pixel_wands[id][x],pixels+x);
989 if (destination_image->colorspace == CMYKColorspace)
990 for (x=0; x < (ssize_t) destination->extent.width; x++)
991 indexes[x]=PixelGetBlackQuantum(destination->pixel_wands[id][x]);
992 sync=SyncCacheViewAuthenticPixels(destination->view,exception);
993 if (sync == MagickFalse)
995 InheritException(destination->exception,GetCacheViewException(
999 if (destination_image->progress_monitor != (MagickProgressMonitor) NULL)
1004 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1005 #pragma omp critical (MagickWand_SetWandViewIterator)
1007 proceed=SetImageProgress(destination_image,destination->description,
1008 progress++,destination->extent.height);
1009 if (proceed == MagickFalse)
1017 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1021 % T r a n s f e r W a n d V i e w I t e r a t o r %
1025 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1027 % TransferWandViewIterator() iterates over two wand views in parallel and
1028 % calls your transfer method for each scanline of the view. The source pixel
1029 % extent is not confined to the image canvas-- that is you can include
1030 % negative offsets or widths or heights that exceed the image dimension.
1031 % However, the destination wand view is confined to the image canvas-- that
1032 % is no negative offsets or widths or heights that exceed the image dimension
1035 % The callback signature is:
1037 % MagickBooleanType TransferImageViewMethod(const WandView *source,
1038 % WandView *destination,const ssize_t y,const int thread_id,
1041 % Use this pragma if the view is not single threaded:
1043 % #pragma omp critical
1045 % to define a section of code in your callback transfer method that must be
1046 % executed by a single thread at a time.
1048 % The format of the TransferWandViewIterator method is:
1050 % MagickBooleanType TransferWandViewIterator(WandView *source,
1051 % WandView *destination,TransferWandViewMethod transfer,void *context)
1053 % A description of each parameter follows:
1055 % o source: the source wand view.
1057 % o destination: the destination wand view.
1059 % o transfer: the transfer callback method.
1061 % o context: the user defined context.
1064 WandExport MagickBooleanType TransferWandViewIterator(WandView *source,
1065 WandView *destination,TransferWandViewMethod transfer,void *context)
1083 assert(source != (WandView *) NULL);
1084 assert(source->signature == WandSignature);
1085 if (transfer == (TransferWandViewMethod) NULL)
1086 return(MagickFalse);
1087 source_image=source->wand->images;
1088 destination_image=destination->wand->images;
1089 if (SetImageStorageClass(destination_image,DirectClass) == MagickFalse)
1090 return(MagickFalse);
1093 exception=destination->exception;
1094 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1095 #pragma omp parallel for schedule(static,1) shared(progress,status)
1097 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
1100 id = GetOpenMPThreadId();
1105 register const IndexPacket
1108 register const PixelPacket
1111 register IndexPacket
1112 *restrict destination_indexes;
1117 register PixelPacket
1118 *restrict destination_pixels;
1120 if (status == MagickFalse)
1122 pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y,
1123 source->extent.width,1,source->exception);
1124 if (pixels == (const PixelPacket *) NULL)
1129 indexes=GetCacheViewVirtualIndexQueue(source->view);
1130 for (x=0; x < (ssize_t) source->extent.width; x++)
1131 PixelSetQuantumColor(source->pixel_wands[id][x],pixels+x);
1132 if (source_image->colorspace == CMYKColorspace)
1133 for (x=0; x < (ssize_t) source->extent.width; x++)
1134 PixelSetBlackQuantum(source->pixel_wands[id][x],indexes[x]);
1135 if (source_image->storage_class == PseudoClass)
1136 for (x=0; x < (ssize_t) source->extent.width; x++)
1137 PixelSetIndex(source->pixel_wands[id][x],indexes[x]);
1138 destination_pixels=GetCacheViewAuthenticPixels(destination->view,
1139 destination->extent.x,y,destination->extent.width,1,exception);
1140 if (destination_pixels == (PixelPacket *) NULL)
1145 destination_indexes=GetCacheViewAuthenticIndexQueue(destination->view);
1146 for (x=0; x < (ssize_t) destination->extent.width; x++)
1147 PixelSetQuantumColor(destination->pixel_wands[id][x],pixels+x);
1148 if (destination_image->colorspace == CMYKColorspace)
1149 for (x=0; x < (ssize_t) destination->extent.width; x++)
1150 PixelSetBlackQuantum(destination->pixel_wands[id][x],indexes[x]);
1151 if (destination_image->storage_class == PseudoClass)
1152 for (x=0; x < (ssize_t) destination->extent.width; x++)
1153 PixelSetIndex(destination->pixel_wands[id][x],indexes[x]);
1154 if (transfer(source,destination,y,id,context) == MagickFalse)
1156 for (x=0; x < (ssize_t) destination->extent.width; x++)
1157 PixelGetQuantumColor(destination->pixel_wands[id][x],
1158 destination_pixels+x);
1159 if (destination_image->colorspace == CMYKColorspace)
1160 for (x=0; x < (ssize_t) destination->extent.width; x++)
1161 destination_indexes[x]=PixelGetBlackQuantum(
1162 destination->pixel_wands[id][x]);
1163 sync=SyncCacheViewAuthenticPixels(destination->view,exception);
1164 if (sync == MagickFalse)
1166 InheritException(destination->exception,GetCacheViewException(
1170 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
1175 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1176 #pragma omp critical (MagickWand_TransferWandViewIterator)
1178 proceed=SetImageProgress(source_image,source->description,progress++,
1179 source->extent.height);
1180 if (proceed == MagickFalse)
1188 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1192 % U p d a t e W a n d V i e w I t e r a t o r %
1196 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1198 % UpdateWandViewIterator() iterates over the wand view in parallel and calls
1199 % your update method for each scanline of the view. The pixel extent is
1200 % confined to the image canvas-- that is no negative offsets or widths or
1201 % heights that exceed the image dimension are permitted. Updates to pixels
1202 % in your callback are automagically synced back to the image.
1204 % The callback signature is:
1206 % MagickBooleanType UpdateImageViewMethod(WandView *source,const ssize_t y,
1207 % const int thread_id,void *context)
1209 % Use this pragma if the view is not single threaded:
1211 % #pragma omp critical
1213 % to define a section of code in your callback update method that must be
1214 % executed by a single thread at a time.
1216 % The format of the UpdateWandViewIterator method is:
1218 % MagickBooleanType UpdateWandViewIterator(WandView *source,
1219 % UpdateWandViewMethod update,void *context)
1221 % A description of each parameter follows:
1223 % o source: the source wand view.
1225 % o update: the update callback method.
1227 % o context: the user defined context.
1230 WandExport MagickBooleanType UpdateWandViewIterator(WandView *source,
1231 UpdateWandViewMethod update,void *context)
1248 assert(source != (WandView *) NULL);
1249 assert(source->signature == WandSignature);
1250 if (update == (UpdateWandViewMethod) NULL)
1251 return(MagickFalse);
1252 source_image=source->wand->images;
1253 if (SetImageStorageClass(source_image,DirectClass) == MagickFalse)
1254 return(MagickFalse);
1257 exception=source->exception;
1258 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1259 #pragma omp parallel for schedule(static,1) shared(progress,status)
1261 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
1264 id = GetOpenMPThreadId();
1266 register IndexPacket
1272 register PixelPacket
1275 if (status == MagickFalse)
1277 pixels=GetCacheViewAuthenticPixels(source->view,source->extent.x,y,
1278 source->extent.width,1,exception);
1279 if (pixels == (PixelPacket *) NULL)
1281 InheritException(source->exception,GetCacheViewException(
1286 indexes=GetCacheViewAuthenticIndexQueue(source->view);
1287 for (x=0; x < (ssize_t) source->extent.width; x++)
1288 PixelSetQuantumColor(source->pixel_wands[id][x],pixels+x);
1289 if (source_image->colorspace == CMYKColorspace)
1290 for (x=0; x < (ssize_t) source->extent.width; x++)
1291 PixelSetBlackQuantum(source->pixel_wands[id][x],indexes[x]);
1292 if (update(source,y,id,context) == MagickFalse)
1294 for (x=0; x < (ssize_t) source->extent.width; x++)
1295 PixelGetQuantumColor(source->pixel_wands[id][x],pixels+x);
1296 if (source_image->colorspace == CMYKColorspace)
1297 for (x=0; x < (ssize_t) source->extent.width; x++)
1298 indexes[x]=PixelGetBlackQuantum(source->pixel_wands[id][x]);
1299 if (SyncCacheViewAuthenticPixels(source->view,exception) == MagickFalse)
1301 InheritException(source->exception,GetCacheViewException(source->view));
1304 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
1309 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1310 #pragma omp critical (MagickWand_UpdateWandViewIterator)
1312 proceed=SetImageProgress(source_image,source->description,progress++,
1313 source->extent.height);
1314 if (proceed == MagickFalse)