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