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