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