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