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