]> 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-2010 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
70   ExceptionInfo
71     *exception;
72
73   MagickWand
74     *wand;
75
76   CacheView
77     *view;
78
79   RectangleInfo
80     region;
81
82   size_t
83     number_threads;
84
85   PixelWand
86     ***pixel_wands;
87
88   MagickBooleanType
89     debug;
90
91   size_t
92     signature;
93 };
94 \f
95 /*
96 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
97 %                                                                             %
98 %                                                                             %
99 %                                                                             %
100 %   C l o n e W a n d V i e w                                                 %
101 %                                                                             %
102 %                                                                             %
103 %                                                                             %
104 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
105 %
106 %  CloneWandView() makes a copy of the specified wand view.
107 %
108 %  The format of the CloneWandView method is:
109 %
110 %      WandView *CloneWandView(const WandView *wand_view)
111 %
112 %  A description of each parameter follows:
113 %
114 %    o wand_view: the wand view.
115 %
116 */
117 WandExport WandView *CloneWandView(const WandView *wand_view)
118 {
119   WandView
120     *clone_view;
121
122   register ssize_t
123     i;
124
125   assert(wand_view != (WandView *) NULL);
126   assert(wand_view->signature == WandSignature);
127   if (wand_view->debug != MagickFalse)
128     (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",wand_view->name);
129   clone_view=(WandView *) AcquireAlignedMemory(1,sizeof(*clone_view));
130   if (clone_view == (WandView *) NULL)
131     ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
132       wand_view->name);
133   (void) ResetMagickMemory(clone_view,0,sizeof(*clone_view));
134   clone_view->id=AcquireWandId();
135   (void) FormatMagickString(clone_view->name,MaxTextExtent,"%s-%.20g",
136     WandViewId,(double) clone_view->id);
137   clone_view->exception=AcquireExceptionInfo();
138   InheritException(clone_view->exception,wand_view->exception);
139   clone_view->view=CloneCacheView(wand_view->view);
140   clone_view->region=wand_view->region;
141   clone_view->number_threads=wand_view->number_threads;
142   for (i=0; i < (ssize_t) wand_view->number_threads; i++)
143     clone_view->pixel_wands[i]=ClonePixelWands((const PixelWand **)
144       wand_view->pixel_wands[i],wand_view->region.width);
145   clone_view->debug=wand_view->debug;
146   if (clone_view->debug != MagickFalse)
147     (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",clone_view->name);
148   clone_view->signature=WandSignature;
149   return(clone_view);
150 }
151 \f
152 /*
153 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
154 %                                                                             %
155 %                                                                             %
156 %                                                                             %
157 %   D e s t r o y W a n d V i e w                                             %
158 %                                                                             %
159 %                                                                             %
160 %                                                                             %
161 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
162 %
163 %  DestroyWandView() deallocates memory associated with a wand view.
164 %
165 %  The format of the DestroyWandView method is:
166 %
167 %      WandView *DestroyWandView(WandView *wand_view)
168 %
169 %  A description of each parameter follows:
170 %
171 %    o wand_view: the wand view.
172 %
173 */
174
175 static PixelWand ***DestroyPixelsThreadSet(PixelWand ***pixel_wands,
176   const size_t number_wands,const size_t number_threads)
177 {
178   register ssize_t
179     i;
180
181   assert(pixel_wands != (PixelWand ***) NULL);
182   for (i=0; i < (ssize_t) number_threads; i++)
183     if (pixel_wands[i] != (PixelWand **) NULL)
184       pixel_wands[i]=DestroyPixelWands(pixel_wands[i],number_wands);
185   pixel_wands=(PixelWand ***) RelinquishAlignedMemory(pixel_wands);
186   return(pixel_wands);
187 }
188
189 WandExport WandView *DestroyWandView(WandView *wand_view)
190 {
191   assert(wand_view != (WandView *) NULL);
192   assert(wand_view->signature == WandSignature);
193   wand_view->pixel_wands=DestroyPixelsThreadSet(wand_view->pixel_wands,
194     wand_view->region.width,wand_view->number_threads);
195   wand_view->view=DestroyCacheView(wand_view->view);
196   wand_view->exception=DestroyExceptionInfo(wand_view->exception);
197   wand_view->signature=(~WandSignature);
198   RelinquishWandId(wand_view->id);
199   wand_view=(WandView *) RelinquishMagickMemory(wand_view);
200   return(wand_view);
201 }
202 \f
203 /*
204 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
205 %                                                                             %
206 %                                                                             %
207 %                                                                             %
208 %   D u p l e x T r a n s f e r W a n d V i e w I t e r a t o r               %
209 %                                                                             %
210 %                                                                             %
211 %                                                                             %
212 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
213 %
214 %  DuplexTransferWandViewIterator() iterates over three wand views in
215 %  parallel and calls your transfer method for each scanline of the view.  The
216 %  source and duplex pixel region is not confined to the image canvas-- that is
217 %  you can include negative offsets or widths or heights that exceed the image
218 %  dimension.  However, the destination wand view is confined to the image
219 %  canvas-- that is no negative offsets or widths or heights that exceed the
220 %  image dimension are permitted.
221 %
222 %  Use this pragma if the view is not single threaded:
223 %
224 %    #pragma omp critical
225 %
226 %  to define a section of code in your callback transfer method that must be
227 %  executed by a single thread at a time.
228 %
229 %  The format of the DuplexTransferWandViewIterator method is:
230 %
231 %      MagickBooleanType DuplexTransferWandViewIterator(WandView *source,
232 %        WandView *duplex,WandView *destination,
233 %        DuplexTransferWandViewMethod transfer,void *context)
234 %
235 %  A description of each parameter follows:
236 %
237 %    o source: the source wand view.
238 %
239 %    o duplex: the duplex wand view.
240 %
241 %    o destination: the destination wand view.
242 %
243 %    o transfer: the transfer callback method.
244 %
245 %    o context: the user defined context.
246 %
247 */
248 WandExport MagickBooleanType DuplexTransferWandViewIterator(WandView *source,
249   WandView *duplex,WandView *destination,DuplexTransferWandViewMethod transfer,
250   void *context)
251 {
252 #define DuplexTransferWandViewTag  "WandView/DuplexTransfer"
253
254   ExceptionInfo
255     *exception;
256
257   Image
258     *destination_image,
259     *duplex_image,
260     *source_image;
261
262   MagickBooleanType
263     status;
264
265   MagickOffsetType
266     progress;
267
268   ssize_t
269     y;
270
271   assert(source != (WandView *) NULL);
272   assert(source->signature == WandSignature);
273   if (transfer == (DuplexTransferWandViewMethod) NULL)
274     return(MagickFalse);
275   source_image=source->wand->images;
276   duplex_image=duplex->wand->images;
277   destination_image=destination->wand->images;
278   if (SetImageStorageClass(destination_image,DirectClass) == MagickFalse)
279     return(MagickFalse);
280   status=MagickTrue;
281   progress=0;
282   exception=destination->exception;
283 #if defined(MAGICKCORE_OPENMP_SUPPORT)
284   #pragma omp parallel for schedule(static,1) shared(progress,status)
285 #endif
286   for (y=source->region.y; y < (ssize_t) source->region.height; y++)
287   {
288     MagickBooleanType
289       sync;
290
291     register const IndexPacket
292       *restrict duplex_indexes,
293       *restrict indexes;
294
295     register const PixelPacket
296       *restrict duplex_pixels,
297       *restrict pixels;
298
299     register IndexPacket
300       *restrict destination_indexes;
301
302     register ssize_t
303       id,
304       x;
305
306     register PixelPacket
307       *restrict destination_pixels;
308
309     if (status == MagickFalse)
310       continue;
311     id=GetOpenMPThreadId();
312     pixels=GetCacheViewVirtualPixels(source->view,source->region.x,y,
313       source->region.width,1,source->exception);
314     if (pixels == (const PixelPacket *) NULL)
315       {
316         status=MagickFalse;
317         continue;
318       }
319     indexes=GetCacheViewVirtualIndexQueue(source->view);
320     for (x=0; x < (ssize_t) source->region.width; x++)
321       PixelSetQuantumColor(source->pixel_wands[id][x],pixels+x);
322     if (source_image->colorspace == CMYKColorspace)
323       for (x=0; x < (ssize_t) source->region.width; x++)
324         PixelSetBlackQuantum(source->pixel_wands[id][x],indexes[x]);
325     if (source_image->storage_class == PseudoClass)
326       for (x=0; x < (ssize_t) source->region.width; x++)
327         PixelSetIndex(source->pixel_wands[id][x],indexes[x]);
328     duplex_pixels=GetCacheViewVirtualPixels(duplex->view,duplex->region.x,y,
329       duplex->region.width,1,duplex->exception);
330     if (duplex_pixels == (const PixelPacket *) NULL)
331       {
332         status=MagickFalse;
333         continue;
334       }
335     duplex_indexes=GetCacheViewVirtualIndexQueue(duplex->view);
336     for (x=0; x < (ssize_t) duplex->region.width; x++)
337       PixelSetQuantumColor(duplex->pixel_wands[id][x],duplex_pixels+x);
338     if (duplex_image->colorspace == CMYKColorspace)
339       for (x=0; x < (ssize_t) duplex->region.width; x++)
340         PixelSetBlackQuantum(duplex->pixel_wands[id][x],duplex_indexes[x]);
341     if (duplex_image->storage_class == PseudoClass)
342       for (x=0; x < (ssize_t) duplex->region.width; x++)
343         PixelSetIndex(duplex->pixel_wands[id][x],duplex_indexes[x]);
344     destination_pixels=GetCacheViewAuthenticPixels(destination->view,
345       destination->region.x,y,destination->region.width,1,exception);
346     if (destination_pixels == (PixelPacket *) NULL)
347       {
348         status=MagickFalse;
349         continue;
350       }
351     destination_indexes=GetCacheViewAuthenticIndexQueue(destination->view);
352     for (x=0; x < (ssize_t) destination->region.width; x++)
353       PixelSetQuantumColor(destination->pixel_wands[id][x],
354         destination_pixels+x);
355     if (destination_image->colorspace == CMYKColorspace)
356       for (x=0; x < (ssize_t) destination->region.width; x++)
357         PixelSetBlackQuantum(destination->pixel_wands[id][x],
358           destination_indexes[x]);
359     if (destination_image->storage_class == PseudoClass)
360       for (x=0; x < (ssize_t) destination->region.width; x++)
361         PixelSetIndex(destination->pixel_wands[id][x],destination_indexes[x]);
362     if (transfer(source,duplex,destination,context) == MagickFalse)
363       status=MagickFalse;
364     for (x=0; x < (ssize_t) destination->region.width; x++)
365       PixelGetQuantumColor(destination->pixel_wands[id][x],
366         destination_pixels+x);
367     if (destination_image->colorspace == CMYKColorspace)
368       for (x=0; x < (ssize_t) destination->region.width; x++)
369         destination_indexes[x]=PixelGetBlackQuantum(
370           destination->pixel_wands[id][x]);
371     sync=SyncCacheViewAuthenticPixels(destination->view,exception);
372     if (sync == MagickFalse)
373       {
374         InheritException(destination->exception,GetCacheViewException(
375           source->view));
376         status=MagickFalse;
377       }
378     if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
379       {
380         MagickBooleanType
381           proceed;
382
383 #if defined(MAGICKCORE_OPENMP_SUPPORT)
384   #pragma omp critical (MagickWand_DuplexTransferWandViewIterator)
385 #endif
386         proceed=SetImageProgress(source_image,DuplexTransferWandViewTag,
387           progress++,source->region.height);
388         if (proceed == MagickFalse)
389           status=MagickFalse;
390       }
391   }
392   return(status);
393 }
394 \f
395 /*
396 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
397 %                                                                             %
398 %                                                                             %
399 %                                                                             %
400 %   G e t W a n d V i e w E x c e p t i o n                                   %
401 %                                                                             %
402 %                                                                             %
403 %                                                                             %
404 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
405 %
406 %  GetWandViewException() returns the severity, reason, and description of any
407 %  error that occurs when utilizing a wand view.
408 %
409 %  The format of the GetWandViewException method is:
410 %
411 %      char *GetWandViewException(const PixelWand *wand_view,
412 %        ExceptionType *severity)
413 %
414 %  A description of each parameter follows:
415 %
416 %    o wand_view: the pixel wand_view.
417 %
418 %    o severity: the severity of the error is returned here.
419 %
420 */
421 WandExport char *GetWandViewException(const WandView *wand_view,
422   ExceptionType *severity)
423 {
424   char
425     *description;
426
427   assert(wand_view != (const WandView *) NULL);
428   assert(wand_view->signature == WandSignature);
429   if (wand_view->debug != MagickFalse)
430     (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",wand_view->name);
431   assert(severity != (ExceptionType *) NULL);
432   *severity=wand_view->exception->severity;
433   description=(char *) AcquireQuantumMemory(2UL*MaxTextExtent,
434     sizeof(*description));
435   if (description == (char *) NULL)
436     ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
437       wand_view->name);
438   *description='\0';
439   if (wand_view->exception->reason != (char *) NULL)
440     (void) CopyMagickString(description,GetLocaleExceptionMessage(
441       wand_view->exception->severity,wand_view->exception->reason),
442         MaxTextExtent);
443   if (wand_view->exception->description != (char *) NULL)
444     {
445       (void) ConcatenateMagickString(description," (",MaxTextExtent);
446       (void) ConcatenateMagickString(description,GetLocaleExceptionMessage(
447         wand_view->exception->severity,wand_view->exception->description),
448         MaxTextExtent);
449       (void) ConcatenateMagickString(description,")",MaxTextExtent);
450     }
451   return(description);
452 }
453 \f
454 /*
455 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
456 %                                                                             %
457 %                                                                             %
458 %                                                                             %
459 %   G e t W a n d V i e w H e i g h t                                         %
460 %                                                                             %
461 %                                                                             %
462 %                                                                             %
463 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
464 %
465 %  GetWandViewHeight() returns the wand view height.
466 %
467 %  The format of the GetWandViewHeight method is:
468 %
469 %      size_t GetWandViewHeight(const WandView *wand_view)
470 %
471 %  A description of each parameter follows:
472 %
473 %    o wand_view: the wand view.
474 %
475 */
476 WandExport size_t GetWandViewHeight(const WandView *wand_view)
477 {
478   assert(wand_view != (WandView *) NULL);
479   assert(wand_view->signature == WandSignature);
480   return(wand_view->region.height);
481 }
482 \f
483 /*
484 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
485 %                                                                             %
486 %                                                                             %
487 %                                                                             %
488 %   G e t W a n d V i e w I t e r a t o r                                     %
489 %                                                                             %
490 %                                                                             %
491 %                                                                             %
492 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
493 %
494 %  GetWandViewIterator() iterates over the wand view in parallel and calls
495 %  your get method for each scanline of the view.  The pixel region is
496 %  not confined to the image canvas-- that is you can include negative offsets
497 %  or widths or heights that exceed the image dimension.  Any updates to
498 %  the pixels in your callback are ignored.
499 %
500 %  Use this pragma if the view is not single threaded:
501 %
502 %    #pragma omp critical
503 %
504 %  to define a section of code in your callback get method that must be
505 %  executed by a single thread at a time.
506 %
507 %  The format of the GetWandViewIterator method is:
508 %
509 %      MagickBooleanType GetWandViewIterator(WandView *source,
510 %        GetWandViewMethod get,void *context)
511 %
512 %  A description of each parameter follows:
513 %
514 %    o source: the source wand view.
515 %
516 %    o get: the get callback method.
517 %
518 %    o context: the user defined context.
519 %
520 */
521 WandExport MagickBooleanType GetWandViewIterator(WandView *source,
522   GetWandViewMethod get,void *context)
523 {
524 #define GetWandViewTag  "WandView/Get"
525
526   Image
527     *source_image;
528
529   MagickBooleanType
530     status;
531
532   MagickOffsetType
533     progress;
534
535   ssize_t
536     y;
537
538   assert(source != (WandView *) NULL);
539   assert(source->signature == WandSignature);
540   if (get == (GetWandViewMethod) NULL)
541     return(MagickFalse);
542   source_image=source->wand->images;
543   status=MagickTrue;
544   progress=0;
545 #if defined(MAGICKCORE_OPENMP_SUPPORT)
546   #pragma omp parallel for schedule(static,1) shared(progress,status)
547 #endif
548   for (y=source->region.y; y < (ssize_t) source->region.height; y++)
549   {
550     register const IndexPacket
551       *indexes;
552
553     register const PixelPacket
554       *pixels;
555
556     register ssize_t
557       id,
558       x;
559
560     if (status == MagickFalse)
561       continue;
562     id=GetOpenMPThreadId();
563     pixels=GetCacheViewVirtualPixels(source->view,source->region.x,y,
564       source->region.width,1,source->exception);
565     if (pixels == (const PixelPacket *) NULL)
566       {
567         status=MagickFalse;
568         continue;
569       }
570     indexes=GetCacheViewVirtualIndexQueue(source->view);
571     for (x=0; x < (ssize_t) source->region.width; x++)
572       PixelSetQuantumColor(source->pixel_wands[id][x],pixels+x);
573     if (source_image->colorspace == CMYKColorspace)
574       for (x=0; x < (ssize_t) source->region.width; x++)
575         PixelSetBlackQuantum(source->pixel_wands[id][x],indexes[x]);
576     if (source_image->storage_class == PseudoClass)
577       for (x=0; x < (ssize_t) source->region.width; x++)
578         PixelSetIndex(source->pixel_wands[id][x],indexes[x]);
579     if (get(source,context) == MagickFalse)
580       status=MagickFalse;
581     if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
582       {
583         MagickBooleanType
584           proceed;
585
586 #if defined(MAGICKCORE_OPENMP_SUPPORT)
587   #pragma omp critical (MagickWand_GetWandViewIterator)
588 #endif
589         proceed=SetImageProgress(source_image,GetWandViewTag,progress++,
590           source->region.height);
591         if (proceed == MagickFalse)
592           status=MagickFalse;
593       }
594   }
595   return(status);
596 }
597 \f
598 /*
599 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
600 %                                                                             %
601 %                                                                             %
602 %                                                                             %
603 %   G e t W a n d V i e w P i x e l s                                         %
604 %                                                                             %
605 %                                                                             %
606 %                                                                             %
607 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
608 %
609 %  GetWandViewPixels() returns the wand view pixel_wands.
610 %
611 %  The format of the GetWandViewPixels method is:
612 %
613 %      PixelWand *GetWandViewPixels(const WandView *wand_view)
614 %
615 %  A description of each parameter follows:
616 %
617 %    o wand_view: the wand view.
618 %
619 */
620 WandExport PixelWand **GetWandViewPixels(const WandView *wand_view)
621 {
622   ssize_t
623     id;
624
625   assert(wand_view != (WandView *) NULL);
626   assert(wand_view->signature == WandSignature);
627   id=GetOpenMPThreadId();
628   return(wand_view->pixel_wands[id]);
629 }
630 \f
631 /*
632 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
633 %                                                                             %
634 %                                                                             %
635 %                                                                             %
636 %   G e t W a n d V i e w W a n d                                             %
637 %                                                                             %
638 %                                                                             %
639 %                                                                             %
640 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
641 %
642 %  GetWandViewWand() returns the magick wand associated with the wand view.
643 %
644 %  The format of the GetWandViewWand method is:
645 %
646 %      MagickWand *GetWandViewWand(const WandView *wand_view)
647 %
648 %  A description of each parameter follows:
649 %
650 %    o wand_view: the wand view.
651 %
652 */
653 WandExport MagickWand *GetWandViewWand(const WandView *wand_view)
654 {
655   assert(wand_view != (WandView *) NULL);
656   assert(wand_view->signature == WandSignature);
657   return(wand_view->wand);
658 }
659 \f
660 /*
661 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
662 %                                                                             %
663 %                                                                             %
664 %                                                                             %
665 %   G e t W a n d V i e w W i d t h                                           %
666 %                                                                             %
667 %                                                                             %
668 %                                                                             %
669 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
670 %
671 %  GetWandViewWidth() returns the wand view width.
672 %
673 %  The format of the GetWandViewWidth method is:
674 %
675 %      size_t GetWandViewWidth(const WandView *wand_view)
676 %
677 %  A description of each parameter follows:
678 %
679 %    o wand_view: the wand view.
680 %
681 */
682 WandExport size_t GetWandViewWidth(const WandView *wand_view)
683 {
684   assert(wand_view != (WandView *) NULL);
685   assert(wand_view->signature == WandSignature);
686   return(wand_view->region.width);
687 }
688 \f
689 /*
690 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
691 %                                                                             %
692 %                                                                             %
693 %                                                                             %
694 %   G e t W a n d V i e w X                                                   %
695 %                                                                             %
696 %                                                                             %
697 %                                                                             %
698 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
699 %
700 %  GetWandViewX() returns the wand view x offset.
701 %
702 %  The format of the GetWandViewX method is:
703 %
704 %      ssize_t GetWandViewX(const WandView *wand_view)
705 %
706 %  A description of each parameter follows:
707 %
708 %    o wand_view: the wand view.
709 %
710 */
711 WandExport ssize_t GetWandViewX(const WandView *wand_view)
712 {
713   assert(wand_view != (WandView *) NULL);
714   assert(wand_view->signature == WandSignature);
715   return(wand_view->region.x);
716 }
717 \f
718 /*
719 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
720 %                                                                             %
721 %                                                                             %
722 %                                                                             %
723 %   G e t W a n d V i e w Y                                                   %
724 %                                                                             %
725 %                                                                             %
726 %                                                                             %
727 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
728 %
729 %  GetWandViewY() returns the wand view y offset.
730 %
731 %  The format of the GetWandViewY method is:
732 %
733 %      ssize_t GetWandViewY(const WandView *wand_view)
734 %
735 %  A description of each parameter follows:
736 %
737 %    o wand_view: the wand view.
738 %
739 */
740 WandExport ssize_t GetWandViewY(const WandView *wand_view)
741 {
742   assert(wand_view != (WandView *) NULL);
743   assert(wand_view->signature == WandSignature);
744   return(wand_view->region.y);
745 }
746 \f
747 /*
748 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
749 %                                                                             %
750 %                                                                             %
751 %                                                                             %
752 %   I s W a n d V i e w                                                       %
753 %                                                                             %
754 %                                                                             %
755 %                                                                             %
756 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
757 %
758 %  IsWandView() returns MagickTrue if the the parameter is verified as a wand
759 %  view object.
760 %
761 %  The format of the IsWandView method is:
762 %
763 %      MagickBooleanType IsWandView(const WandView *wand_view)
764 %
765 %  A description of each parameter follows:
766 %
767 %    o wand_view: the wand view.
768 %
769 */
770 WandExport MagickBooleanType IsWandView(const WandView *wand_view)
771 {
772   size_t
773     length;
774
775   if (wand_view == (const WandView *) NULL)
776     return(MagickFalse);
777   if (wand_view->signature != WandSignature)
778     return(MagickFalse);
779   length=strlen(WandViewId);
780   if (LocaleNCompare(wand_view->name,WandViewId,length) != 0)
781     return(MagickFalse);
782   return(MagickTrue);
783 }
784 \f
785 /*
786 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
787 %                                                                             %
788 %                                                                             %
789 %                                                                             %
790 %   N e w W a n d V i e w                                                     %
791 %                                                                             %
792 %                                                                             %
793 %                                                                             %
794 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
795 %
796 %  NewWandView() returns a wand view required for all other methods in the
797 %  Wand View API.
798 %
799 %  The format of the NewWandView method is:
800 %
801 %      WandView *NewWandView(MagickWand *wand)
802 %
803 %  A description of each parameter follows:
804 %
805 %    o wand: the wand.
806 %
807 */
808
809 static PixelWand ***AcquirePixelsThreadSet(const size_t number_wands,
810   const size_t number_threads)
811 {
812   PixelWand
813     ***pixel_wands;
814
815   register ssize_t
816     i;
817
818   pixel_wands=(PixelWand ***) AcquireAlignedMemory(number_threads,
819     sizeof(*pixel_wands));
820   if (pixel_wands == (PixelWand ***) NULL)
821     return((PixelWand ***) NULL);
822   (void) ResetMagickMemory(pixel_wands,0,number_threads*sizeof(*pixel_wands));
823   for (i=0; i < (ssize_t) number_threads; i++)
824   {
825     pixel_wands[i]=NewPixelWands(number_wands);
826     if (pixel_wands[i] == (PixelWand **) NULL)
827       return(DestroyPixelsThreadSet(pixel_wands,number_wands,number_threads));
828   }
829   return(pixel_wands);
830 }
831
832 WandExport WandView *NewWandView(MagickWand *wand)
833 {
834   WandView
835     *wand_view;
836
837   assert(wand != (MagickWand *) NULL);
838   assert(wand->signature == MagickSignature);
839   wand_view=(WandView *) AcquireAlignedMemory(1,sizeof(*wand_view));
840   if (wand_view == (WandView *) NULL)
841     ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
842       GetExceptionMessage(errno));
843   (void) ResetMagickMemory(wand_view,0,sizeof(*wand_view));
844   wand_view->id=AcquireWandId();
845   (void) FormatMagickString(wand_view->name,MaxTextExtent,"%s-%.20g",
846     WandViewId,(double) wand_view->id);
847   wand_view->exception=AcquireExceptionInfo();
848   wand_view->wand=wand;
849   wand_view->view=AcquireCacheView(wand_view->wand->images);
850   wand_view->region.width=wand->images->columns;
851   wand_view->region.height=wand->images->rows;
852   wand_view->number_threads=GetOpenMPMaximumThreads();
853   wand_view->pixel_wands=AcquirePixelsThreadSet(wand_view->region.width,
854     wand_view->number_threads);
855   if (wand_view->pixel_wands == (PixelWand ***) NULL)
856     ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
857       GetExceptionMessage(errno));
858   wand_view->debug=IsEventLogging();
859   wand_view->signature=WandSignature;
860   return(wand_view);
861 }
862 \f
863 /*
864 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
865 %                                                                             %
866 %                                                                             %
867 %                                                                             %
868 %   N e w W a n d V i e w R e g i o n                                         %
869 %                                                                             %
870 %                                                                             %
871 %                                                                             %
872 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
873 %
874 %  NewWandViewRegion() returns a wand view required for all other methods
875 %  in the Wand View API.
876 %
877 %  The format of the NewWandViewRegion method is:
878 %
879 %      WandView *NewWandViewRegion(MagickWand *wand,const ssize_t x,
880 %        const ssize_t y,const size_t width,const size_t height)
881 %
882 %  A description of each parameter follows:
883 %
884 %    o wand: the magick wand.
885 %
886 %    o x,y,columns,rows:  These values define the perimeter of a region of
887 %      pixel_wands view.
888 %
889 */
890 WandExport WandView *NewWandViewRegion(MagickWand *wand,const ssize_t x,
891   const ssize_t y,const size_t width,const size_t height)
892 {
893   WandView
894     *wand_view;
895
896   assert(wand != (MagickWand *) NULL);
897   assert(wand->signature == MagickSignature);
898   wand_view=(WandView *) AcquireAlignedMemory(1,sizeof(*wand_view));
899   if (wand_view == (WandView *) NULL)
900     ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
901       GetExceptionMessage(errno));
902   (void) ResetMagickMemory(wand_view,0,sizeof(*wand_view));
903   wand_view->id=AcquireWandId();
904   (void) FormatMagickString(wand_view->name,MaxTextExtent,"%s-%.20g",
905     WandViewId,(double) wand_view->id);
906   wand_view->exception=AcquireExceptionInfo();
907   wand_view->view=AcquireCacheView(wand_view->wand->images);
908   wand_view->wand=wand;
909   wand_view->region.width=width;
910   wand_view->region.height=height;
911   wand_view->region.x=x;
912   wand_view->region.y=y;
913   wand_view->number_threads=GetOpenMPMaximumThreads();
914   wand_view->pixel_wands=AcquirePixelsThreadSet(wand_view->region.width,
915     wand_view->number_threads);
916   if (wand_view->pixel_wands == (PixelWand ***) NULL)
917     ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
918       GetExceptionMessage(errno));
919   wand_view->debug=IsEventLogging();
920   wand_view->signature=WandSignature;
921   return(wand_view);
922 }
923 \f
924 /*
925 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
926 %                                                                             %
927 %                                                                             %
928 %                                                                             %
929 %   S e t W a n d V i e w I t e r a t o r                                     %
930 %                                                                             %
931 %                                                                             %
932 %                                                                             %
933 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
934 %
935 %  SetWandViewIterator() iterates over the wand view in parallel and calls
936 %  your set method for each scanline of the view.  The pixel region is
937 %  confined to the image canvas-- that is no negative offsets or widths or
938 %  heights that exceed the image dimension.  The pixels are initiallly
939 %  undefined and any settings you make in the callback method are automagically
940 %  synced back to your image.
941 %
942 %  Use this pragma if the view is not single threaded:
943 %
944 %    #pragma omp critical
945 %
946 %  to define a section of code in your callback set method that must be
947 %  executed by a single thread at a time.
948 %
949 %  The format of the SetWandViewIterator method is:
950 %
951 %      MagickBooleanType SetWandViewIterator(WandView *destination,
952 %        SetWandViewMethod set,void *context)
953 %
954 %  A description of each parameter follows:
955 %
956 %    o destination: the wand view.
957 %
958 %    o set: the set callback method.
959 %
960 %    o context: the user defined context.
961 %
962 */
963 WandExport MagickBooleanType SetWandViewIterator(WandView *destination,
964   SetWandViewMethod set,void *context)
965 {
966 #define SetWandViewTag  "WandView/Set"
967
968   ExceptionInfo
969     *exception;
970
971   Image
972     *destination_image;
973
974   MagickBooleanType
975     status;
976
977   MagickOffsetType
978     progress;
979
980   ssize_t
981     y;
982
983   assert(destination != (WandView *) NULL);
984   assert(destination->signature == WandSignature);
985   if (set == (SetWandViewMethod) NULL)
986     return(MagickFalse);
987   destination_image=destination->wand->images;
988   if (SetImageStorageClass(destination_image,DirectClass) == MagickFalse)
989     return(MagickFalse);
990   status=MagickTrue;
991   progress=0;
992   exception=destination->exception;
993 #if defined(MAGICKCORE_OPENMP_SUPPORT)
994   #pragma omp parallel for schedule(static,1) shared(progress,status)
995 #endif
996   for (y=destination->region.y; y < (ssize_t) destination->region.height; y++)
997   {
998     MagickBooleanType
999       sync;
1000
1001     register IndexPacket
1002       *restrict indexes;
1003
1004     register ssize_t
1005       id,
1006       x;
1007
1008     register PixelPacket
1009       *restrict pixels;
1010
1011     if (status == MagickFalse)
1012       continue;
1013     id=GetOpenMPThreadId();
1014     pixels=GetCacheViewAuthenticPixels(destination->view,destination->region.x,
1015       y,destination->region.width,1,exception);
1016     if (pixels == (PixelPacket *) NULL)
1017       {
1018         InheritException(destination->exception,GetCacheViewException(
1019           destination->view));
1020         status=MagickFalse;
1021         continue;
1022       }
1023     indexes=GetCacheViewAuthenticIndexQueue(destination->view);
1024     if (set(destination,context) == MagickFalse)
1025       status=MagickFalse;
1026     for (x=0; x < (ssize_t) destination->region.width; x++)
1027       PixelGetQuantumColor(destination->pixel_wands[id][x],pixels+x);
1028     if (destination_image->colorspace == CMYKColorspace)
1029       for (x=0; x < (ssize_t) destination->region.width; x++)
1030         indexes[x]=PixelGetBlackQuantum(destination->pixel_wands[id][x]);
1031     sync=SyncCacheViewAuthenticPixels(destination->view,exception);
1032     if (sync == MagickFalse)
1033       {
1034         InheritException(destination->exception,GetCacheViewException(
1035           destination->view));
1036         status=MagickFalse;
1037       }
1038     if (destination_image->progress_monitor != (MagickProgressMonitor) NULL)
1039       {
1040         MagickBooleanType
1041           proceed;
1042
1043 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1044   #pragma omp critical (MagickWand_SetWandViewIterator)
1045 #endif
1046         proceed=SetImageProgress(destination_image,SetWandViewTag,progress++,
1047           destination->region.height);
1048         if (proceed == MagickFalse)
1049           status=MagickFalse;
1050       }
1051   }
1052   return(status);
1053 }
1054 \f
1055 /*
1056 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1057 %                                                                             %
1058 %                                                                             %
1059 %                                                                             %
1060 %   T r a n s f e r W a n d V i e w I t e r a t o r                           %
1061 %                                                                             %
1062 %                                                                             %
1063 %                                                                             %
1064 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1065 %
1066 %  TransferWandViewIterator() iterates over two wand views in parallel and
1067 %  calls your transfer method for each scanline of the view.  The source pixel
1068 %  region is not confined to the image canvas-- that is you can include
1069 %  negative offsets or widths or heights that exceed the image dimension.
1070 %  However, the destination wand view is confined to the image canvas-- that
1071 %  is no negative offsets or widths or heights that exceed the image dimension
1072 %  are permitted.
1073 %
1074 %  Use this pragma if the view is not single threaded:
1075 %
1076 %    #pragma omp critical
1077 %
1078 %  to define a section of code in your callback transfer method that must be
1079 %  executed by a single thread at a time.
1080 %
1081 %  The format of the TransferWandViewIterator method is:
1082 %
1083 %      MagickBooleanType TransferWandViewIterator(WandView *source,
1084 %        WandView *destination,TransferWandViewMethod transfer,void *context)
1085 %
1086 %  A description of each parameter follows:
1087 %
1088 %    o source: the source wand view.
1089 %
1090 %    o destination: the destination wand view.
1091 %
1092 %    o transfer: the transfer callback method.
1093 %
1094 %    o context: the user defined context.
1095 %
1096 */
1097 WandExport MagickBooleanType TransferWandViewIterator(WandView *source,
1098   WandView *destination,TransferWandViewMethod transfer,void *context)
1099 {
1100 #define TransferWandViewTag  "WandView/Transfer"
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)
1131 #endif
1132   for (y=source->region.y; y < (ssize_t) source->region.height; y++)
1133   {
1134     MagickBooleanType
1135       sync;
1136
1137     register const IndexPacket
1138       *restrict indexes;
1139
1140     register const PixelPacket
1141       *restrict pixels;
1142
1143     register IndexPacket
1144       *restrict destination_indexes;
1145
1146     register ssize_t
1147       id,
1148       x;
1149
1150     register PixelPacket
1151       *restrict destination_pixels;
1152
1153     if (status == MagickFalse)
1154       continue;
1155     id=GetOpenMPThreadId();
1156     pixels=GetCacheViewVirtualPixels(source->view,source->region.x,y,
1157       source->region.width,1,source->exception);
1158     if (pixels == (const PixelPacket *) NULL)
1159       {
1160         status=MagickFalse;
1161         continue;
1162       }
1163     indexes=GetCacheViewVirtualIndexQueue(source->view);
1164     for (x=0; x < (ssize_t) source->region.width; x++)
1165       PixelSetQuantumColor(source->pixel_wands[id][x],pixels+x);
1166     if (source_image->colorspace == CMYKColorspace)
1167       for (x=0; x < (ssize_t) source->region.width; x++)
1168         PixelSetBlackQuantum(source->pixel_wands[id][x],indexes[x]);
1169     if (source_image->storage_class == PseudoClass)
1170       for (x=0; x < (ssize_t) source->region.width; x++)
1171         PixelSetIndex(source->pixel_wands[id][x],indexes[x]);
1172     destination_pixels=GetCacheViewAuthenticPixels(destination->view,
1173       destination->region.x,y,destination->region.width,1,exception);
1174     if (destination_pixels == (PixelPacket *) NULL)
1175       {
1176         status=MagickFalse;
1177         continue;
1178       }
1179     destination_indexes=GetCacheViewAuthenticIndexQueue(destination->view);
1180     for (x=0; x < (ssize_t) destination->region.width; x++)
1181       PixelSetQuantumColor(destination->pixel_wands[id][x],pixels+x);
1182     if (destination_image->colorspace == CMYKColorspace)
1183       for (x=0; x < (ssize_t) destination->region.width; x++)
1184         PixelSetBlackQuantum(destination->pixel_wands[id][x],indexes[x]);
1185     if (destination_image->storage_class == PseudoClass)
1186       for (x=0; x < (ssize_t) destination->region.width; x++)
1187         PixelSetIndex(destination->pixel_wands[id][x],indexes[x]);
1188     if (transfer(source,destination,context) == MagickFalse)
1189       status=MagickFalse;
1190     for (x=0; x < (ssize_t) destination->region.width; x++)
1191       PixelGetQuantumColor(destination->pixel_wands[id][x],
1192         destination_pixels+x);
1193     if (destination_image->colorspace == CMYKColorspace)
1194       for (x=0; x < (ssize_t) destination->region.width; x++)
1195         destination_indexes[x]=PixelGetBlackQuantum(
1196           destination->pixel_wands[id][x]);
1197     sync=SyncCacheViewAuthenticPixels(destination->view,exception);
1198     if (sync == MagickFalse)
1199       {
1200         InheritException(destination->exception,GetCacheViewException(
1201           source->view));
1202         status=MagickFalse;
1203       }
1204     if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
1205       {
1206         MagickBooleanType
1207           proceed;
1208
1209 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1210   #pragma omp critical (MagickWand_TransferWandViewIterator)
1211 #endif
1212         proceed=SetImageProgress(source_image,TransferWandViewTag,progress++,
1213           source->region.height);
1214         if (proceed == MagickFalse)
1215           status=MagickFalse;
1216       }
1217   }
1218   return(status);
1219 }
1220 \f
1221 /*
1222 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1223 %                                                                             %
1224 %                                                                             %
1225 %                                                                             %
1226 %   U p d a t e W a n d V i e w I t e r a t o r                               %
1227 %                                                                             %
1228 %                                                                             %
1229 %                                                                             %
1230 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1231 %
1232 %  UpdateWandViewIterator() iterates over the wand view in parallel and calls
1233 %  your update method for each scanline of the view.  The pixel region is
1234 %  confined to the image canvas-- that is no negative offsets or widths or
1235 %  heights that exceed the image dimension are permitted.  Updates to pixels
1236 %  in your callback are automagically synced back to the image.
1237 %
1238 %  Use this pragma if the view is not single threaded:
1239 %
1240 %    #pragma omp critical
1241 %
1242 %  to define a section of code in your callback update method that must be
1243 %  executed by a single thread at a time.
1244 %
1245 %  The format of the UpdateWandViewIterator method is:
1246 %
1247 %      MagickBooleanType UpdateWandViewIterator(WandView *source,
1248 %        UpdateWandViewMethod update,void *context)
1249 %
1250 %  A description of each parameter follows:
1251 %
1252 %    o source: the source wand view.
1253 %
1254 %    o update: the update callback method.
1255 %
1256 %    o context: the user defined context.
1257 %
1258 */
1259 WandExport MagickBooleanType UpdateWandViewIterator(WandView *source,
1260   UpdateWandViewMethod update,void *context)
1261 {
1262 #define UpdateWandViewTag  "WandView/Update"
1263
1264   ExceptionInfo
1265     *exception;
1266
1267   Image
1268     *source_image;
1269
1270   MagickBooleanType
1271     status;
1272
1273   MagickOffsetType
1274     progress;
1275
1276   ssize_t
1277     y;
1278
1279   assert(source != (WandView *) NULL);
1280   assert(source->signature == WandSignature);
1281   if (update == (UpdateWandViewMethod) NULL)
1282     return(MagickFalse);
1283   source_image=source->wand->images;
1284   if (SetImageStorageClass(source_image,DirectClass) == MagickFalse)
1285     return(MagickFalse);
1286   status=MagickTrue;
1287   progress=0;
1288   exception=source->exception;
1289 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1290   #pragma omp parallel for schedule(static,1) shared(progress,status)
1291 #endif
1292   for (y=source->region.y; y < (ssize_t) source->region.height; y++)
1293   {
1294     register IndexPacket
1295       *restrict indexes;
1296
1297     register ssize_t
1298       id,
1299       x;
1300
1301     register PixelPacket
1302       *restrict pixels;
1303
1304     if (status == MagickFalse)
1305       continue;
1306     id=GetOpenMPThreadId();
1307     pixels=GetCacheViewAuthenticPixels(source->view,source->region.x,y,
1308       source->region.width,1,exception);
1309     if (pixels == (PixelPacket *) NULL)
1310       {
1311         InheritException(source->exception,GetCacheViewException(
1312           source->view));
1313         status=MagickFalse;
1314         continue;
1315       }
1316     indexes=GetCacheViewAuthenticIndexQueue(source->view);
1317     for (x=0; x < (ssize_t) source->region.width; x++)
1318       PixelSetQuantumColor(source->pixel_wands[id][x],pixels+x);
1319     if (source_image->colorspace == CMYKColorspace)
1320       for (x=0; x < (ssize_t) source->region.width; x++)
1321         PixelSetBlackQuantum(source->pixel_wands[id][x],indexes[x]);
1322     if (update(source,context) == MagickFalse)
1323       status=MagickFalse;
1324     for (x=0; x < (ssize_t) source->region.width; x++)
1325       PixelGetQuantumColor(source->pixel_wands[id][x],pixels+x);
1326     if (source_image->colorspace == CMYKColorspace)
1327       for (x=0; x < (ssize_t) source->region.width; x++)
1328         indexes[x]=PixelGetBlackQuantum(source->pixel_wands[id][x]);
1329     if (SyncCacheViewAuthenticPixels(source->view,exception) == MagickFalse)
1330       {
1331         InheritException(source->exception,GetCacheViewException(source->view));
1332         status=MagickFalse;
1333       }
1334     if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
1335       {
1336         MagickBooleanType
1337           proceed;
1338
1339 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1340   #pragma omp critical (MagickWand_UpdateWandViewIterator)
1341 #endif
1342         proceed=SetImageProgress(source_image,UpdateWandViewTag,progress++,
1343           source->region.height);
1344         if (proceed == MagickFalse)
1345           status=MagickFalse;
1346       }
1347   }
1348   return(status);
1349 }