]> granicus.if.org Git - imagemagick/blob - MagickWand/wand-view.c
Update copyright years
[imagemagick] / MagickWand / wand-view.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                        W   W   AAA   N   N  DDDD                            %
6 %                        W   W  A   A  NN  N  D   D                           %
7 %                        W W W  AAAAA  N N N  D   D                           %
8 %                        WW WW  A   A  N  NN  D   D                           %
9 %                        W   W  A   A  N   N  DDDD                            %
10 %                                                                             %
11 %                        V   V  IIIII  EEEEE  W   W                           %
12 %                        V   V    I    E      W   W                           %
13 %                        V   V    I    EEE    W W W                           %
14 %                         V V     I    E      WW WW                           %
15 %                          V    IIIII  EEEEE  W   W                           %
16 %                                                                             %
17 %                                                                             %
18 %                        MagickWand Wand View Methods                         %
19 %                                                                             %
20 %                              Software Design                                %
21 %                                   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 \f
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 \f
59 /*
60   Typedef declarations.
61 */
62 struct _WandView
63 {
64   size_t
65     id;
66
67   char
68     name[MagickPathExtent],
69     *description;
70
71   RectangleInfo
72     extent;
73
74   MagickWand
75     *wand;
76
77   Image
78     *image;
79
80   CacheView
81     *view;
82
83   PixelWand
84     ***pixel_wands;
85
86   ExceptionInfo
87     *exception;
88
89   MagickBooleanType
90     debug;
91
92   size_t
93     signature;
94 };
95 \f
96 /*
97 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
98 %                                                                             %
99 %                                                                             %
100 %                                                                             %
101 %   C l o n e W a n d V i e w                                                 %
102 %                                                                             %
103 %                                                                             %
104 %                                                                             %
105 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
106 %
107 %  CloneWandView() makes a copy of the specified wand view.
108 %
109 %  The format of the CloneWandView method is:
110 %
111 %      WandView *CloneWandView(const WandView *wand_view)
112 %
113 %  A description of each parameter follows:
114 %
115 %    o wand_view: the wand view.
116 %
117 */
118 WandExport WandView *CloneWandView(const WandView *wand_view)
119 {
120   WandView
121     *clone_view;
122
123   register ssize_t
124     i;
125
126   assert(wand_view != (WandView *) NULL);
127   assert(wand_view->signature == 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 \f
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
178 static PixelWand ***DestroyPixelsThreadSet(PixelWand ***pixel_wands,
179   const size_t number_wands)
180 {
181   register ssize_t
182     i;
183
184   assert(pixel_wands != (PixelWand ***) NULL);
185   for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
186     if (pixel_wands[i] != (PixelWand **) NULL)
187       pixel_wands[i]=DestroyPixelWands(pixel_wands[i],number_wands);
188   pixel_wands=(PixelWand ***) RelinquishMagickMemory(pixel_wands);
189   return(pixel_wands);
190 }
191
192 WandExport WandView *DestroyWandView(WandView *wand_view)
193 {
194   assert(wand_view != (WandView *) NULL);
195   assert(wand_view->signature == MagickWandSignature);
196   wand_view->pixel_wands=DestroyPixelsThreadSet(wand_view->pixel_wands,
197     wand_view->extent.width);
198   wand_view->image=DestroyImage(wand_view->image);
199   wand_view->view=DestroyCacheView(wand_view->view);
200   wand_view->exception=DestroyExceptionInfo(wand_view->exception);
201   wand_view->signature=(~MagickWandSignature);
202   RelinquishWandId(wand_view->id);
203   wand_view=(WandView *) RelinquishMagickMemory(wand_view);
204   return(wand_view);
205 }
206 \f
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 */
258 WandExport MagickBooleanType DuplexTransferWandViewIterator(WandView *source,
259   WandView *duplex,WandView *destination,DuplexTransferWandViewMethod transfer,
260   void *context)
261 {
262   Image
263     *destination_image,
264     *source_image;
265
266   MagickBooleanType
267     status;
268
269   MagickOffsetType
270     progress;
271
272 #if defined(MAGICKCORE_OPENMP_SUPPORT)
273   size_t
274     height;
275 #endif
276
277   ssize_t
278     y;
279
280   assert(source != (WandView *) NULL);
281   assert(source->signature == MagickWandSignature);
282   if (transfer == (DuplexTransferWandViewMethod) NULL)
283     return(MagickFalse);
284   source_image=source->wand->images;
285   destination_image=destination->wand->images;
286   status=SetImageStorageClass(destination_image,DirectClass,
287     destination->exception);
288   if (status == MagickFalse)
289     return(MagickFalse);
290   status=MagickTrue;
291   progress=0;
292 #if defined(MAGICKCORE_OPENMP_SUPPORT)
293   height=source->extent.height-source->extent.y;
294   #pragma omp parallel for schedule(static,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 \f
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 */
413 WandExport 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 \f
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 */
468 WandExport 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 \f
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 */
518 WandExport 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 \f
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 */
616 WandExport 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 \f
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 */
648 WandExport 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 \f
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 */
678 WandExport 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 \f
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
717 static 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
743 WandExport 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 \f
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 */
804 WandExport 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 \f
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 */
865 MagickExport 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 \f
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 */
917 WandExport 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 \f
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 */
1052 WandExport 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 \f
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 */
1209 WandExport 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 }