]> granicus.if.org Git - imagemagick/blob - MagickWand/wand-view.c
83b024e307643bffa4722b45a99058eba49ca4e9
[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-2011 ImageMagick Studio LLC, a non-profit organization      %
26 %  dedicated to making software imaging solutions freely available.           %
27 %                                                                             %
28 %  You may not use this file except in compliance with the License.  You may  %
29 %  obtain a copy of the License at                                            %
30 %                                                                             %
31 %    http://www.imagemagick.org/script/license.php                            %
32 %                                                                             %
33 %  Unless required by applicable law or agreed to in writing, software        %
34 %  distributed under the License is distributed on an "AS IS" BASIS,          %
35 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
36 %  See the License for the specific language governing permissions and        %
37 %  limitations under the License.                                             %
38 %                                                                             %
39 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
40 %
41 %
42 %
43 */
44 \f
45 /*
46   Include declarations.
47 */
48 #include "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   ExceptionInfo
267     *exception;
268
269   Image
270     *destination_image,
271     *source_image;
272
273   MagickBooleanType
274     status;
275
276   MagickOffsetType
277     progress;
278
279   ssize_t
280     y;
281
282   assert(source != (WandView *) NULL);
283   assert(source->signature == WandSignature);
284   if (transfer == (DuplexTransferWandViewMethod) NULL)
285     return(MagickFalse);
286   source_image=source->wand->images;
287   destination_image=destination->wand->images;
288   exception=destination->exception;
289   if (SetImageStorageClass(destination_image,DirectClass,exception) == MagickFalse)
290     return(MagickFalse);
291   status=MagickTrue;
292   progress=0;
293 #if defined(MAGICKCORE_OPENMP_SUPPORT)
294   #pragma omp parallel for schedule(static,1) shared(progress,status) num_threads(source->number_threads)
295 #endif
296   for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
297   {
298     const int
299       id = GetOpenMPThreadId();
300
301     MagickBooleanType
302       sync;
303
304     register const Quantum
305       *restrict duplex_pixels,
306       *restrict pixels;
307
308     register ssize_t
309       x;
310
311     register Quantum
312       *restrict destination_pixels;
313
314     if (status == MagickFalse)
315       continue;
316     pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y,
317       source->extent.width,1,source->exception);
318     if (pixels == (const Quantum *) NULL)
319       {
320         status=MagickFalse;
321         continue;
322       }
323     for (x=0; x < (ssize_t) source->extent.width; x++)
324     {
325       PixelSetQuantumPixel(source->image,pixels,source->pixel_wands[id][x]);
326       pixels+=GetPixelChannels(source->image);
327     }
328     duplex_pixels=GetCacheViewVirtualPixels(duplex->view,duplex->extent.x,y,
329       duplex->extent.width,1,duplex->exception);
330     if (duplex_pixels == (const Quantum *) NULL)
331       {
332         status=MagickFalse;
333         continue;
334       }
335     for (x=0; x < (ssize_t) duplex->extent.width; x++)
336     {
337       PixelSetQuantumPixel(duplex->image,duplex_pixels,
338         duplex->pixel_wands[id][x]);
339       duplex_pixels+=GetPixelChannels(duplex->image);
340     }
341     destination_pixels=GetCacheViewAuthenticPixels(destination->view,
342       destination->extent.x,y,destination->extent.width,1,exception);
343     if (destination_pixels == (Quantum *) NULL)
344       {
345         status=MagickFalse;
346         continue;
347       }
348     for (x=0; x < (ssize_t) destination->extent.width; x++)
349     {
350       PixelSetQuantumPixel(destination->image,destination_pixels,
351         destination->pixel_wands[id][x]);
352       destination_pixels+=GetPixelChannels(destination->image);
353     }
354     if (transfer(source,duplex,destination,y,id,context) == MagickFalse)
355       status=MagickFalse;
356     destination_pixels=GetCacheViewAuthenticPixels(destination->view,
357       destination->extent.x,y,destination->extent.width,1,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,exception);
365     if (sync == MagickFalse)
366       {
367         InheritException(destination->exception,GetCacheViewException(
368           source->view));
369         status=MagickFalse;
370       }
371     if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
372       {
373         MagickBooleanType
374           proceed;
375
376 #if defined(MAGICKCORE_OPENMP_SUPPORT)
377   #pragma omp critical (MagickWand_DuplexTransferWandViewIterator)
378 #endif
379         proceed=SetImageProgress(source_image,source->description,progress++,
380           source->extent.height);
381         if (proceed == MagickFalse)
382           status=MagickFalse;
383       }
384   }
385   return(status);
386 }
387 \f
388 /*
389 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
390 %                                                                             %
391 %                                                                             %
392 %                                                                             %
393 %   G e t W a n d V i e w E x c e p t i o n                                   %
394 %                                                                             %
395 %                                                                             %
396 %                                                                             %
397 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
398 %
399 %  GetWandViewException() returns the severity, reason, and description of any
400 %  error that occurs when utilizing a wand view.
401 %
402 %  The format of the GetWandViewException method is:
403 %
404 %      char *GetWandViewException(const PixelWand *wand_view,
405 %        ExceptionType *severity)
406 %
407 %  A description of each parameter follows:
408 %
409 %    o wand_view: the pixel wand_view.
410 %
411 %    o severity: the severity of the error is returned here.
412 %
413 */
414 WandExport char *GetWandViewException(const WandView *wand_view,
415   ExceptionType *severity)
416 {
417   char
418     *description;
419
420   assert(wand_view != (const WandView *) NULL);
421   assert(wand_view->signature == WandSignature);
422   if (wand_view->debug != MagickFalse)
423     (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",wand_view->name);
424   assert(severity != (ExceptionType *) NULL);
425   *severity=wand_view->exception->severity;
426   description=(char *) AcquireQuantumMemory(2UL*MaxTextExtent,
427     sizeof(*description));
428   if (description == (char *) NULL)
429     ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
430       wand_view->name);
431   *description='\0';
432   if (wand_view->exception->reason != (char *) NULL)
433     (void) CopyMagickString(description,GetLocaleExceptionMessage(
434       wand_view->exception->severity,wand_view->exception->reason),
435         MaxTextExtent);
436   if (wand_view->exception->description != (char *) NULL)
437     {
438       (void) ConcatenateMagickString(description," (",MaxTextExtent);
439       (void) ConcatenateMagickString(description,GetLocaleExceptionMessage(
440         wand_view->exception->severity,wand_view->exception->description),
441         MaxTextExtent);
442       (void) ConcatenateMagickString(description,")",MaxTextExtent);
443     }
444   return(description);
445 }
446 \f
447 /*
448 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
449 %                                                                             %
450 %                                                                             %
451 %                                                                             %
452 %   G e t W a n d V i e w E x t e n t                                         %
453 %                                                                             %
454 %                                                                             %
455 %                                                                             %
456 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
457 %
458 %  GetWandViewExtent() returns the wand view extent.
459 %
460 %  The format of the GetWandViewExtent method is:
461 %
462 %      RectangleInfo GetWandViewExtent(const WandView *wand_view)
463 %
464 %  A description of each parameter follows:
465 %
466 %    o wand_view: the wand view.
467 %
468 */
469 WandExport RectangleInfo GetWandViewExtent(const WandView *wand_view)
470 {
471   assert(wand_view != (WandView *) NULL);
472   assert(wand_view->signature == WandSignature);
473   return(wand_view->extent);
474 }
475 \f
476 /*
477 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
478 %                                                                             %
479 %                                                                             %
480 %                                                                             %
481 %   G e t W a n d V i e w I t e r a t o r                                     %
482 %                                                                             %
483 %                                                                             %
484 %                                                                             %
485 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
486 %
487 %  GetWandViewIterator() iterates over the wand view in parallel and calls
488 %  your get method for each scanline of the view.  The pixel extent is
489 %  not confined to the image canvas-- that is you can include negative offsets
490 %  or widths or heights that exceed the image dimension.  Any updates to
491 %  the pixels in your callback are ignored.
492 %
493 %  The callback signature is:
494 %
495 %      MagickBooleanType GetImageViewMethod(const WandView *source,
496 %        const ssize_t y,const int thread_id,void *context)
497 %
498 %  Use this pragma if the view is not single threaded:
499 %
500 %    #pragma omp critical
501 %
502 %  to define a section of code in your callback get method that must be
503 %  executed by a single thread at a time.
504 %
505 %  The format of the GetWandViewIterator method is:
506 %
507 %      MagickBooleanType GetWandViewIterator(WandView *source,
508 %        GetWandViewMethod get,void *context)
509 %
510 %  A description of each parameter follows:
511 %
512 %    o source: the source wand view.
513 %
514 %    o get: the get callback method.
515 %
516 %    o context: the user defined context.
517 %
518 */
519 WandExport MagickBooleanType GetWandViewIterator(WandView *source,
520   GetWandViewMethod get,void *context)
521 {
522   Image
523     *source_image;
524
525   MagickBooleanType
526     status;
527
528   MagickOffsetType
529     progress;
530
531   ssize_t
532     y;
533
534   assert(source != (WandView *) NULL);
535   assert(source->signature == WandSignature);
536   if (get == (GetWandViewMethod) NULL)
537     return(MagickFalse);
538   source_image=source->wand->images;
539   status=MagickTrue;
540   progress=0;
541 #if defined(MAGICKCORE_OPENMP_SUPPORT)
542   #pragma omp parallel for schedule(static,1) shared(progress,status) num_threads(source->number_threads)
543 #endif
544   for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
545   {
546     const int
547       id = GetOpenMPThreadId();
548
549     register const Quantum
550       *pixels;
551
552     register ssize_t
553       x;
554
555     if (status == MagickFalse)
556       continue;
557     pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y,
558       source->extent.width,1,source->exception);
559     if (pixels == (const Quantum *) NULL)
560       {
561         status=MagickFalse;
562         continue;
563       }
564     for (x=0; x < (ssize_t) source->extent.width; x++)
565     {
566       PixelSetQuantumPixel(source->image,pixels,source->pixel_wands[id][x]);
567       pixels+=GetPixelChannels(source->image);
568     }
569     if (get(source,y,id,context) == MagickFalse)
570       status=MagickFalse;
571     if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
572       {
573         MagickBooleanType
574           proceed;
575
576 #if defined(MAGICKCORE_OPENMP_SUPPORT)
577   #pragma omp critical (MagickWand_GetWandViewIterator)
578 #endif
579         proceed=SetImageProgress(source_image,source->description,progress++,
580           source->extent.height);
581         if (proceed == MagickFalse)
582           status=MagickFalse;
583       }
584   }
585   return(status);
586 }
587 \f
588 /*
589 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
590 %                                                                             %
591 %                                                                             %
592 %                                                                             %
593 %   G e t W a n d V i e w P i x e l s                                         %
594 %                                                                             %
595 %                                                                             %
596 %                                                                             %
597 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
598 %
599 %  GetWandViewPixels() returns the wand view pixel_wands.
600 %
601 %  The format of the GetWandViewPixels method is:
602 %
603 %      PixelWand *GetWandViewPixels(const WandView *wand_view)
604 %
605 %  A description of each parameter follows:
606 %
607 %    o wand_view: the wand view.
608 %
609 */
610 WandExport PixelWand **GetWandViewPixels(const WandView *wand_view)
611 {
612   const int
613     id = GetOpenMPThreadId();
614
615   assert(wand_view != (WandView *) NULL);
616   assert(wand_view->signature == WandSignature);
617   return(wand_view->pixel_wands[id]);
618 }
619 \f
620 /*
621 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
622 %                                                                             %
623 %                                                                             %
624 %                                                                             %
625 %   G e t W a n d V i e w W a n d                                             %
626 %                                                                             %
627 %                                                                             %
628 %                                                                             %
629 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
630 %
631 %  GetWandViewWand() returns the magick wand associated with the wand view.
632 %
633 %  The format of the GetWandViewWand method is:
634 %
635 %      MagickWand *GetWandViewWand(const WandView *wand_view)
636 %
637 %  A description of each parameter follows:
638 %
639 %    o wand_view: the wand view.
640 %
641 */
642 WandExport MagickWand *GetWandViewWand(const WandView *wand_view)
643 {
644   assert(wand_view != (WandView *) NULL);
645   assert(wand_view->signature == WandSignature);
646   return(wand_view->wand);
647 }
648 \f
649 /*
650 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
651 %                                                                             %
652 %                                                                             %
653 %                                                                             %
654 %   I s W a n d V i e w                                                       %
655 %                                                                             %
656 %                                                                             %
657 %                                                                             %
658 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
659 %
660 %  IsWandView() returns MagickTrue if the the parameter is verified as a wand
661 %  view object.
662 %
663 %  The format of the IsWandView method is:
664 %
665 %      MagickBooleanType IsWandView(const WandView *wand_view)
666 %
667 %  A description of each parameter follows:
668 %
669 %    o wand_view: the wand view.
670 %
671 */
672 WandExport MagickBooleanType IsWandView(const WandView *wand_view)
673 {
674   size_t
675     length;
676
677   if (wand_view == (const WandView *) NULL)
678     return(MagickFalse);
679   if (wand_view->signature != WandSignature)
680     return(MagickFalse);
681   length=strlen(WandViewId);
682   if (LocaleNCompare(wand_view->name,WandViewId,length) != 0)
683     return(MagickFalse);
684   return(MagickTrue);
685 }
686 \f
687 /*
688 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
689 %                                                                             %
690 %                                                                             %
691 %                                                                             %
692 %   N e w W a n d V i e w                                                     %
693 %                                                                             %
694 %                                                                             %
695 %                                                                             %
696 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
697 %
698 %  NewWandView() returns a wand view required for all other methods in the
699 %  Wand View API.
700 %
701 %  The format of the NewWandView method is:
702 %
703 %      WandView *NewWandView(MagickWand *wand)
704 %
705 %  A description of each parameter follows:
706 %
707 %    o wand: the wand.
708 %
709 */
710
711 static PixelWand ***AcquirePixelsThreadSet(const size_t number_wands,
712   const size_t number_threads)
713 {
714   PixelWand
715     ***pixel_wands;
716
717   register ssize_t
718     i;
719
720   pixel_wands=(PixelWand ***) AcquireQuantumMemory(number_threads,
721     sizeof(*pixel_wands));
722   if (pixel_wands == (PixelWand ***) NULL)
723     return((PixelWand ***) NULL);
724   (void) ResetMagickMemory(pixel_wands,0,number_threads*sizeof(*pixel_wands));
725   for (i=0; i < (ssize_t) number_threads; i++)
726   {
727     pixel_wands[i]=NewPixelWands(number_wands);
728     if (pixel_wands[i] == (PixelWand **) NULL)
729       return(DestroyPixelsThreadSet(pixel_wands,number_wands,number_threads));
730   }
731   return(pixel_wands);
732 }
733
734 WandExport WandView *NewWandView(MagickWand *wand)
735 {
736   WandView
737     *wand_view;
738
739   assert(wand != (MagickWand *) NULL);
740   assert(wand->signature == WandSignature);
741   wand_view=(WandView *) AcquireMagickMemory(sizeof(*wand_view));
742   if (wand_view == (WandView *) NULL)
743     ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
744       GetExceptionMessage(errno));
745   (void) ResetMagickMemory(wand_view,0,sizeof(*wand_view));
746   wand_view->id=AcquireWandId();
747   (void) FormatLocaleString(wand_view->name,MaxTextExtent,"%s-%.20g",
748     WandViewId,(double) wand_view->id);
749   wand_view->description=ConstantString("WandView");
750   wand_view->wand=wand;
751   wand_view->view=AcquireCacheView(wand_view->wand->images);
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=AcquireExceptionInfo();
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   WandView
797     *wand_view;
798
799   assert(wand != (MagickWand *) NULL);
800   assert(wand->signature == WandSignature);
801   wand_view=(WandView *) AcquireMagickMemory(sizeof(*wand_view));
802   if (wand_view == (WandView *) NULL)
803     ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
804       GetExceptionMessage(errno));
805   (void) ResetMagickMemory(wand_view,0,sizeof(*wand_view));
806   wand_view->id=AcquireWandId();
807   (void) FormatLocaleString(wand_view->name,MaxTextExtent,"%s-%.20g",
808     WandViewId,(double) wand_view->id);
809   wand_view->description=ConstantString("WandView");
810   wand_view->view=AcquireCacheView(wand_view->wand->images);
811   wand_view->wand=wand;
812   wand_view->extent.width=width;
813   wand_view->extent.height=height;
814   wand_view->extent.x=x;
815   wand_view->extent.y=y;
816   wand_view->number_threads=GetOpenMPMaximumThreads();
817   wand_view->exception=AcquireExceptionInfo();
818   wand_view->pixel_wands=AcquirePixelsThreadSet(wand_view->extent.width,
819     wand_view->number_threads);
820   if (wand_view->pixel_wands == (PixelWand ***) NULL)
821     ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
822       GetExceptionMessage(errno));
823   wand_view->debug=IsEventLogging();
824   wand_view->signature=WandSignature;
825   return(wand_view);
826 }
827 \f
828 /*
829 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
830 %                                                                             %
831 %                                                                             %
832 %                                                                             %
833 %   S e t W a n d V i e w D e s c r i p t i o n                               %
834 %                                                                             %
835 %                                                                             %
836 %                                                                             %
837 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
838 %
839 %  SetWandViewDescription() associates a description with an image view.
840 %
841 %  The format of the SetWandViewDescription method is:
842 %
843 %      void SetWandViewDescription(WandView *image_view,const char *description)
844 %
845 %  A description of each parameter follows:
846 %
847 %    o wand_view: the wand view.
848 %
849 %    o description: the wand view description.
850 %
851 */
852 MagickExport void SetWandViewDescription(WandView *wand_view,
853   const char *description)
854 {
855   assert(wand_view != (WandView *) NULL);
856   assert(wand_view->signature == WandSignature);
857   wand_view->description=ConstantString(description);
858 }
859 \f
860 /*
861 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
862 %                                                                             %
863 %                                                                             %
864 %                                                                             %
865 %   S e t W a n d V i e w I t e r a t o r                                     %
866 %                                                                             %
867 %                                                                             %
868 %                                                                             %
869 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
870 %
871 %  SetWandViewIterator() iterates over the wand view in parallel and calls
872 %  your set method for each scanline of the view.  The pixel extent is
873 %  confined to the image canvas-- that is no negative offsets or widths or
874 %  heights that exceed the image dimension.  The pixels are initiallly
875 %  undefined and any settings you make in the callback method are automagically
876 %  synced back to your image.
877 %
878 %  The callback signature is:
879 %
880 %      MagickBooleanType SetImageViewMethod(ImageView *destination,
881 %        const ssize_t y,const int thread_id,void *context)
882 %
883 %  Use this pragma if the view is not single threaded:
884 %
885 %    #pragma omp critical
886 %
887 %  to define a section of code in your callback set method that must be
888 %  executed by a single thread at a time.
889 %
890 %  The format of the SetWandViewIterator method is:
891 %
892 %      MagickBooleanType SetWandViewIterator(WandView *destination,
893 %        SetWandViewMethod set,void *context)
894 %
895 %  A description of each parameter follows:
896 %
897 %    o destination: the wand view.
898 %
899 %    o set: the set callback method.
900 %
901 %    o context: the user defined context.
902 %
903 */
904 WandExport MagickBooleanType SetWandViewIterator(WandView *destination,
905   SetWandViewMethod set,void *context)
906 {
907   ExceptionInfo
908     *exception;
909
910   Image
911     *destination_image;
912
913   MagickBooleanType
914     status;
915
916   MagickOffsetType
917     progress;
918
919   ssize_t
920     y;
921
922   assert(destination != (WandView *) NULL);
923   assert(destination->signature == WandSignature);
924   if (set == (SetWandViewMethod) NULL)
925     return(MagickFalse);
926   destination_image=destination->wand->images;
927   exception=destination->exception;
928   if (SetImageStorageClass(destination_image,DirectClass,exception) == MagickFalse)
929     return(MagickFalse);
930   status=MagickTrue;
931   progress=0;
932 #if defined(MAGICKCORE_OPENMP_SUPPORT)
933   #pragma omp parallel for schedule(static,1) shared(progress,status) num_threads(destination->number_threads)
934 #endif
935   for (y=destination->extent.y; y < (ssize_t) destination->extent.height; y++)
936   {
937     const int
938       id = GetOpenMPThreadId();
939
940     MagickBooleanType
941       sync;
942
943     register ssize_t
944       x;
945
946     register Quantum
947       *restrict pixels;
948
949     if (status == MagickFalse)
950       continue;
951     pixels=GetCacheViewAuthenticPixels(destination->view,destination->extent.x,
952       y,destination->extent.width,1,exception);
953     if (pixels == (Quantum *) NULL)
954       {
955         InheritException(destination->exception,GetCacheViewException(
956           destination->view));
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,exception);
969     if (sync == MagickFalse)
970       {
971         InheritException(destination->exception,GetCacheViewException(
972           destination->view));
973         status=MagickFalse;
974       }
975     if (destination_image->progress_monitor != (MagickProgressMonitor) NULL)
976       {
977         MagickBooleanType
978           proceed;
979
980 #if defined(MAGICKCORE_OPENMP_SUPPORT)
981   #pragma omp critical (MagickWand_SetWandViewIterator)
982 #endif
983         proceed=SetImageProgress(destination_image,destination->description,
984           progress++,destination->extent.height);
985         if (proceed == MagickFalse)
986           status=MagickFalse;
987       }
988   }
989   return(status);
990 }
991 \f
992 /*
993 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
994 %                                                                             %
995 %                                                                             %
996 %                                                                             %
997 %   S e t W a n d V i e w T h r e a d s                                       %
998 %                                                                             %
999 %                                                                             %
1000 %                                                                             %
1001 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1002 %
1003 %  SetWandViewThreads() sets the number of threads in a thread team.
1004 %
1005 %  The format of the SetWandViewDescription method is:
1006 %
1007 %      void SetWandViewThreads(WandView *image_view,
1008 %        const size_t number_threads)
1009 %
1010 %  A description of each parameter follows:
1011 %
1012 %    o image_view: the image view.
1013 %
1014 %    o number_threads: the number of threads in a thread team.
1015 %
1016 */
1017 MagickExport void SetWandViewThreads(WandView *image_view,
1018   const size_t number_threads)
1019 {
1020   assert(image_view != (WandView *) NULL);
1021   assert(image_view->signature == MagickSignature);
1022   image_view->number_threads=number_threads;
1023   if (number_threads > GetOpenMPMaximumThreads())
1024     image_view->number_threads=GetOpenMPMaximumThreads();
1025 }
1026 \f
1027 /*
1028 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1029 %                                                                             %
1030 %                                                                             %
1031 %                                                                             %
1032 %   T r a n s f e r W a n d V i e w I t e r a t o r                           %
1033 %                                                                             %
1034 %                                                                             %
1035 %                                                                             %
1036 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1037 %
1038 %  TransferWandViewIterator() iterates over two wand views in parallel and
1039 %  calls your transfer method for each scanline of the view.  The source pixel
1040 %  extent is not confined to the image canvas-- that is you can include
1041 %  negative offsets or widths or heights that exceed the image dimension.
1042 %  However, the destination wand view is confined to the image canvas-- that
1043 %  is no negative offsets or widths or heights that exceed the image dimension
1044 %  are permitted.
1045 %
1046 %  The callback signature is:
1047 %
1048 %      MagickBooleanType TransferImageViewMethod(const WandView *source,
1049 %        WandView *destination,const ssize_t y,const int thread_id,
1050 %        void *context)
1051 %
1052 %  Use this pragma if the view is not single threaded:
1053 %
1054 %    #pragma omp critical
1055 %
1056 %  to define a section of code in your callback transfer method that must be
1057 %  executed by a single thread at a time.
1058 %
1059 %  The format of the TransferWandViewIterator method is:
1060 %
1061 %      MagickBooleanType TransferWandViewIterator(WandView *source,
1062 %        WandView *destination,TransferWandViewMethod transfer,void *context)
1063 %
1064 %  A description of each parameter follows:
1065 %
1066 %    o source: the source wand view.
1067 %
1068 %    o destination: the destination wand view.
1069 %
1070 %    o transfer: the transfer callback method.
1071 %
1072 %    o context: the user defined context.
1073 %
1074 */
1075 WandExport MagickBooleanType TransferWandViewIterator(WandView *source,
1076   WandView *destination,TransferWandViewMethod transfer,void *context)
1077 {
1078   ExceptionInfo
1079     *exception;
1080
1081   Image
1082     *destination_image,
1083     *source_image;
1084
1085   MagickBooleanType
1086     status;
1087
1088   MagickOffsetType
1089     progress;
1090
1091   ssize_t
1092     y;
1093
1094   assert(source != (WandView *) NULL);
1095   assert(source->signature == WandSignature);
1096   if (transfer == (TransferWandViewMethod) NULL)
1097     return(MagickFalse);
1098   source_image=source->wand->images;
1099   destination_image=destination->wand->images;
1100   exception=destination->exception;
1101   if (SetImageStorageClass(destination_image,DirectClass,exception) == MagickFalse)
1102     return(MagickFalse);
1103   status=MagickTrue;
1104   progress=0;
1105 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1106   #pragma omp parallel for schedule(static,1) shared(progress,status) num_threads(source->number_threads)
1107 #endif
1108   for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
1109   {
1110     const int
1111       id = GetOpenMPThreadId();
1112
1113     MagickBooleanType
1114       sync;
1115
1116     register const Quantum
1117       *restrict pixels;
1118
1119     register ssize_t
1120       x;
1121
1122     register Quantum
1123       *restrict destination_pixels;
1124
1125     if (status == MagickFalse)
1126       continue;
1127     pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y,
1128       source->extent.width,1,source->exception);
1129     if (pixels == (const Quantum *) NULL)
1130       {
1131         status=MagickFalse;
1132         continue;
1133       }
1134     for (x=0; x < (ssize_t) source->extent.width; x++)
1135     {
1136       PixelSetQuantumPixel(source->image,pixels,source->pixel_wands[id][x]);
1137       pixels+=GetPixelChannels(source->image);
1138     }
1139     destination_pixels=GetCacheViewAuthenticPixels(destination->view,
1140       destination->extent.x,y,destination->extent.width,1,exception);
1141     if (destination_pixels == (Quantum *) NULL)
1142       {
1143         status=MagickFalse;
1144         continue;
1145       }
1146     for (x=0; x < (ssize_t) destination->extent.width; x++)
1147     {
1148       PixelSetQuantumPixel(destination->image,destination_pixels,
1149         destination->pixel_wands[id][x]);
1150       destination_pixels+=GetPixelChannels(destination->image);
1151     }
1152     if (transfer(source,destination,y,id,context) == MagickFalse)
1153       status=MagickFalse;
1154     destination_pixels=GetCacheViewAuthenticPixels(destination->view,
1155       destination->extent.x,y,destination->extent.width,1,exception);
1156     for (x=0; x < (ssize_t) destination->extent.width; x++)
1157     {
1158       PixelGetQuantumPixel(destination->image,destination->pixel_wands[id][x],
1159         destination_pixels);
1160       destination_pixels+=GetPixelChannels(destination->image);
1161     }
1162     sync=SyncCacheViewAuthenticPixels(destination->view,exception);
1163     if (sync == MagickFalse)
1164       {
1165         InheritException(destination->exception,GetCacheViewException(
1166           source->view));
1167         status=MagickFalse;
1168       }
1169     if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
1170       {
1171         MagickBooleanType
1172           proceed;
1173
1174 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1175   #pragma omp critical (MagickWand_TransferWandViewIterator)
1176 #endif
1177         proceed=SetImageProgress(source_image,source->description,progress++,
1178           source->extent.height);
1179         if (proceed == MagickFalse)
1180           status=MagickFalse;
1181       }
1182   }
1183   return(status);
1184 }
1185 \f
1186 /*
1187 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1188 %                                                                             %
1189 %                                                                             %
1190 %                                                                             %
1191 %   U p d a t e W a n d V i e w I t e r a t o r                               %
1192 %                                                                             %
1193 %                                                                             %
1194 %                                                                             %
1195 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1196 %
1197 %  UpdateWandViewIterator() iterates over the wand view in parallel and calls
1198 %  your update method for each scanline of the view.  The pixel extent is
1199 %  confined to the image canvas-- that is no negative offsets or widths or
1200 %  heights that exceed the image dimension are permitted.  Updates to pixels
1201 %  in your callback are automagically synced back to the image.
1202 %
1203 %  The callback signature is:
1204 %
1205 %      MagickBooleanType UpdateImageViewMethod(WandView *source,const ssize_t y,
1206 %        const int thread_id,void *context)
1207 %
1208 %  Use this pragma if the view is not single threaded:
1209 %
1210 %    #pragma omp critical
1211 %
1212 %  to define a section of code in your callback update method that must be
1213 %  executed by a single thread at a time.
1214 %
1215 %  The format of the UpdateWandViewIterator method is:
1216 %
1217 %      MagickBooleanType UpdateWandViewIterator(WandView *source,
1218 %        UpdateWandViewMethod update,void *context)
1219 %
1220 %  A description of each parameter follows:
1221 %
1222 %    o source: the source wand view.
1223 %
1224 %    o update: the update callback method.
1225 %
1226 %    o context: the user defined context.
1227 %
1228 */
1229 WandExport MagickBooleanType UpdateWandViewIterator(WandView *source,
1230   UpdateWandViewMethod update,void *context)
1231 {
1232   ExceptionInfo
1233     *exception;
1234
1235   Image
1236     *source_image;
1237
1238   MagickBooleanType
1239     status;
1240
1241   MagickOffsetType
1242     progress;
1243
1244   ssize_t
1245     y;
1246
1247   assert(source != (WandView *) NULL);
1248   assert(source->signature == WandSignature);
1249   if (update == (UpdateWandViewMethod) NULL)
1250     return(MagickFalse);
1251   source_image=source->wand->images;
1252   exception=source->exception;
1253   if (SetImageStorageClass(source_image,DirectClass,exception) == MagickFalse)
1254     return(MagickFalse);
1255   status=MagickTrue;
1256   progress=0;
1257 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1258   #pragma omp parallel for schedule(static,1) shared(progress,status) num_threads(source->number_threads)
1259 #endif
1260   for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
1261   {
1262     const int
1263       id = GetOpenMPThreadId();
1264
1265     register ssize_t
1266       x;
1267
1268     register Quantum
1269       *restrict pixels;
1270
1271     if (status == MagickFalse)
1272       continue;
1273     pixels=GetCacheViewAuthenticPixels(source->view,source->extent.x,y,
1274       source->extent.width,1,exception);
1275     if (pixels == (Quantum *) NULL)
1276       {
1277         InheritException(source->exception,GetCacheViewException(
1278           source->view));
1279         status=MagickFalse;
1280         continue;
1281       }
1282     for (x=0; x < (ssize_t) source->extent.width; x++)
1283     {
1284       PixelSetQuantumPixel(source->image,pixels,source->pixel_wands[id][x]);
1285       pixels+=GetPixelChannels(source->image);
1286     }
1287     if (update(source,y,id,context) == MagickFalse)
1288       status=MagickFalse;
1289     for (x=0; x < (ssize_t) source->extent.width; x++)
1290     {
1291       PixelGetQuantumPixel(source->image,source->pixel_wands[id][x],pixels);
1292       pixels+=GetPixelChannels(source->image);
1293     }
1294     if (SyncCacheViewAuthenticPixels(source->view,exception) == MagickFalse)
1295       {
1296         InheritException(source->exception,GetCacheViewException(source->view));
1297         status=MagickFalse;
1298       }
1299     if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
1300       {
1301         MagickBooleanType
1302           proceed;
1303
1304 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1305   #pragma omp critical (MagickWand_UpdateWandViewIterator)
1306 #endif
1307         proceed=SetImageProgress(source_image,source->description,progress++,
1308           source->extent.height);
1309         if (proceed == MagickFalse)
1310           status=MagickFalse;
1311       }
1312   }
1313   return(status);
1314 }