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