]> granicus.if.org Git - imagemagick/blob - wand/wand-view.c
(no commit message)
[imagemagick] / wand / wand-view.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                        W   W   AAA   N   N  DDDD                            %
6 %                        W   W  A   A  NN  N  D   D                           %
7 %                        W W W  AAAAA  N N N  D   D                           %
8 %                        WW WW  A   A  N  NN  D   D                           %
9 %                        W   W  A   A  N   N  DDDD                            %
10 %                                                                             %
11 %                        V   V  IIIII  EEEEE  W   W                           %
12 %                        V   V    I    E      W   W                           %
13 %                        V   V    I    EEE    W W W                           %
14 %                         V V     I    E      WW WW                           %
15 %                          V    IIIII  EEEEE  W   W                           %
16 %                                                                             %
17 %                                                                             %
18 %                        MagickWand Wand View Methods                         %
19 %                                                                             %
20 %                              Software Design                                %
21 %                                John Cristy                                  %
22 %                                March 2003                                   %
23 %                                                                             %
24 %                                                                             %
25 %  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
26 %  dedicated to making software imaging solutions freely available.           %
27 %                                                                             %
28 %  You may not use this file except in compliance with the License.  You may  %
29 %  obtain a copy of the License at                                            %
30 %                                                                             %
31 %    http://www.imagemagick.org/script/license.php                            %
32 %                                                                             %
33 %  Unless required by applicable law or agreed to in writing, software        %
34 %  distributed under the License is distributed on an "AS IS" BASIS,          %
35 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
36 %  See the License for the specific language governing permissions and        %
37 %  limitations under the License.                                             %
38 %                                                                             %
39 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
40 %
41 %
42 %
43 */
44 \f
45 /*
46   Include declarations.
47 */
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"
54 /*
55  Define declarations.
56 */
57 #define WandViewId  "WandView"
58 \f
59 /*
60   Typedef declarations.
61 */
62 struct _WandView
63 {
64   size_t
65     id;
66
67   char
68     name[MaxTextExtent],
69     *description;
70
71   RectangleInfo
72     extent;
73
74   MagickWand
75     *wand;
76
77   CacheView
78     *view;
79
80   size_t
81     number_threads;
82
83   PixelWand
84     ***pixel_wands;
85
86   ExceptionInfo
87     *exception;
88
89   MagickBooleanType
90     debug;
91
92   size_t
93     signature;
94 };
95 \f
96 /*
97 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
98 %                                                                             %
99 %                                                                             %
100 %                                                                             %
101 %   C l o n e W a n d V i e w                                                 %
102 %                                                                             %
103 %                                                                             %
104 %                                                                             %
105 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
106 %
107 %  CloneWandView() makes a copy of the specified wand view.
108 %
109 %  The format of the CloneWandView method is:
110 %
111 %      WandView *CloneWandView(const WandView *wand_view)
112 %
113 %  A description of each parameter follows:
114 %
115 %    o wand_view: the wand view.
116 %
117 */
118 WandExport WandView *CloneWandView(const WandView *wand_view)
119 {
120   WandView
121     *clone_view;
122
123   register ssize_t
124     i;
125
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",
133       wand_view->name);
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;
151   return(clone_view);
152 }
153 \f
154 /*
155 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
156 %                                                                             %
157 %                                                                             %
158 %                                                                             %
159 %   D e s t r o y W a n d V i e w                                             %
160 %                                                                             %
161 %                                                                             %
162 %                                                                             %
163 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
164 %
165 %  DestroyWandView() deallocates memory associated with a wand view.
166 %
167 %  The format of the DestroyWandView method is:
168 %
169 %      WandView *DestroyWandView(WandView *wand_view)
170 %
171 %  A description of each parameter follows:
172 %
173 %    o wand_view: the wand view.
174 %
175 */
176
177 static PixelWand ***DestroyPixelsThreadSet(PixelWand ***pixel_wands,
178   const size_t number_wands,const size_t number_threads)
179 {
180   register ssize_t
181     i;
182
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);
188   return(pixel_wands);
189 }
190
191 WandExport WandView *DestroyWandView(WandView *wand_view)
192 {
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);
202   return(wand_view);
203 }
204 \f
205 /*
206 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
207 %                                                                             %
208 %                                                                             %
209 %                                                                             %
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               %
211 %                                                                             %
212 %                                                                             %
213 %                                                                             %
214 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
215 %
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.
223 %
224 %  The callback signature is:
225 %
226 %      MagickBooleanType DuplexTransferImageViewMethod(const WandView *source,
227 %        const WandView *duplex,WandView *destination,const ssize_t y,
228 %        const int thread_id,void *context)
229 %
230 %  Use this pragma if the view is not single threaded:
231 %
232 %    #pragma omp critical
233 %
234 %  to define a section of code in your callback transfer method that must be
235 %  executed by a single thread at a time.
236 %
237 %  The format of the DuplexTransferWandViewIterator method is:
238 %
239 %      MagickBooleanType DuplexTransferWandViewIterator(WandView *source,
240 %        WandView *duplex,WandView *destination,
241 %        DuplexTransferWandViewMethod transfer,void *context)
242 %
243 %  A description of each parameter follows:
244 %
245 %    o source: the source wand view.
246 %
247 %    o duplex: the duplex wand view.
248 %
249 %    o destination: the destination wand view.
250 %
251 %    o transfer: the transfer callback method.
252 %
253 %    o context: the user defined context.
254 %
255 */
256 WandExport MagickBooleanType DuplexTransferWandViewIterator(WandView *source,
257   WandView *duplex,WandView *destination,DuplexTransferWandViewMethod transfer,
258   void *context)
259 {
260   ExceptionInfo
261     *exception;
262
263   Image
264     *destination_image,
265     *duplex_image,
266     *source_image;
267
268   MagickBooleanType
269     status;
270
271   MagickOffsetType
272     progress;
273
274   ssize_t
275     y;
276
277   assert(source != (WandView *) NULL);
278   assert(source->signature == WandSignature);
279   if (transfer == (DuplexTransferWandViewMethod) NULL)
280     return(MagickFalse);
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)
285     return(MagickFalse);
286   status=MagickTrue;
287   progress=0;
288   exception=destination->exception;
289 #if defined(MAGICKCORE_OPENMP_SUPPORT)
290   #pragma omp parallel for schedule(static,1) shared(progress,status) num_threads(source->number_threads)
291 #endif
292   for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
293   {
294     const int
295       id = GetOpenMPThreadId();
296
297     MagickBooleanType
298       sync;
299
300     register const IndexPacket
301       *restrict duplex_indexes,
302       *restrict indexes;
303
304     register const PixelPacket
305       *restrict duplex_pixels,
306       *restrict pixels;
307
308     register IndexPacket
309       *restrict destination_indexes;
310
311     register ssize_t
312       x;
313
314     register PixelPacket
315       *restrict destination_pixels;
316
317     if (status == MagickFalse)
318       continue;
319     pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y,
320       source->extent.width,1,source->exception);
321     if (pixels == (const PixelPacket *) NULL)
322       {
323         status=MagickFalse;
324         continue;
325       }
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)
338       {
339         status=MagickFalse;
340         continue;
341       }
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)
354       {
355         status=MagickFalse;
356         continue;
357       }
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)
370       status=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)
380       {
381         InheritException(destination->exception,GetCacheViewException(
382           source->view));
383         status=MagickFalse;
384       }
385     if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
386       {
387         MagickBooleanType
388           proceed;
389
390 #if defined(MAGICKCORE_OPENMP_SUPPORT)
391   #pragma omp critical (MagickWand_DuplexTransferWandViewIterator)
392 #endif
393         proceed=SetImageProgress(source_image,source->description,progress++,
394           source->extent.height);
395         if (proceed == MagickFalse)
396           status=MagickFalse;
397       }
398   }
399   return(status);
400 }
401 \f
402 /*
403 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
404 %                                                                             %
405 %                                                                             %
406 %                                                                             %
407 %   G e t W a n d V i e w E x c e p t i o n                                   %
408 %                                                                             %
409 %                                                                             %
410 %                                                                             %
411 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
412 %
413 %  GetWandViewException() returns the severity, reason, and description of any
414 %  error that occurs when utilizing a wand view.
415 %
416 %  The format of the GetWandViewException method is:
417 %
418 %      char *GetWandViewException(const PixelWand *wand_view,
419 %        ExceptionType *severity)
420 %
421 %  A description of each parameter follows:
422 %
423 %    o wand_view: the pixel wand_view.
424 %
425 %    o severity: the severity of the error is returned here.
426 %
427 */
428 WandExport char *GetWandViewException(const WandView *wand_view,
429   ExceptionType *severity)
430 {
431   char
432     *description;
433
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",
444       wand_view->name);
445   *description='\0';
446   if (wand_view->exception->reason != (char *) NULL)
447     (void) CopyMagickString(description,GetLocaleExceptionMessage(
448       wand_view->exception->severity,wand_view->exception->reason),
449         MaxTextExtent);
450   if (wand_view->exception->description != (char *) NULL)
451     {
452       (void) ConcatenateMagickString(description," (",MaxTextExtent);
453       (void) ConcatenateMagickString(description,GetLocaleExceptionMessage(
454         wand_view->exception->severity,wand_view->exception->description),
455         MaxTextExtent);
456       (void) ConcatenateMagickString(description,")",MaxTextExtent);
457     }
458   return(description);
459 }
460 \f
461 /*
462 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
463 %                                                                             %
464 %                                                                             %
465 %                                                                             %
466 %   G e t W a n d V i e w E x t e n t                                         %
467 %                                                                             %
468 %                                                                             %
469 %                                                                             %
470 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
471 %
472 %  GetWandViewExtent() returns the wand view extent.
473 %
474 %  The format of the GetWandViewExtent method is:
475 %
476 %      RectangleInfo GetWandViewExtent(const WandView *wand_view)
477 %
478 %  A description of each parameter follows:
479 %
480 %    o wand_view: the wand view.
481 %
482 */
483 WandExport RectangleInfo GetWandViewExtent(const WandView *wand_view)
484 {
485   assert(wand_view != (WandView *) NULL);
486   assert(wand_view->signature == WandSignature);
487   return(wand_view->extent);
488 }
489 \f
490 /*
491 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
492 %                                                                             %
493 %                                                                             %
494 %                                                                             %
495 %   G e t W a n d V i e w I t e r a t o r                                     %
496 %                                                                             %
497 %                                                                             %
498 %                                                                             %
499 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
500 %
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.
506 %
507 %  The callback signature is:
508 %
509 %      MagickBooleanType GetImageViewMethod(const WandView *source,
510 %        const ssize_t y,const int thread_id,void *context)
511 %
512 %  Use this pragma if the view is not single threaded:
513 %
514 %    #pragma omp critical
515 %
516 %  to define a section of code in your callback get method that must be
517 %  executed by a single thread at a time.
518 %
519 %  The format of the GetWandViewIterator method is:
520 %
521 %      MagickBooleanType GetWandViewIterator(WandView *source,
522 %        GetWandViewMethod get,void *context)
523 %
524 %  A description of each parameter follows:
525 %
526 %    o source: the source wand view.
527 %
528 %    o get: the get callback method.
529 %
530 %    o context: the user defined context.
531 %
532 */
533 WandExport MagickBooleanType GetWandViewIterator(WandView *source,
534   GetWandViewMethod get,void *context)
535 {
536   Image
537     *source_image;
538
539   MagickBooleanType
540     status;
541
542   MagickOffsetType
543     progress;
544
545   ssize_t
546     y;
547
548   assert(source != (WandView *) NULL);
549   assert(source->signature == WandSignature);
550   if (get == (GetWandViewMethod) NULL)
551     return(MagickFalse);
552   source_image=source->wand->images;
553   status=MagickTrue;
554   progress=0;
555 #if defined(MAGICKCORE_OPENMP_SUPPORT)
556   #pragma omp parallel for schedule(static,1) shared(progress,status) num_threads(source->number_threads)
557 #endif
558   for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
559   {
560     const int
561       id = GetOpenMPThreadId();
562
563     register const IndexPacket
564       *indexes;
565
566     register const PixelPacket
567       *pixels;
568
569     register ssize_t
570       x;
571
572     if (status == MagickFalse)
573       continue;
574     pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y,
575       source->extent.width,1,source->exception);
576     if (pixels == (const PixelPacket *) NULL)
577       {
578         status=MagickFalse;
579         continue;
580       }
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)
591       status=MagickFalse;
592     if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
593       {
594         MagickBooleanType
595           proceed;
596
597 #if defined(MAGICKCORE_OPENMP_SUPPORT)
598   #pragma omp critical (MagickWand_GetWandViewIterator)
599 #endif
600         proceed=SetImageProgress(source_image,source->description,progress++,
601           source->extent.height);
602         if (proceed == MagickFalse)
603           status=MagickFalse;
604       }
605   }
606   return(status);
607 }
608 \f
609 /*
610 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
611 %                                                                             %
612 %                                                                             %
613 %                                                                             %
614 %   G e t W a n d V i e w P i x e l s                                         %
615 %                                                                             %
616 %                                                                             %
617 %                                                                             %
618 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
619 %
620 %  GetWandViewPixels() returns the wand view pixel_wands.
621 %
622 %  The format of the GetWandViewPixels method is:
623 %
624 %      PixelWand *GetWandViewPixels(const WandView *wand_view)
625 %
626 %  A description of each parameter follows:
627 %
628 %    o wand_view: the wand view.
629 %
630 */
631 WandExport PixelWand **GetWandViewPixels(const WandView *wand_view)
632 {
633   const int
634     id = GetOpenMPThreadId();
635
636   assert(wand_view != (WandView *) NULL);
637   assert(wand_view->signature == WandSignature);
638   return(wand_view->pixel_wands[id]);
639 }
640 \f
641 /*
642 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
643 %                                                                             %
644 %                                                                             %
645 %                                                                             %
646 %   G e t W a n d V i e w W a n d                                             %
647 %                                                                             %
648 %                                                                             %
649 %                                                                             %
650 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
651 %
652 %  GetWandViewWand() returns the magick wand associated with the wand view.
653 %
654 %  The format of the GetWandViewWand method is:
655 %
656 %      MagickWand *GetWandViewWand(const WandView *wand_view)
657 %
658 %  A description of each parameter follows:
659 %
660 %    o wand_view: the wand view.
661 %
662 */
663 WandExport MagickWand *GetWandViewWand(const WandView *wand_view)
664 {
665   assert(wand_view != (WandView *) NULL);
666   assert(wand_view->signature == WandSignature);
667   return(wand_view->wand);
668 }
669 \f
670 /*
671 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
672 %                                                                             %
673 %                                                                             %
674 %                                                                             %
675 %   I s W a n d V i e w                                                       %
676 %                                                                             %
677 %                                                                             %
678 %                                                                             %
679 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
680 %
681 %  IsWandView() returns MagickTrue if the the parameter is verified as a wand
682 %  view object.
683 %
684 %  The format of the IsWandView method is:
685 %
686 %      MagickBooleanType IsWandView(const WandView *wand_view)
687 %
688 %  A description of each parameter follows:
689 %
690 %    o wand_view: the wand view.
691 %
692 */
693 WandExport MagickBooleanType IsWandView(const WandView *wand_view)
694 {
695   size_t
696     length;
697
698   if (wand_view == (const WandView *) NULL)
699     return(MagickFalse);
700   if (wand_view->signature != WandSignature)
701     return(MagickFalse);
702   length=strlen(WandViewId);
703   if (LocaleNCompare(wand_view->name,WandViewId,length) != 0)
704     return(MagickFalse);
705   return(MagickTrue);
706 }
707 \f
708 /*
709 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
710 %                                                                             %
711 %                                                                             %
712 %                                                                             %
713 %   N e w W a n d V i e w                                                     %
714 %                                                                             %
715 %                                                                             %
716 %                                                                             %
717 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
718 %
719 %  NewWandView() returns a wand view required for all other methods in the
720 %  Wand View API.
721 %
722 %  The format of the NewWandView method is:
723 %
724 %      WandView *NewWandView(MagickWand *wand)
725 %
726 %  A description of each parameter follows:
727 %
728 %    o wand: the wand.
729 %
730 */
731
732 static PixelWand ***AcquirePixelsThreadSet(const size_t number_wands,
733   const size_t number_threads)
734 {
735   PixelWand
736     ***pixel_wands;
737
738   register ssize_t
739     i;
740
741   pixel_wands=(PixelWand ***) AcquireQuantumMemory(number_threads,
742     sizeof(*pixel_wands));
743   if (pixel_wands == (PixelWand ***) NULL)
744     return((PixelWand ***) NULL);
745   (void) ResetMagickMemory(pixel_wands,0,number_threads*sizeof(*pixel_wands));
746   for (i=0; i < (ssize_t) number_threads; i++)
747   {
748     pixel_wands[i]=NewPixelWands(number_wands);
749     if (pixel_wands[i] == (PixelWand **) NULL)
750       return(DestroyPixelsThreadSet(pixel_wands,number_wands,number_threads));
751   }
752   return(pixel_wands);
753 }
754
755 WandExport WandView *NewWandView(MagickWand *wand)
756 {
757   WandView
758     *wand_view;
759
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;
784   return(wand_view);
785 }
786 \f
787 /*
788 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
789 %                                                                             %
790 %                                                                             %
791 %                                                                             %
792 %   N e w W a n d V i e w E x t e n t                                         %
793 %                                                                             %
794 %                                                                             %
795 %                                                                             %
796 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
797 %
798 %  NewWandViewExtent() returns a wand view required for all other methods
799 %  in the Wand View API.
800 %
801 %  The format of the NewWandViewExtent method is:
802 %
803 %      WandView *NewWandViewExtent(MagickWand *wand,const ssize_t x,
804 %        const ssize_t y,const size_t width,const size_t height)
805 %
806 %  A description of each parameter follows:
807 %
808 %    o wand: the magick wand.
809 %
810 %    o x,y,columns,rows:  These values define the perimeter of a extent of
811 %      pixel_wands view.
812 %
813 */
814 WandExport WandView *NewWandViewExtent(MagickWand *wand,const ssize_t x,
815   const ssize_t y,const size_t width,const size_t height)
816 {
817   WandView
818     *wand_view;
819
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;
846   return(wand_view);
847 }
848 \f
849 /*
850 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
851 %                                                                             %
852 %                                                                             %
853 %                                                                             %
854 %   S e t W a n d V i e w D e s c r i p t i o n                               %
855 %                                                                             %
856 %                                                                             %
857 %                                                                             %
858 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
859 %
860 %  SetWandViewDescription() associates a description with an image view.
861 %
862 %  The format of the SetWandViewDescription method is:
863 %
864 %      void SetWandViewDescription(WandView *image_view,const char *description)
865 %
866 %  A description of each parameter follows:
867 %
868 %    o wand_view: the wand view.
869 %
870 %    o description: the wand view description.
871 %
872 */
873 MagickExport void SetWandViewDescription(WandView *wand_view,
874   const char *description)
875 {
876   assert(wand_view != (WandView *) NULL);
877   assert(wand_view->signature == WandSignature);
878   wand_view->description=ConstantString(description);
879 }
880 \f
881 /*
882 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
883 %                                                                             %
884 %                                                                             %
885 %                                                                             %
886 %   S e t W a n d V i e w I t e r a t o r                                     %
887 %                                                                             %
888 %                                                                             %
889 %                                                                             %
890 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
891 %
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.
898 %
899 %  The callback signature is:
900 %
901 %      MagickBooleanType SetImageViewMethod(ImageView *destination,
902 %        const ssize_t y,const int thread_id,void *context)
903 %
904 %  Use this pragma if the view is not single threaded:
905 %
906 %    #pragma omp critical
907 %
908 %  to define a section of code in your callback set method that must be
909 %  executed by a single thread at a time.
910 %
911 %  The format of the SetWandViewIterator method is:
912 %
913 %      MagickBooleanType SetWandViewIterator(WandView *destination,
914 %        SetWandViewMethod set,void *context)
915 %
916 %  A description of each parameter follows:
917 %
918 %    o destination: the wand view.
919 %
920 %    o set: the set callback method.
921 %
922 %    o context: the user defined context.
923 %
924 */
925 WandExport MagickBooleanType SetWandViewIterator(WandView *destination,
926   SetWandViewMethod set,void *context)
927 {
928   ExceptionInfo
929     *exception;
930
931   Image
932     *destination_image;
933
934   MagickBooleanType
935     status;
936
937   MagickOffsetType
938     progress;
939
940   ssize_t
941     y;
942
943   assert(destination != (WandView *) NULL);
944   assert(destination->signature == WandSignature);
945   if (set == (SetWandViewMethod) NULL)
946     return(MagickFalse);
947   destination_image=destination->wand->images;
948   if (SetImageStorageClass(destination_image,DirectClass) == MagickFalse)
949     return(MagickFalse);
950   status=MagickTrue;
951   progress=0;
952   exception=destination->exception;
953 #if defined(MAGICKCORE_OPENMP_SUPPORT)
954   #pragma omp parallel for schedule(static,1) shared(progress,status) num_threads(destination->number_threads)
955 #endif
956   for (y=destination->extent.y; y < (ssize_t) destination->extent.height; y++)
957   {
958     const int
959       id = GetOpenMPThreadId();
960
961     MagickBooleanType
962       sync;
963
964     register IndexPacket
965       *restrict indexes;
966
967     register ssize_t
968       x;
969
970     register PixelPacket
971       *restrict pixels;
972
973     if (status == MagickFalse)
974       continue;
975     pixels=GetCacheViewAuthenticPixels(destination->view,destination->extent.x,
976       y,destination->extent.width,1,exception);
977     if (pixels == (PixelPacket *) NULL)
978       {
979         InheritException(destination->exception,GetCacheViewException(
980           destination->view));
981         status=MagickFalse;
982         continue;
983       }
984     indexes=GetCacheViewAuthenticIndexQueue(destination->view);
985     if (set(destination,y,id,context) == MagickFalse)
986       status=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)
994       {
995         InheritException(destination->exception,GetCacheViewException(
996           destination->view));
997         status=MagickFalse;
998       }
999     if (destination_image->progress_monitor != (MagickProgressMonitor) NULL)
1000       {
1001         MagickBooleanType
1002           proceed;
1003
1004 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1005   #pragma omp critical (MagickWand_SetWandViewIterator)
1006 #endif
1007         proceed=SetImageProgress(destination_image,destination->description,
1008           progress++,destination->extent.height);
1009         if (proceed == MagickFalse)
1010           status=MagickFalse;
1011       }
1012   }
1013   return(status);
1014 }
1015 \f
1016 /*
1017 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1018 %                                                                             %
1019 %                                                                             %
1020 %                                                                             %
1021 %   S e t W a n d V i e w T h r e a d s                                       %
1022 %                                                                             %
1023 %                                                                             %
1024 %                                                                             %
1025 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1026 %
1027 %  SetWandViewThreads() sets the number of threads in a thread team.
1028 %
1029 %  The format of the SetWandViewDescription method is:
1030 %
1031 %      void SetWandViewThreads(WandView *image_view,
1032 %        const size_t number_threads)
1033 %
1034 %  A description of each parameter follows:
1035 %
1036 %    o image_view: the image view.
1037 %
1038 %    o number_threads: the number of threads in a thread team.
1039 %
1040 */
1041 MagickExport void SetWandViewThreads(WandView *image_view,
1042   const size_t number_threads)
1043 {
1044   assert(image_view != (WandView *) NULL);
1045   assert(image_view->signature == MagickSignature);
1046   image_view->number_threads=number_threads;
1047   if (number_threads > GetOpenMPMaximumThreads())
1048     image_view->number_threads=GetOpenMPMaximumThreads();
1049 }
1050 \f
1051 /*
1052 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1053 %                                                                             %
1054 %                                                                             %
1055 %                                                                             %
1056 %   T r a n s f e r W a n d V i e w I t e r a t o r                           %
1057 %                                                                             %
1058 %                                                                             %
1059 %                                                                             %
1060 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1061 %
1062 %  TransferWandViewIterator() iterates over two wand views in parallel and
1063 %  calls your transfer method for each scanline of the view.  The source pixel
1064 %  extent is not confined to the image canvas-- that is you can include
1065 %  negative offsets or widths or heights that exceed the image dimension.
1066 %  However, the destination wand view is confined to the image canvas-- that
1067 %  is no negative offsets or widths or heights that exceed the image dimension
1068 %  are permitted.
1069 %
1070 %  The callback signature is:
1071 %
1072 %      MagickBooleanType TransferImageViewMethod(const WandView *source,
1073 %        WandView *destination,const ssize_t y,const int thread_id,
1074 %        void *context)
1075 %
1076 %  Use this pragma if the view is not single threaded:
1077 %
1078 %    #pragma omp critical
1079 %
1080 %  to define a section of code in your callback transfer method that must be
1081 %  executed by a single thread at a time.
1082 %
1083 %  The format of the TransferWandViewIterator method is:
1084 %
1085 %      MagickBooleanType TransferWandViewIterator(WandView *source,
1086 %        WandView *destination,TransferWandViewMethod transfer,void *context)
1087 %
1088 %  A description of each parameter follows:
1089 %
1090 %    o source: the source wand view.
1091 %
1092 %    o destination: the destination wand view.
1093 %
1094 %    o transfer: the transfer callback method.
1095 %
1096 %    o context: the user defined context.
1097 %
1098 */
1099 WandExport MagickBooleanType TransferWandViewIterator(WandView *source,
1100   WandView *destination,TransferWandViewMethod transfer,void *context)
1101 {
1102   ExceptionInfo
1103     *exception;
1104
1105   Image
1106     *destination_image,
1107     *source_image;
1108
1109   MagickBooleanType
1110     status;
1111
1112   MagickOffsetType
1113     progress;
1114
1115   ssize_t
1116     y;
1117
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);
1126   status=MagickTrue;
1127   progress=0;
1128   exception=destination->exception;
1129 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1130   #pragma omp parallel for schedule(static,1) shared(progress,status) num_threads(source->number_threads)
1131 #endif
1132   for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
1133   {
1134     const int
1135       id = GetOpenMPThreadId();
1136
1137     MagickBooleanType
1138       sync;
1139
1140     register const IndexPacket
1141       *restrict indexes;
1142
1143     register const PixelPacket
1144       *restrict pixels;
1145
1146     register IndexPacket
1147       *restrict destination_indexes;
1148
1149     register ssize_t
1150       x;
1151
1152     register PixelPacket
1153       *restrict destination_pixels;
1154
1155     if (status == MagickFalse)
1156       continue;
1157     pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y,
1158       source->extent.width,1,source->exception);
1159     if (pixels == (const PixelPacket *) NULL)
1160       {
1161         status=MagickFalse;
1162         continue;
1163       }
1164     indexes=GetCacheViewVirtualIndexQueue(source->view);
1165     for (x=0; x < (ssize_t) source->extent.width; x++)
1166       PixelSetQuantumColor(source->pixel_wands[id][x],pixels+x);
1167     if (source_image->colorspace == CMYKColorspace)
1168       for (x=0; x < (ssize_t) source->extent.width; x++)
1169         PixelSetBlackQuantum(source->pixel_wands[id][x],indexes[x]);
1170     if (source_image->storage_class == PseudoClass)
1171       for (x=0; x < (ssize_t) source->extent.width; x++)
1172         PixelSetIndex(source->pixel_wands[id][x],indexes[x]);
1173     destination_pixels=GetCacheViewAuthenticPixels(destination->view,
1174       destination->extent.x,y,destination->extent.width,1,exception);
1175     if (destination_pixels == (PixelPacket *) NULL)
1176       {
1177         status=MagickFalse;
1178         continue;
1179       }
1180     destination_indexes=GetCacheViewAuthenticIndexQueue(destination->view);
1181     for (x=0; x < (ssize_t) destination->extent.width; x++)
1182       PixelSetQuantumColor(destination->pixel_wands[id][x],pixels+x);
1183     if (destination_image->colorspace == CMYKColorspace)
1184       for (x=0; x < (ssize_t) destination->extent.width; x++)
1185         PixelSetBlackQuantum(destination->pixel_wands[id][x],indexes[x]);
1186     if (destination_image->storage_class == PseudoClass)
1187       for (x=0; x < (ssize_t) destination->extent.width; x++)
1188         PixelSetIndex(destination->pixel_wands[id][x],indexes[x]);
1189     if (transfer(source,destination,y,id,context) == MagickFalse)
1190       status=MagickFalse;
1191     for (x=0; x < (ssize_t) destination->extent.width; x++)
1192       PixelGetQuantumColor(destination->pixel_wands[id][x],
1193         destination_pixels+x);
1194     if (destination_image->colorspace == CMYKColorspace)
1195       for (x=0; x < (ssize_t) destination->extent.width; x++)
1196         destination_indexes[x]=PixelGetBlackQuantum(
1197           destination->pixel_wands[id][x]);
1198     sync=SyncCacheViewAuthenticPixels(destination->view,exception);
1199     if (sync == MagickFalse)
1200       {
1201         InheritException(destination->exception,GetCacheViewException(
1202           source->view));
1203         status=MagickFalse;
1204       }
1205     if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
1206       {
1207         MagickBooleanType
1208           proceed;
1209
1210 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1211   #pragma omp critical (MagickWand_TransferWandViewIterator)
1212 #endif
1213         proceed=SetImageProgress(source_image,source->description,progress++,
1214           source->extent.height);
1215         if (proceed == MagickFalse)
1216           status=MagickFalse;
1217       }
1218   }
1219   return(status);
1220 }
1221 \f
1222 /*
1223 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1224 %                                                                             %
1225 %                                                                             %
1226 %                                                                             %
1227 %   U p d a t e W a n d V i e w I t e r a t o r                               %
1228 %                                                                             %
1229 %                                                                             %
1230 %                                                                             %
1231 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1232 %
1233 %  UpdateWandViewIterator() iterates over the wand view in parallel and calls
1234 %  your update method for each scanline of the view.  The pixel extent is
1235 %  confined to the image canvas-- that is no negative offsets or widths or
1236 %  heights that exceed the image dimension are permitted.  Updates to pixels
1237 %  in your callback are automagically synced back to the image.
1238 %
1239 %  The callback signature is:
1240 %
1241 %      MagickBooleanType UpdateImageViewMethod(WandView *source,const ssize_t y,
1242 %        const int thread_id,void *context)
1243 %
1244 %  Use this pragma if the view is not single threaded:
1245 %
1246 %    #pragma omp critical
1247 %
1248 %  to define a section of code in your callback update method that must be
1249 %  executed by a single thread at a time.
1250 %
1251 %  The format of the UpdateWandViewIterator method is:
1252 %
1253 %      MagickBooleanType UpdateWandViewIterator(WandView *source,
1254 %        UpdateWandViewMethod update,void *context)
1255 %
1256 %  A description of each parameter follows:
1257 %
1258 %    o source: the source wand view.
1259 %
1260 %    o update: the update callback method.
1261 %
1262 %    o context: the user defined context.
1263 %
1264 */
1265 WandExport MagickBooleanType UpdateWandViewIterator(WandView *source,
1266   UpdateWandViewMethod update,void *context)
1267 {
1268   ExceptionInfo
1269     *exception;
1270
1271   Image
1272     *source_image;
1273
1274   MagickBooleanType
1275     status;
1276
1277   MagickOffsetType
1278     progress;
1279
1280   ssize_t
1281     y;
1282
1283   assert(source != (WandView *) NULL);
1284   assert(source->signature == WandSignature);
1285   if (update == (UpdateWandViewMethod) NULL)
1286     return(MagickFalse);
1287   source_image=source->wand->images;
1288   if (SetImageStorageClass(source_image,DirectClass) == MagickFalse)
1289     return(MagickFalse);
1290   status=MagickTrue;
1291   progress=0;
1292   exception=source->exception;
1293 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1294   #pragma omp parallel for schedule(static,1) shared(progress,status) num_threads(source->number_threads)
1295 #endif
1296   for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
1297   {
1298     const int
1299       id = GetOpenMPThreadId();
1300
1301     register IndexPacket
1302       *restrict indexes;
1303
1304     register ssize_t
1305       x;
1306
1307     register PixelPacket
1308       *restrict pixels;
1309
1310     if (status == MagickFalse)
1311       continue;
1312     pixels=GetCacheViewAuthenticPixels(source->view,source->extent.x,y,
1313       source->extent.width,1,exception);
1314     if (pixels == (PixelPacket *) NULL)
1315       {
1316         InheritException(source->exception,GetCacheViewException(
1317           source->view));
1318         status=MagickFalse;
1319         continue;
1320       }
1321     indexes=GetCacheViewAuthenticIndexQueue(source->view);
1322     for (x=0; x < (ssize_t) source->extent.width; x++)
1323       PixelSetQuantumColor(source->pixel_wands[id][x],pixels+x);
1324     if (source_image->colorspace == CMYKColorspace)
1325       for (x=0; x < (ssize_t) source->extent.width; x++)
1326         PixelSetBlackQuantum(source->pixel_wands[id][x],indexes[x]);
1327     if (update(source,y,id,context) == MagickFalse)
1328       status=MagickFalse;
1329     for (x=0; x < (ssize_t) source->extent.width; x++)
1330       PixelGetQuantumColor(source->pixel_wands[id][x],pixels+x);
1331     if (source_image->colorspace == CMYKColorspace)
1332       for (x=0; x < (ssize_t) source->extent.width; x++)
1333         indexes[x]=PixelGetBlackQuantum(source->pixel_wands[id][x]);
1334     if (SyncCacheViewAuthenticPixels(source->view,exception) == MagickFalse)
1335       {
1336         InheritException(source->exception,GetCacheViewException(source->view));
1337         status=MagickFalse;
1338       }
1339     if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
1340       {
1341         MagickBooleanType
1342           proceed;
1343
1344 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1345   #pragma omp critical (MagickWand_UpdateWandViewIterator)
1346 #endif
1347         proceed=SetImageProgress(source_image,source->description,progress++,
1348           source->extent.height);
1349         if (proceed == MagickFalse)
1350           status=MagickFalse;
1351       }
1352   }
1353   return(status);
1354 }