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-2021 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 */
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
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 */
CloneWandView(const WandView * wand_view)118 WandExport WandView *CloneWandView(const WandView *wand_view)
119 {
120 WandView
121 *clone_view;
122
123 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 *) 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
DestroyPixelsThreadSet(PixelWand *** pixel_wands,const size_t number_wands)175 static PixelWand ***DestroyPixelsThreadSet(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
DestroyWandView(WandView * wand_view)189 WandExport WandView *DestroyWandView(WandView *wand_view)
190 {
191 assert(wand_view != (WandView *) NULL);
192 assert(wand_view->signature == MagickWandSignature);
193 wand_view->pixel_wands=DestroyPixelsThreadSet(wand_view->pixel_wands,
194 wand_view->extent.width);
195 wand_view->image=DestroyImage(wand_view->image);
196 wand_view->view=DestroyCacheView(wand_view->view);
197 wand_view->exception=DestroyExceptionInfo(wand_view->exception);
198 wand_view->signature=(~MagickWandSignature);
199 RelinquishWandId(wand_view->id);
200 wand_view=(WandView *) RelinquishMagickMemory(wand_view);
201 return(wand_view);
202 }
203
204 /*
205 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
206 % %
207 % %
208 % %
209 % 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 %
210 % %
211 % %
212 % %
213 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
214 %
215 % DuplexTransferWandViewIterator() iterates over three wand views in
216 % parallel and calls your transfer method for each scanline of the view. The
217 % source and duplex pixel extent is not confined to the image canvas-- that is
218 % you can include negative offsets or widths or heights that exceed the image
219 % dimension. However, the destination wand view is confined to the image
220 % canvas-- that is no negative offsets or widths or heights that exceed the
221 % image dimension are permitted.
222 %
223 % The callback signature is:
224 %
225 % MagickBooleanType DuplexTransferImageViewMethod(const WandView *source,
226 % const WandView *duplex,WandView *destination,const ssize_t y,
227 % const int thread_id,void *context)
228 %
229 % Use this pragma if the view is not single threaded:
230 %
231 % #pragma omp critical
232 %
233 % to define a section of code in your callback transfer method that must be
234 % executed by a single thread at a time.
235 %
236 % The format of the DuplexTransferWandViewIterator method is:
237 %
238 % MagickBooleanType DuplexTransferWandViewIterator(WandView *source,
239 % WandView *duplex,WandView *destination,
240 % DuplexTransferWandViewMethod transfer,void *context)
241 %
242 % A description of each parameter follows:
243 %
244 % o source: the source wand view.
245 %
246 % o duplex: the duplex wand view.
247 %
248 % o destination: the destination wand view.
249 %
250 % o transfer: the transfer callback method.
251 %
252 % o context: the user defined context.
253 %
254 */
DuplexTransferWandViewIterator(WandView * source,WandView * duplex,WandView * destination,DuplexTransferWandViewMethod transfer,void * context)255 WandExport MagickBooleanType DuplexTransferWandViewIterator(WandView *source,
256 WandView *duplex,WandView *destination,DuplexTransferWandViewMethod transfer,
257 void *context)
258 {
259 Image
260 *destination_image,
261 *source_image;
262
263 MagickBooleanType
264 status;
265
266 MagickOffsetType
267 progress;
268
269 #if defined(MAGICKCORE_OPENMP_SUPPORT)
270 size_t
271 height;
272 #endif
273
274 ssize_t
275 y;
276
277 assert(source != (WandView *) NULL);
278 assert(source->signature == MagickWandSignature);
279 if (transfer == (DuplexTransferWandViewMethod) NULL)
280 return(MagickFalse);
281 source_image=source->wand->images;
282 destination_image=destination->wand->images;
283 status=SetImageStorageClass(destination_image,DirectClass,
284 destination->exception);
285 if (status == MagickFalse)
286 return(MagickFalse);
287 status=MagickTrue;
288 progress=0;
289 #if defined(MAGICKCORE_OPENMP_SUPPORT)
290 height=source->extent.height-source->extent.y;
291 #pragma omp parallel for schedule(static) shared(progress,status) \
292 magick_number_threads(source_image,destination_image,height,1)
293 #endif
294 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
295 {
296 const int
297 id = GetOpenMPThreadId();
298
299 MagickBooleanType
300 sync;
301
302 const Quantum
303 *magick_restrict duplex_pixels,
304 *magick_restrict pixels;
305
306 ssize_t
307 x;
308
309 Quantum
310 *magick_restrict destination_pixels;
311
312 if (status == MagickFalse)
313 continue;
314 pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y,
315 source->extent.width,1,source->exception);
316 if (pixels == (const Quantum *) NULL)
317 {
318 status=MagickFalse;
319 continue;
320 }
321 for (x=0; x < (ssize_t) source->extent.width; x++)
322 {
323 PixelSetQuantumPixel(source->image,pixels,source->pixel_wands[id][x]);
324 pixels+=GetPixelChannels(source->image);
325 }
326 duplex_pixels=GetCacheViewVirtualPixels(duplex->view,duplex->extent.x,y,
327 duplex->extent.width,1,duplex->exception);
328 if (duplex_pixels == (const Quantum *) NULL)
329 {
330 status=MagickFalse;
331 continue;
332 }
333 for (x=0; x < (ssize_t) duplex->extent.width; x++)
334 {
335 PixelSetQuantumPixel(duplex->image,duplex_pixels,
336 duplex->pixel_wands[id][x]);
337 duplex_pixels+=GetPixelChannels(duplex->image);
338 }
339 destination_pixels=GetCacheViewAuthenticPixels(destination->view,
340 destination->extent.x,y,destination->extent.width,1,
341 destination->exception);
342 if (destination_pixels == (Quantum *) NULL)
343 {
344 status=MagickFalse;
345 continue;
346 }
347 for (x=0; x < (ssize_t) destination->extent.width; x++)
348 {
349 PixelSetQuantumPixel(destination->image,destination_pixels,
350 destination->pixel_wands[id][x]);
351 destination_pixels+=GetPixelChannels(destination->image);
352 }
353 if (transfer(source,duplex,destination,y,id,context) == MagickFalse)
354 status=MagickFalse;
355 destination_pixels=GetCacheViewAuthenticPixels(destination->view,
356 destination->extent.x,y,destination->extent.width,1,
357 destination->exception);
358 for (x=0; x < (ssize_t) destination->extent.width; x++)
359 {
360 PixelGetQuantumPixel(destination->image,destination->pixel_wands[id][x],
361 destination_pixels);
362 destination_pixels+=GetPixelChannels(destination->image);
363 }
364 sync=SyncCacheViewAuthenticPixels(destination->view,destination->exception);
365 if (sync == MagickFalse)
366 status=MagickFalse;
367 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
368 {
369 MagickBooleanType
370 proceed;
371
372 #if defined(MAGICKCORE_OPENMP_SUPPORT)
373 #pragma omp atomic
374 #endif
375 progress++;
376 proceed=SetImageProgress(source_image,source->description,progress,
377 source->extent.height);
378 if (proceed == MagickFalse)
379 status=MagickFalse;
380 }
381 }
382 return(status);
383 }
384
385 /*
386 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
387 % %
388 % %
389 % %
390 % G e t W a n d V i e w E x c e p t i o n %
391 % %
392 % %
393 % %
394 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
395 %
396 % GetWandViewException() returns the severity, reason, and description of any
397 % error that occurs when utilizing a wand view.
398 %
399 % The format of the GetWandViewException method is:
400 %
401 % char *GetWandViewException(const WandView *wand_view,
402 % ExceptionType *severity)
403 %
404 % A description of each parameter follows:
405 %
406 % o wand_view: the pixel wand_view.
407 %
408 % o severity: the severity of the error is returned here.
409 %
410 */
GetWandViewException(const WandView * wand_view,ExceptionType * severity)411 WandExport char *GetWandViewException(const WandView *wand_view,
412 ExceptionType *severity)
413 {
414 char
415 *description;
416
417 assert(wand_view != (const WandView *) NULL);
418 assert(wand_view->signature == MagickWandSignature);
419 if (wand_view->debug != MagickFalse)
420 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",wand_view->name);
421 assert(severity != (ExceptionType *) NULL);
422 *severity=wand_view->exception->severity;
423 description=(char *) AcquireQuantumMemory(2UL*MagickPathExtent,
424 sizeof(*description));
425 if (description == (char *) NULL)
426 ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
427 wand_view->name);
428 *description='\0';
429 if (wand_view->exception->reason != (char *) NULL)
430 (void) CopyMagickString(description,GetLocaleExceptionMessage(
431 wand_view->exception->severity,wand_view->exception->reason),
432 MagickPathExtent);
433 if (wand_view->exception->description != (char *) NULL)
434 {
435 (void) ConcatenateMagickString(description," (",MagickPathExtent);
436 (void) ConcatenateMagickString(description,GetLocaleExceptionMessage(
437 wand_view->exception->severity,wand_view->exception->description),
438 MagickPathExtent);
439 (void) ConcatenateMagickString(description,")",MagickPathExtent);
440 }
441 return(description);
442 }
443
444 /*
445 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
446 % %
447 % %
448 % %
449 % G e t W a n d V i e w E x t e n t %
450 % %
451 % %
452 % %
453 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
454 %
455 % GetWandViewExtent() returns the wand view extent.
456 %
457 % The format of the GetWandViewExtent method is:
458 %
459 % RectangleInfo GetWandViewExtent(const WandView *wand_view)
460 %
461 % A description of each parameter follows:
462 %
463 % o wand_view: the wand view.
464 %
465 */
GetWandViewExtent(const WandView * wand_view)466 WandExport RectangleInfo GetWandViewExtent(const WandView *wand_view)
467 {
468 assert(wand_view != (WandView *) NULL);
469 assert(wand_view->signature == MagickWandSignature);
470 return(wand_view->extent);
471 }
472
473 /*
474 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
475 % %
476 % %
477 % %
478 % G e t W a n d V i e w I t e r a t o r %
479 % %
480 % %
481 % %
482 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
483 %
484 % GetWandViewIterator() iterates over the wand view in parallel and calls
485 % your get method for each scanline of the view. The pixel extent is
486 % not confined to the image canvas-- that is you can include negative offsets
487 % or widths or heights that exceed the image dimension. Any updates to
488 % the pixels in your callback are ignored.
489 %
490 % The callback signature is:
491 %
492 % MagickBooleanType GetImageViewMethod(const WandView *source,
493 % const ssize_t y,const int thread_id,void *context)
494 %
495 % Use this pragma if the view is not single threaded:
496 %
497 % #pragma omp critical
498 %
499 % to define a section of code in your callback get method that must be
500 % executed by a single thread at a time.
501 %
502 % The format of the GetWandViewIterator method is:
503 %
504 % MagickBooleanType GetWandViewIterator(WandView *source,
505 % GetWandViewMethod get,void *context)
506 %
507 % A description of each parameter follows:
508 %
509 % o source: the source wand view.
510 %
511 % o get: the get callback method.
512 %
513 % o context: the user defined context.
514 %
515 */
GetWandViewIterator(WandView * source,GetWandViewMethod get,void * context)516 WandExport MagickBooleanType GetWandViewIterator(WandView *source,
517 GetWandViewMethod get,void *context)
518 {
519 Image
520 *source_image;
521
522 MagickBooleanType
523 status;
524
525 MagickOffsetType
526 progress;
527
528 #if defined(MAGICKCORE_OPENMP_SUPPORT)
529 size_t
530 height;
531 #endif
532
533 ssize_t
534 y;
535
536 assert(source != (WandView *) NULL);
537 assert(source->signature == MagickWandSignature);
538 if (get == (GetWandViewMethod) NULL)
539 return(MagickFalse);
540 source_image=source->wand->images;
541 status=MagickTrue;
542 progress=0;
543 #if defined(MAGICKCORE_OPENMP_SUPPORT)
544 height=source->extent.height-source->extent.y;
545 #pragma omp parallel for schedule(static) shared(progress,status) \
546 magick_number_threads(source_image,source_image,height,1)
547 #endif
548 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
549 {
550 const int
551 id = GetOpenMPThreadId();
552
553 const Quantum
554 *pixels;
555
556 ssize_t
557 x;
558
559 if (status == MagickFalse)
560 continue;
561 pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y,
562 source->extent.width,1,source->exception);
563 if (pixels == (const Quantum *) NULL)
564 {
565 status=MagickFalse;
566 continue;
567 }
568 for (x=0; x < (ssize_t) source->extent.width; x++)
569 {
570 PixelSetQuantumPixel(source->image,pixels,source->pixel_wands[id][x]);
571 pixels+=GetPixelChannels(source->image);
572 }
573 if (get(source,y,id,context) == MagickFalse)
574 status=MagickFalse;
575 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
576 {
577 MagickBooleanType
578 proceed;
579
580 #if defined(MAGICKCORE_OPENMP_SUPPORT)
581 #pragma omp atomic
582 #endif
583 progress++;
584 proceed=SetImageProgress(source_image,source->description,progress,
585 source->extent.height);
586 if (proceed == MagickFalse)
587 status=MagickFalse;
588 }
589 }
590 return(status);
591 }
592
593 /*
594 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
595 % %
596 % %
597 % %
598 % G e t W a n d V i e w P i x e l s %
599 % %
600 % %
601 % %
602 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
603 %
604 % GetWandViewPixels() returns the wand view pixel_wands.
605 %
606 % The format of the GetWandViewPixels method is:
607 %
608 % PixelWand *GetWandViewPixels(const WandView *wand_view)
609 %
610 % A description of each parameter follows:
611 %
612 % o wand_view: the wand view.
613 %
614 */
GetWandViewPixels(const WandView * wand_view)615 WandExport PixelWand **GetWandViewPixels(const WandView *wand_view)
616 {
617 const int
618 id = GetOpenMPThreadId();
619
620 assert(wand_view != (WandView *) NULL);
621 assert(wand_view->signature == MagickWandSignature);
622 return(wand_view->pixel_wands[id]);
623 }
624
625 /*
626 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
627 % %
628 % %
629 % %
630 % G e t W a n d V i e w W a n d %
631 % %
632 % %
633 % %
634 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
635 %
636 % GetWandViewWand() returns the magick wand associated with the wand view.
637 %
638 % The format of the GetWandViewWand method is:
639 %
640 % MagickWand *GetWandViewWand(const WandView *wand_view)
641 %
642 % A description of each parameter follows:
643 %
644 % o wand_view: the wand view.
645 %
646 */
GetWandViewWand(const WandView * wand_view)647 WandExport MagickWand *GetWandViewWand(const WandView *wand_view)
648 {
649 assert(wand_view != (WandView *) NULL);
650 assert(wand_view->signature == MagickWandSignature);
651 return(wand_view->wand);
652 }
653
654 /*
655 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
656 % %
657 % %
658 % %
659 % I s W a n d V i e w %
660 % %
661 % %
662 % %
663 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
664 %
665 % IsWandView() returns MagickTrue if the parameter is verified as a wand
666 % view object.
667 %
668 % The format of the IsWandView method is:
669 %
670 % MagickBooleanType IsWandView(const WandView *wand_view)
671 %
672 % A description of each parameter follows:
673 %
674 % o wand_view: the wand view.
675 %
676 */
IsWandView(const WandView * wand_view)677 WandExport MagickBooleanType IsWandView(const WandView *wand_view)
678 {
679 size_t
680 length;
681
682 if (wand_view == (const WandView *) NULL)
683 return(MagickFalse);
684 if (wand_view->signature != MagickWandSignature)
685 return(MagickFalse);
686 length=strlen(WandViewId);
687 if (LocaleNCompare(wand_view->name,WandViewId,length) != 0)
688 return(MagickFalse);
689 return(MagickTrue);
690 }
691
692 /*
693 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
694 % %
695 % %
696 % %
697 % N e w W a n d V i e w %
698 % %
699 % %
700 % %
701 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
702 %
703 % NewWandView() returns a wand view required for all other methods in the
704 % Wand View API.
705 %
706 % The format of the NewWandView method is:
707 %
708 % WandView *NewWandView(MagickWand *wand)
709 %
710 % A description of each parameter follows:
711 %
712 % o wand: the wand.
713 %
714 */
715
AcquirePixelsThreadSet(const size_t number_wands)716 static PixelWand ***AcquirePixelsThreadSet(const size_t number_wands)
717 {
718 PixelWand
719 ***pixel_wands;
720
721 ssize_t
722 i;
723
724 size_t
725 number_threads;
726
727 number_threads=GetOpenMPMaximumThreads();
728 pixel_wands=(PixelWand ***) AcquireQuantumMemory(number_threads,
729 sizeof(*pixel_wands));
730 if (pixel_wands == (PixelWand ***) NULL)
731 return((PixelWand ***) NULL);
732 (void) memset(pixel_wands,0,number_threads*sizeof(*pixel_wands));
733 for (i=0; i < (ssize_t) number_threads; i++)
734 {
735 pixel_wands[i]=NewPixelWands(number_wands);
736 if (pixel_wands[i] == (PixelWand **) NULL)
737 return(DestroyPixelsThreadSet(pixel_wands,number_wands));
738 }
739 return(pixel_wands);
740 }
741
NewWandView(MagickWand * wand)742 WandExport WandView *NewWandView(MagickWand *wand)
743 {
744 ExceptionInfo
745 *exception;
746
747 WandView
748 *wand_view;
749
750 assert(wand != (MagickWand *) NULL);
751 assert(wand->signature == MagickWandSignature);
752 wand_view=(WandView *) AcquireCriticalMemory(sizeof(*wand_view));
753 (void) memset(wand_view,0,sizeof(*wand_view));
754 wand_view->id=AcquireWandId();
755 (void) FormatLocaleString(wand_view->name,MagickPathExtent,"%s-%.20g",
756 WandViewId,(double) wand_view->id);
757 wand_view->description=ConstantString("WandView");
758 wand_view->wand=wand;
759 exception=AcquireExceptionInfo();
760 wand_view->view=AcquireVirtualCacheView(wand_view->wand->images,exception);
761 wand_view->extent.width=wand->images->columns;
762 wand_view->extent.height=wand->images->rows;
763 wand_view->pixel_wands=AcquirePixelsThreadSet(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 */
NewWandViewExtent(MagickWand * wand,const ssize_t x,const ssize_t y,const size_t width,const size_t height)800 WandExport 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
806 WandView
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=AcquirePixelsThreadSet(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 */
SetWandViewDescription(WandView * wand_view,const char * description)858 MagickExport 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 initiallly
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 */
SetWandViewIterator(WandView * destination,SetWandViewMethod set,void * context)910 WandExport 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=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 ssize_t
955 x;
956
957 Quantum
958 *magick_restrict pixels;
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+=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 */
TransferWandViewIterator(WandView * source,WandView * destination,TransferWandViewMethod transfer,void * context)1046 WandExport 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=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 MagickBooleanType
1090 sync;
1091
1092 const Quantum
1093 *magick_restrict pixels;
1094
1095 ssize_t
1096 x;
1097
1098 Quantum
1099 *magick_restrict destination_pixels;
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+=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+=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+=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 */
UpdateWandViewIterator(WandView * source,UpdateWandViewMethod update,void * context)1204 WandExport 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=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 MagickBooleanType
1245 sync;
1246
1247 ssize_t
1248 x;
1249
1250 Quantum
1251 *magick_restrict pixels;
1252
1253 if (status == MagickFalse)
1254 continue;
1255 pixels=GetCacheViewAuthenticPixels(source->view,source->extent.x,y,
1256 source->extent.width,1,source->exception);
1257 if (pixels == (Quantum *) NULL)
1258 {
1259 status=MagickFalse;
1260 continue;
1261 }
1262 for (x=0; x < (ssize_t) source->extent.width; x++)
1263 {
1264 PixelSetQuantumPixel(source->image,pixels,source->pixel_wands[id][x]);
1265 pixels+=GetPixelChannels(source->image);
1266 }
1267 if (update(source,y,id,context) == MagickFalse)
1268 status=MagickFalse;
1269 for (x=0; x < (ssize_t) source->extent.width; x++)
1270 {
1271 PixelGetQuantumPixel(source->image,source->pixel_wands[id][x],pixels);
1272 pixels+=GetPixelChannels(source->image);
1273 }
1274 sync=SyncCacheViewAuthenticPixels(source->view,source->exception);
1275 if (sync == MagickFalse)
1276 status=MagickFalse;
1277 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
1278 {
1279 MagickBooleanType
1280 proceed;
1281
1282 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1283 #pragma omp atomic
1284 #endif
1285 progress++;
1286 proceed=SetImageProgress(source_image,source->description,progress,
1287 source->extent.height);
1288 if (proceed == MagickFalse)
1289 status=MagickFalse;
1290 }
1291 }
1292 return(status);
1293 }
1294