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