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