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