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