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