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-2016 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 
     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) ResetMagickMemory(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,4) shared(progress,status) \
    300     magick_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 critical (MagickWand_DuplexTransferWandViewIterator)
    382 #endif
    383         proceed=SetImageProgress(source_image,source->description,progress++,
    384           source->extent.height);
    385         if (proceed == MagickFalse)
    386           status=MagickFalse;
    387       }
    388   }
    389   return(status);
    390 }
    391 
    392 /*
    394 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    395 %                                                                             %
    396 %                                                                             %
    397 %                                                                             %
    398 %   G e t W a n d V i e w E x c e p t i o n                                   %
    399 %                                                                             %
    400 %                                                                             %
    401 %                                                                             %
    402 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    403 %
    404 %  GetWandViewException() returns the severity, reason, and description of any
    405 %  error that occurs when utilizing a wand view.
    406 %
    407 %  The format of the GetWandViewException method is:
    408 %
    409 %      char *GetWandViewException(const WandView *wand_view,
    410 %        ExceptionType *severity)
    411 %
    412 %  A description of each parameter follows:
    413 %
    414 %    o wand_view: the pixel wand_view.
    415 %
    416 %    o severity: the severity of the error is returned here.
    417 %
    418 */
    419 WandExport char *GetWandViewException(const WandView *wand_view,
    420   ExceptionType *severity)
    421 {
    422   char
    423     *description;
    424 
    425   assert(wand_view != (const WandView *) NULL);
    426   assert(wand_view->signature == MagickWandSignature);
    427   if (wand_view->debug != MagickFalse)
    428     (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",wand_view->name);
    429   assert(severity != (ExceptionType *) NULL);
    430   *severity=wand_view->exception->severity;
    431   description=(char *) AcquireQuantumMemory(2UL*MagickPathExtent,
    432     sizeof(*description));
    433   if (description == (char *) NULL)
    434     ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
    435       wand_view->name);
    436   *description='\0';
    437   if (wand_view->exception->reason != (char *) NULL)
    438     (void) CopyMagickString(description,GetLocaleExceptionMessage(
    439       wand_view->exception->severity,wand_view->exception->reason),
    440         MagickPathExtent);
    441   if (wand_view->exception->description != (char *) NULL)
    442     {
    443       (void) ConcatenateMagickString(description," (",MagickPathExtent);
    444       (void) ConcatenateMagickString(description,GetLocaleExceptionMessage(
    445         wand_view->exception->severity,wand_view->exception->description),
    446         MagickPathExtent);
    447       (void) ConcatenateMagickString(description,")",MagickPathExtent);
    448     }
    449   return(description);
    450 }
    451 
    452 /*
    454 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    455 %                                                                             %
    456 %                                                                             %
    457 %                                                                             %
    458 %   G e t W a n d V i e w E x t e n t                                         %
    459 %                                                                             %
    460 %                                                                             %
    461 %                                                                             %
    462 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    463 %
    464 %  GetWandViewExtent() returns the wand view extent.
    465 %
    466 %  The format of the GetWandViewExtent method is:
    467 %
    468 %      RectangleInfo GetWandViewExtent(const WandView *wand_view)
    469 %
    470 %  A description of each parameter follows:
    471 %
    472 %    o wand_view: the wand view.
    473 %
    474 */
    475 WandExport RectangleInfo GetWandViewExtent(const WandView *wand_view)
    476 {
    477   assert(wand_view != (WandView *) NULL);
    478   assert(wand_view->signature == MagickWandSignature);
    479   return(wand_view->extent);
    480 }
    481 
    482 /*
    484 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    485 %                                                                             %
    486 %                                                                             %
    487 %                                                                             %
    488 %   G e t W a n d V i e w I t e r a t o r                                     %
    489 %                                                                             %
    490 %                                                                             %
    491 %                                                                             %
    492 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    493 %
    494 %  GetWandViewIterator() iterates over the wand view in parallel and calls
    495 %  your get method for each scanline of the view.  The pixel extent is
    496 %  not confined to the image canvas-- that is you can include negative offsets
    497 %  or widths or heights that exceed the image dimension.  Any updates to
    498 %  the pixels in your callback are ignored.
    499 %
    500 %  The callback signature is:
    501 %
    502 %      MagickBooleanType GetImageViewMethod(const WandView *source,
    503 %        const ssize_t y,const int thread_id,void *context)
    504 %
    505 %  Use this pragma if the view is not single threaded:
    506 %
    507 %    #pragma omp critical
    508 %
    509 %  to define a section of code in your callback get method that must be
    510 %  executed by a single thread at a time.
    511 %
    512 %  The format of the GetWandViewIterator method is:
    513 %
    514 %      MagickBooleanType GetWandViewIterator(WandView *source,
    515 %        GetWandViewMethod get,void *context)
    516 %
    517 %  A description of each parameter follows:
    518 %
    519 %    o source: the source wand view.
    520 %
    521 %    o get: the get callback method.
    522 %
    523 %    o context: the user defined context.
    524 %
    525 */
    526 WandExport MagickBooleanType GetWandViewIterator(WandView *source,
    527   GetWandViewMethod get,void *context)
    528 {
    529   Image
    530     *source_image;
    531 
    532   MagickBooleanType
    533     status;
    534 
    535   MagickOffsetType
    536     progress;
    537 
    538 #if defined(MAGICKCORE_OPENMP_SUPPORT)
    539   size_t
    540     height;
    541 #endif
    542 
    543   ssize_t
    544     y;
    545 
    546   assert(source != (WandView *) NULL);
    547   assert(source->signature == MagickWandSignature);
    548   if (get == (GetWandViewMethod) NULL)
    549     return(MagickFalse);
    550   source_image=source->wand->images;
    551   status=MagickTrue;
    552   progress=0;
    553 #if defined(MAGICKCORE_OPENMP_SUPPORT)
    554   height=source->extent.height-source->extent.y;
    555   #pragma omp parallel for schedule(static,4) shared(progress,status) \
    556     magick_threads(source_image,source_image,height,1)
    557 #endif
    558   for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
    559   {
    560     const int
    561       id = GetOpenMPThreadId();
    562 
    563     register const Quantum
    564       *pixels;
    565 
    566     register ssize_t
    567       x;
    568 
    569     if (status == MagickFalse)
    570       continue;
    571     pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y,
    572       source->extent.width,1,source->exception);
    573     if (pixels == (const Quantum *) NULL)
    574       {
    575         status=MagickFalse;
    576         continue;
    577       }
    578     for (x=0; x < (ssize_t) source->extent.width; x++)
    579     {
    580       PixelSetQuantumPixel(source->image,pixels,source->pixel_wands[id][x]);
    581       pixels+=GetPixelChannels(source->image);
    582     }
    583     if (get(source,y,id,context) == MagickFalse)
    584       status=MagickFalse;
    585     if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
    586       {
    587         MagickBooleanType
    588           proceed;
    589 
    590 #if defined(MAGICKCORE_OPENMP_SUPPORT)
    591         #pragma omp critical (MagickWand_GetWandViewIterator)
    592 #endif
    593         proceed=SetImageProgress(source_image,source->description,progress++,
    594           source->extent.height);
    595         if (proceed == MagickFalse)
    596           status=MagickFalse;
    597       }
    598   }
    599   return(status);
    600 }
    601 
    602 /*
    604 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    605 %                                                                             %
    606 %                                                                             %
    607 %                                                                             %
    608 %   G e t W a n d V i e w P i x e l s                                         %
    609 %                                                                             %
    610 %                                                                             %
    611 %                                                                             %
    612 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    613 %
    614 %  GetWandViewPixels() returns the wand view pixel_wands.
    615 %
    616 %  The format of the GetWandViewPixels method is:
    617 %
    618 %      PixelWand *GetWandViewPixels(const WandView *wand_view)
    619 %
    620 %  A description of each parameter follows:
    621 %
    622 %    o wand_view: the wand view.
    623 %
    624 */
    625 WandExport PixelWand **GetWandViewPixels(const WandView *wand_view)
    626 {
    627   const int
    628     id = GetOpenMPThreadId();
    629 
    630   assert(wand_view != (WandView *) NULL);
    631   assert(wand_view->signature == MagickWandSignature);
    632   return(wand_view->pixel_wands[id]);
    633 }
    634 
    635 /*
    637 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    638 %                                                                             %
    639 %                                                                             %
    640 %                                                                             %
    641 %   G e t W a n d V i e w W a n d                                             %
    642 %                                                                             %
    643 %                                                                             %
    644 %                                                                             %
    645 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    646 %
    647 %  GetWandViewWand() returns the magick wand associated with the wand view.
    648 %
    649 %  The format of the GetWandViewWand method is:
    650 %
    651 %      MagickWand *GetWandViewWand(const WandView *wand_view)
    652 %
    653 %  A description of each parameter follows:
    654 %
    655 %    o wand_view: the wand view.
    656 %
    657 */
    658 WandExport MagickWand *GetWandViewWand(const WandView *wand_view)
    659 {
    660   assert(wand_view != (WandView *) NULL);
    661   assert(wand_view->signature == MagickWandSignature);
    662   return(wand_view->wand);
    663 }
    664 
    665 /*
    667 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    668 %                                                                             %
    669 %                                                                             %
    670 %                                                                             %
    671 %   I s W a n d V i e w                                                       %
    672 %                                                                             %
    673 %                                                                             %
    674 %                                                                             %
    675 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    676 %
    677 %  IsWandView() returns MagickTrue if the the parameter is verified as a wand
    678 %  view object.
    679 %
    680 %  The format of the IsWandView method is:
    681 %
    682 %      MagickBooleanType IsWandView(const WandView *wand_view)
    683 %
    684 %  A description of each parameter follows:
    685 %
    686 %    o wand_view: the wand view.
    687 %
    688 */
    689 WandExport MagickBooleanType IsWandView(const WandView *wand_view)
    690 {
    691   size_t
    692     length;
    693 
    694   if (wand_view == (const WandView *) NULL)
    695     return(MagickFalse);
    696   if (wand_view->signature != MagickWandSignature)
    697     return(MagickFalse);
    698   length=strlen(WandViewId);
    699   if (LocaleNCompare(wand_view->name,WandViewId,length) != 0)
    700     return(MagickFalse);
    701   return(MagickTrue);
    702 }
    703 
    704 /*
    706 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    707 %                                                                             %
    708 %                                                                             %
    709 %                                                                             %
    710 %   N e w W a n d V i e w                                                     %
    711 %                                                                             %
    712 %                                                                             %
    713 %                                                                             %
    714 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    715 %
    716 %  NewWandView() returns a wand view required for all other methods in the
    717 %  Wand View API.
    718 %
    719 %  The format of the NewWandView method is:
    720 %
    721 %      WandView *NewWandView(MagickWand *wand)
    722 %
    723 %  A description of each parameter follows:
    724 %
    725 %    o wand: the wand.
    726 %
    727 */
    728 
    729 static PixelWand ***AcquirePixelsThreadSet(const size_t number_wands)
    730 {
    731   PixelWand
    732     ***pixel_wands;
    733 
    734   register ssize_t
    735     i;
    736 
    737   size_t
    738     number_threads;
    739 
    740   number_threads=GetOpenMPMaximumThreads();
    741   pixel_wands=(PixelWand ***) AcquireQuantumMemory(number_threads,
    742     sizeof(*pixel_wands));
    743   if (pixel_wands == (PixelWand ***) NULL)
    744     return((PixelWand ***) NULL);
    745   (void) ResetMagickMemory(pixel_wands,0,number_threads*sizeof(*pixel_wands));
    746   for (i=0; i < (ssize_t) number_threads; i++)
    747   {
    748     pixel_wands[i]=NewPixelWands(number_wands);
    749     if (pixel_wands[i] == (PixelWand **) NULL)
    750       return(DestroyPixelsThreadSet(pixel_wands,number_wands));
    751   }
    752   return(pixel_wands);
    753 }
    754 
    755 WandExport WandView *NewWandView(MagickWand *wand)
    756 {
    757   ExceptionInfo
    758     *exception;
    759 
    760   WandView
    761     *wand_view;
    762 
    763   assert(wand != (MagickWand *) NULL);
    764   assert(wand->signature == MagickWandSignature);
    765   wand_view=(WandView *) AcquireMagickMemory(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) FormatLocaleString(wand_view->name,MagickPathExtent,"%s-%.20g",
    772     WandViewId,(double) wand_view->id);
    773   wand_view->description=ConstantString("WandView");
    774   wand_view->wand=wand;
    775   exception=AcquireExceptionInfo();
    776   wand_view->view=AcquireVirtualCacheView(wand_view->wand->images,exception);
    777   wand_view->extent.width=wand->images->columns;
    778   wand_view->extent.height=wand->images->rows;
    779   wand_view->pixel_wands=AcquirePixelsThreadSet(wand_view->extent.width);
    780   wand_view->exception=exception;
    781   if (wand_view->pixel_wands == (PixelWand ***) NULL)
    782     ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
    783       GetExceptionMessage(errno));
    784   wand_view->debug=IsEventLogging();
    785   wand_view->signature=MagickWandSignature;
    786   return(wand_view);
    787 }
    788 
    789 /*
    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   ExceptionInfo
    821     *exception;
    822 
    823   WandView
    824     *wand_view;
    825 
    826   assert(wand != (MagickWand *) NULL);
    827   assert(wand->signature == MagickWandSignature);
    828   wand_view=(WandView *) AcquireMagickMemory(sizeof(*wand_view));
    829   if (wand_view == (WandView *) NULL)
    830     ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
    831       GetExceptionMessage(errno));
    832   (void) ResetMagickMemory(wand_view,0,sizeof(*wand_view));
    833   wand_view->id=AcquireWandId();
    834   (void) FormatLocaleString(wand_view->name,MagickPathExtent,"%s-%.20g",
    835     WandViewId,(double) wand_view->id);
    836   wand_view->description=ConstantString("WandView");
    837   exception=AcquireExceptionInfo();
    838   wand_view->view=AcquireVirtualCacheView(wand_view->wand->images,exception);
    839   wand_view->wand=wand;
    840   wand_view->extent.width=width;
    841   wand_view->extent.height=height;
    842   wand_view->extent.x=x;
    843   wand_view->extent.y=y;
    844   wand_view->exception=exception;
    845   wand_view->pixel_wands=AcquirePixelsThreadSet(wand_view->extent.width);
    846   if (wand_view->pixel_wands == (PixelWand ***) NULL)
    847     ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
    848       GetExceptionMessage(errno));
    849   wand_view->debug=IsEventLogging();
    850   wand_view->signature=MagickWandSignature;
    851   return(wand_view);
    852 }
    853 
    854 /*
    856 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    857 %                                                                             %
    858 %                                                                             %
    859 %                                                                             %
    860 %   S e t W a n d V i e w D e s c r i p t i o n                               %
    861 %                                                                             %
    862 %                                                                             %
    863 %                                                                             %
    864 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    865 %
    866 %  SetWandViewDescription() associates a description with an image view.
    867 %
    868 %  The format of the SetWandViewDescription method is:
    869 %
    870 %      void SetWandViewDescription(WandView *image_view,const char *description)
    871 %
    872 %  A description of each parameter follows:
    873 %
    874 %    o wand_view: the wand view.
    875 %
    876 %    o description: the wand view description.
    877 %
    878 */
    879 MagickExport void SetWandViewDescription(WandView *wand_view,
    880   const char *description)
    881 {
    882   assert(wand_view != (WandView *) NULL);
    883   assert(wand_view->signature == MagickWandSignature);
    884   wand_view->description=ConstantString(description);
    885 }
    886 
    887 /*
    889 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    890 %                                                                             %
    891 %                                                                             %
    892 %                                                                             %
    893 %   S e t W a n d V i e w I t e r a t o r                                     %
    894 %                                                                             %
    895 %                                                                             %
    896 %                                                                             %
    897 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    898 %
    899 %  SetWandViewIterator() iterates over the wand view in parallel and calls
    900 %  your set method for each scanline of the view.  The pixel extent is
    901 %  confined to the image canvas-- that is no negative offsets or widths or
    902 %  heights that exceed the image dimension.  The pixels are initiallly
    903 %  undefined and any settings you make in the callback method are automagically
    904 %  synced back to your image.
    905 %
    906 %  The callback signature is:
    907 %
    908 %      MagickBooleanType SetImageViewMethod(ImageView *destination,
    909 %        const ssize_t y,const int thread_id,void *context)
    910 %
    911 %  Use this pragma if the view is not single threaded:
    912 %
    913 %    #pragma omp critical
    914 %
    915 %  to define a section of code in your callback set method that must be
    916 %  executed by a single thread at a time.
    917 %
    918 %  The format of the SetWandViewIterator method is:
    919 %
    920 %      MagickBooleanType SetWandViewIterator(WandView *destination,
    921 %        SetWandViewMethod set,void *context)
    922 %
    923 %  A description of each parameter follows:
    924 %
    925 %    o destination: the wand view.
    926 %
    927 %    o set: the set callback method.
    928 %
    929 %    o context: the user defined context.
    930 %
    931 */
    932 WandExport MagickBooleanType SetWandViewIterator(WandView *destination,
    933   SetWandViewMethod set,void *context)
    934 {
    935   Image
    936     *destination_image;
    937 
    938   MagickBooleanType
    939     status;
    940 
    941   MagickOffsetType
    942     progress;
    943 
    944 #if defined(MAGICKCORE_OPENMP_SUPPORT)
    945   size_t
    946     height;
    947 #endif
    948 
    949   ssize_t
    950     y;
    951 
    952   assert(destination != (WandView *) NULL);
    953   assert(destination->signature == MagickWandSignature);
    954   if (set == (SetWandViewMethod) NULL)
    955     return(MagickFalse);
    956   destination_image=destination->wand->images;
    957   status=SetImageStorageClass(destination_image,DirectClass,
    958     destination->exception);
    959   if (status == MagickFalse)
    960     return(MagickFalse);
    961   status=MagickTrue;
    962   progress=0;
    963 #if defined(MAGICKCORE_OPENMP_SUPPORT)
    964   height=destination->extent.height-destination->extent.y;
    965   #pragma omp parallel for schedule(static,4) shared(progress,status) \
    966     magick_threads(destination_image,destination_image,height,1)
    967 #endif
    968   for (y=destination->extent.y; y < (ssize_t) destination->extent.height; y++)
    969   {
    970     const int
    971       id = GetOpenMPThreadId();
    972 
    973     MagickBooleanType
    974       sync;
    975 
    976     register ssize_t
    977       x;
    978 
    979     register Quantum
    980       *magick_restrict pixels;
    981 
    982     if (status == MagickFalse)
    983       continue;
    984     pixels=GetCacheViewAuthenticPixels(destination->view,destination->extent.x,
    985       y,destination->extent.width,1,destination->exception);
    986     if (pixels == (Quantum *) NULL)
    987       {
    988         status=MagickFalse;
    989         continue;
    990       }
    991     if (set(destination,y,id,context) == MagickFalse)
    992       status=MagickFalse;
    993     for (x=0; x < (ssize_t) destination->extent.width; x++)
    994     {
    995       PixelGetQuantumPixel(destination->image,destination->pixel_wands[id][x],
    996         pixels);
    997       pixels+=GetPixelChannels(destination->image);
    998     }
    999     sync=SyncCacheViewAuthenticPixels(destination->view,destination->exception);
   1000     if (sync == MagickFalse)
   1001       status=MagickFalse;
   1002     if (destination_image->progress_monitor != (MagickProgressMonitor) NULL)
   1003       {
   1004         MagickBooleanType
   1005           proceed;
   1006 
   1007 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   1008         #pragma omp critical (MagickWand_SetWandViewIterator)
   1009 #endif
   1010         proceed=SetImageProgress(destination_image,destination->description,
   1011           progress++,destination->extent.height);
   1012         if (proceed == MagickFalse)
   1013           status=MagickFalse;
   1014       }
   1015   }
   1016   return(status);
   1017 }
   1018 
   1019 /*
   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   Image
   1072     *destination_image,
   1073     *source_image;
   1074 
   1075   MagickBooleanType
   1076     status;
   1077 
   1078   MagickOffsetType
   1079     progress;
   1080 
   1081 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   1082   size_t
   1083     height;
   1084 #endif
   1085 
   1086   ssize_t
   1087     y;
   1088 
   1089   assert(source != (WandView *) NULL);
   1090   assert(source->signature == MagickWandSignature);
   1091   if (transfer == (TransferWandViewMethod) NULL)
   1092     return(MagickFalse);
   1093   source_image=source->wand->images;
   1094   destination_image=destination->wand->images;
   1095   status=SetImageStorageClass(destination_image,DirectClass,
   1096     destination->exception);
   1097   if (status == MagickFalse)
   1098     return(MagickFalse);
   1099   status=MagickTrue;
   1100   progress=0;
   1101 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   1102   height=source->extent.height-source->extent.y;
   1103   #pragma omp parallel for schedule(static,4) shared(progress,status) \
   1104     magick_threads(source_image,destination_image,height,1)
   1105 #endif
   1106   for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
   1107   {
   1108     const int
   1109       id = GetOpenMPThreadId();
   1110 
   1111     MagickBooleanType
   1112       sync;
   1113 
   1114     register const Quantum
   1115       *magick_restrict pixels;
   1116 
   1117     register ssize_t
   1118       x;
   1119 
   1120     register Quantum
   1121       *magick_restrict destination_pixels;
   1122 
   1123     if (status == MagickFalse)
   1124       continue;
   1125     pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y,
   1126       source->extent.width,1,source->exception);
   1127     if (pixels == (const Quantum *) NULL)
   1128       {
   1129         status=MagickFalse;
   1130         continue;
   1131       }
   1132     for (x=0; x < (ssize_t) source->extent.width; x++)
   1133     {
   1134       PixelSetQuantumPixel(source->image,pixels,source->pixel_wands[id][x]);
   1135       pixels+=GetPixelChannels(source->image);
   1136     }
   1137     destination_pixels=GetCacheViewAuthenticPixels(destination->view,
   1138       destination->extent.x,y,destination->extent.width,1,
   1139       destination->exception);
   1140     if (destination_pixels == (Quantum *) NULL)
   1141       {
   1142         status=MagickFalse;
   1143         continue;
   1144       }
   1145     for (x=0; x < (ssize_t) destination->extent.width; x++)
   1146     {
   1147       PixelSetQuantumPixel(destination->image,destination_pixels,
   1148         destination->pixel_wands[id][x]);
   1149       destination_pixels+=GetPixelChannels(destination->image);
   1150     }
   1151     if (transfer(source,destination,y,id,context) == MagickFalse)
   1152       status=MagickFalse;
   1153     destination_pixels=GetCacheViewAuthenticPixels(destination->view,
   1154       destination->extent.x,y,destination->extent.width,1,
   1155       destination->exception);
   1156     for (x=0; x < (ssize_t) destination->extent.width; x++)
   1157     {
   1158       PixelGetQuantumPixel(destination->image,destination->pixel_wands[id][x],
   1159         destination_pixels);
   1160       destination_pixels+=GetPixelChannels(destination->image);
   1161     }
   1162     sync=SyncCacheViewAuthenticPixels(destination->view,destination->exception);
   1163     if (sync == MagickFalse)
   1164       status=MagickFalse;
   1165     if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
   1166       {
   1167         MagickBooleanType
   1168           proceed;
   1169 
   1170 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   1171         #pragma omp critical (MagickWand_TransferWandViewIterator)
   1172 #endif
   1173         proceed=SetImageProgress(source_image,source->description,progress++,
   1174           source->extent.height);
   1175         if (proceed == MagickFalse)
   1176           status=MagickFalse;
   1177       }
   1178   }
   1179   return(status);
   1180 }
   1181 
   1182 /*
   1184 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1185 %                                                                             %
   1186 %                                                                             %
   1187 %                                                                             %
   1188 %   U p d a t e W a n d V i e w I t e r a t o r                               %
   1189 %                                                                             %
   1190 %                                                                             %
   1191 %                                                                             %
   1192 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1193 %
   1194 %  UpdateWandViewIterator() iterates over the wand view in parallel and calls
   1195 %  your update method for each scanline of the view.  The pixel extent is
   1196 %  confined to the image canvas-- that is no negative offsets or widths or
   1197 %  heights that exceed the image dimension are permitted.  Updates to pixels
   1198 %  in your callback are automagically synced back to the image.
   1199 %
   1200 %  The callback signature is:
   1201 %
   1202 %      MagickBooleanType UpdateImageViewMethod(WandView *source,const ssize_t y,
   1203 %        const int thread_id,void *context)
   1204 %
   1205 %  Use this pragma if the view is not single threaded:
   1206 %
   1207 %    #pragma omp critical
   1208 %
   1209 %  to define a section of code in your callback update method that must be
   1210 %  executed by a single thread at a time.
   1211 %
   1212 %  The format of the UpdateWandViewIterator method is:
   1213 %
   1214 %      MagickBooleanType UpdateWandViewIterator(WandView *source,
   1215 %        UpdateWandViewMethod update,void *context)
   1216 %
   1217 %  A description of each parameter follows:
   1218 %
   1219 %    o source: the source wand view.
   1220 %
   1221 %    o update: the update callback method.
   1222 %
   1223 %    o context: the user defined context.
   1224 %
   1225 */
   1226 WandExport MagickBooleanType UpdateWandViewIterator(WandView *source,
   1227   UpdateWandViewMethod update,void *context)
   1228 {
   1229   Image
   1230     *source_image;
   1231 
   1232   MagickBooleanType
   1233     status;
   1234 
   1235   MagickOffsetType
   1236     progress;
   1237 
   1238 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   1239   size_t
   1240     height;
   1241 #endif
   1242 
   1243   ssize_t
   1244     y;
   1245 
   1246   assert(source != (WandView *) NULL);
   1247   assert(source->signature == MagickWandSignature);
   1248   if (update == (UpdateWandViewMethod) NULL)
   1249     return(MagickFalse);
   1250   source_image=source->wand->images;
   1251   status=SetImageStorageClass(source_image,DirectClass,source->exception);
   1252   if (status == MagickFalse)
   1253     return(MagickFalse);
   1254   status=MagickTrue;
   1255   progress=0;
   1256 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   1257   height=source->extent.height-source->extent.y;
   1258   #pragma omp parallel for schedule(static,4) shared(progress,status) \
   1259     magick_threads(source_image,source_image,height,1)
   1260 #endif
   1261   for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
   1262   {
   1263     const int
   1264       id = GetOpenMPThreadId();
   1265 
   1266     MagickBooleanType
   1267       sync;
   1268 
   1269     register ssize_t
   1270       x;
   1271 
   1272     register Quantum
   1273       *magick_restrict pixels;
   1274 
   1275     if (status == MagickFalse)
   1276       continue;
   1277     pixels=GetCacheViewAuthenticPixels(source->view,source->extent.x,y,
   1278       source->extent.width,1,source->exception);
   1279     if (pixels == (Quantum *) NULL)
   1280       {
   1281         status=MagickFalse;
   1282         continue;
   1283       }
   1284     for (x=0; x < (ssize_t) source->extent.width; x++)
   1285     {
   1286       PixelSetQuantumPixel(source->image,pixels,source->pixel_wands[id][x]);
   1287       pixels+=GetPixelChannels(source->image);
   1288     }
   1289     if (update(source,y,id,context) == MagickFalse)
   1290       status=MagickFalse;
   1291     for (x=0; x < (ssize_t) source->extent.width; x++)
   1292     {
   1293       PixelGetQuantumPixel(source->image,source->pixel_wands[id][x],pixels);
   1294       pixels+=GetPixelChannels(source->image);
   1295     }
   1296     sync=SyncCacheViewAuthenticPixels(source->view,source->exception);
   1297     if (sync == MagickFalse)
   1298       status=MagickFalse;
   1299     if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
   1300       {
   1301         MagickBooleanType
   1302           proceed;
   1303 
   1304 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   1305         #pragma omp critical (MagickWand_UpdateWandViewIterator)
   1306 #endif
   1307         proceed=SetImageProgress(source_image,source->description,progress++,
   1308           source->extent.height);
   1309         if (proceed == MagickFalse)
   1310           status=MagickFalse;
   1311       }
   1312   }
   1313   return(status);
   1314 }
   1315