MagickCore 6.9.13
Loading...
Searching...
No Matches
image-view.c
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 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*/
58{
59 char
60 *description;
61
63 extent;
64
65 Image
66 *image;
67
69 *view;
70
71 size_t
72 number_threads;
73
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*/
106MagickExport ImageView *CloneImageView(const ImageView *image_view)
107{
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*/
150MagickExport 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*/
214MagickExport MagickBooleanType DuplexTransferImageViewIterator(
215 ImageView *source,ImageView *duplex,ImageView *destination,
216 DuplexTransferImageViewMethod transfer,void *context)
217{
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
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*/
342MagickExport 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*/
372MagickExport 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*/
406MagickExport 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*/
458MagickExport 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*/
487MagickExport 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*/
537MagickExport 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*/
629MagickExport 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*/
659MagickExport 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*/
690MagickExport 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*/
722MagickExport ImageView *NewImageView(Image *image)
723{
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=(GetLogEventMask() & ImageEvent) != 0 ? MagickTrue :
744 MagickFalse;
745 image_view->signature=MagickCoreSignature;
746 return(image_view);
747}
748
749/*
750%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
751% %
752% %
753% %
754% N e w I m a g e V i e w R e g i o n %
755% %
756% %
757% %
758%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
759%
760% NewImageViewRegion() returns a image view required for all other methods
761% in the Image View API.
762%
763% The format of the NewImageViewRegion method is:
764%
765% ImageView *NewImageViewRegion(MagickCore *wand,const ssize_t x,
766% const ssize_t y,const size_t width,const size_t height)
767%
768% A description of each parameter follows:
769%
770% o wand: the magick wand.
771%
772% o x,y,columns,rows: These values define the perimeter of a extent of
773% pixel_wands view.
774%
775*/
776MagickExport ImageView *NewImageViewRegion(Image *image,const ssize_t x,
777 const ssize_t y,const size_t width,const size_t height)
778{
780 *image_view;
781
782 assert(image != (Image *) NULL);
783 assert(image->signature == MagickCoreSignature);
784 image_view=(ImageView *) AcquireMagickMemory(sizeof(*image_view));
785 if (image_view == (ImageView *) NULL)
786 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
787 (void) memset(image_view,0,sizeof(*image_view));
788 image_view->description=ConstantString("ImageView");
789 image_view->exception=AcquireExceptionInfo();
790 image_view->view=AcquireVirtualCacheView(image_view->image,
791 image_view->exception);
792 image_view->image=image;
793 image_view->extent.width=width;
794 image_view->extent.height=height;
795 image_view->extent.x=x;
796 image_view->extent.y=y;
797 image_view->number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
798 image_view->debug=(GetLogEventMask() & ImageEvent) != 0 ? MagickTrue :
799 MagickFalse;
800 image_view->signature=MagickCoreSignature;
801 return(image_view);
802}
803
804/*
805%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
806% %
807% %
808% %
809% S e t I m a g e V i e w D e s c r i p t i o n %
810% %
811% %
812% %
813%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
814%
815% SetImageViewDescription() associates a description with an image view.
816%
817% The format of the SetImageViewDescription method is:
818%
819% void SetImageViewDescription(ImageView *image_view,
820% const char *description)
821%
822% A description of each parameter follows:
823%
824% o image_view: the image view.
825%
826% o description: the image view description.
827%
828*/
829MagickExport void SetImageViewDescription(ImageView *image_view,
830 const char *description)
831{
832 assert(image_view != (ImageView *) NULL);
833 assert(image_view->signature == MagickCoreSignature);
834 image_view->description=ConstantString(description);
835}
836
837/*
838%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
839% %
840% %
841% %
842% S e t I m a g e V i e w I t e r a t o r %
843% %
844% %
845% %
846%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
847%
848% SetImageViewIterator() iterates over the image view in parallel and calls
849% your set method for each scanline of the view. The pixel extent is
850% confined to the image canvas-- that is no negative offsets or widths or
851% heights that exceed the image dimension. The pixels are initially
852% undefined and any settings you make in the callback method are automagically
853% synced back to your image.
854%
855% The callback signature is:
856%
857% MagickBooleanType SetImageViewMethod(ImageView *destination,
858% const ssize_t y,const int thread_id,void *context)
859%
860% Use this pragma if the view is not single threaded:
861%
862% #pragma omp critical
863%
864% to define a section of code in your callback set method that must be
865% executed by a single thread at a time.
866%
867% The format of the SetImageViewIterator method is:
868%
869% MagickBooleanType SetImageViewIterator(ImageView *destination,
870% SetImageViewMethod set,void *context)
871%
872% A description of each parameter follows:
873%
874% o destination: the image view.
875%
876% o set: the set callback method.
877%
878% o context: the user defined context.
879%
880*/
881MagickExport MagickBooleanType SetImageViewIterator(ImageView *destination,
882 SetImageViewMethod set,void *context)
883{
885 *exception;
886
887 Image
888 *destination_image;
889
890 MagickBooleanType
891 status;
892
893 MagickOffsetType
894 progress;
895
896#if defined(MAGICKCORE_OPENMP_SUPPORT)
897 size_t
898 height;
899#endif
900
901 ssize_t
902 y;
903
904 assert(destination != (ImageView *) NULL);
905 assert(destination->signature == MagickCoreSignature);
906 if (set == (SetImageViewMethod) NULL)
907 return(MagickFalse);
908 destination_image=destination->image;
909 if (SetImageStorageClass(destination_image,DirectClass) == MagickFalse)
910 return(MagickFalse);
911 status=MagickTrue;
912 progress=0;
913#if defined(MAGICKCORE_OPENMP_SUPPORT)
914 height=(size_t) (destination->extent.height-destination->extent.y);
915#endif
916 exception=destination->exception;
917#if defined(MAGICKCORE_OPENMP_SUPPORT)
918 #pragma omp parallel for schedule(static) shared(progress,status) \
919 magick_number_threads(destination_image,destination_image,height,1)
920#endif
921 for (y=destination->extent.y; y < (ssize_t) destination->extent.height; y++)
922 {
923 const int
924 id = GetOpenMPThreadId();
925
926 MagickBooleanType
927 sync;
928
930 *magick_restrict pixels;
931
932 if (status == MagickFalse)
933 continue;
934 pixels=GetCacheViewAuthenticPixels(destination->view,destination->extent.x,
935 y,destination->extent.width,1,exception);
936 if (pixels == (PixelPacket *) NULL)
937 {
938 InheritException(destination->exception,GetCacheViewException(
939 destination->view));
940 status=MagickFalse;
941 continue;
942 }
943 if (set(destination,y,id,context) == MagickFalse)
944 status=MagickFalse;
945 sync=SyncCacheViewAuthenticPixels(destination->view,exception);
946 if (sync == MagickFalse)
947 {
948 InheritException(destination->exception,GetCacheViewException(
949 destination->view));
950 status=MagickFalse;
951 }
952 if (destination_image->progress_monitor != (MagickProgressMonitor) NULL)
953 {
954 MagickBooleanType
955 proceed;
956
957#if defined(MAGICKCORE_OPENMP_SUPPORT)
958 #pragma omp atomic
959#endif
960 progress++;
961 proceed=SetImageProgress(destination_image,destination->description,
962 progress,destination->extent.height);
963 if (proceed == MagickFalse)
964 status=MagickFalse;
965 }
966 }
967 return(status);
968}
969
970/*
971%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
972% %
973% %
974% %
975% S e t I m a g e V i e w T h r e a d s %
976% %
977% %
978% %
979%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
980%
981% SetImageViewThreads() sets the number of threads in a thread team.
982%
983% The format of the SetImageViewDescription method is:
984%
985% void SetImageViewThreads(ImageView *image_view,
986% const size_t number_threads)
987%
988% A description of each parameter follows:
989%
990% o image_view: the image view.
991%
992% o number_threads: the number of threads in a thread team.
993%
994*/
995MagickExport void SetImageViewThreads(ImageView *image_view,
996 const size_t number_threads)
997{
998 assert(image_view != (ImageView *) NULL);
999 assert(image_view->signature == MagickCoreSignature);
1000 image_view->number_threads=number_threads;
1001 if (number_threads > (size_t) GetMagickResourceLimit(ThreadResource))
1002 image_view->number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
1003}
1004
1005/*
1006%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1007% %
1008% %
1009% %
1010% 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 %
1011% %
1012% %
1013% %
1014%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1015%
1016% TransferImageViewIterator() iterates over two image views in parallel and
1017% calls your transfer method for each scanline of the view. The source pixel
1018% extent is not confined to the image canvas-- that is you can include
1019% negative offsets or widths or heights that exceed the image dimension.
1020% However, the destination image view is confined to the image canvas-- that
1021% is no negative offsets or widths or heights that exceed the image dimension
1022% are permitted.
1023%
1024% The callback signature is:
1025%
1026% MagickBooleanType TransferImageViewMethod(const ImageView *source,
1027% ImageView *destination,const ssize_t y,const int thread_id,
1028% void *context)
1029%
1030% Use this pragma if the view is not single threaded:
1031%
1032% #pragma omp critical
1033%
1034% to define a section of code in your callback transfer method that must be
1035% executed by a single thread at a time.
1036%
1037% The format of the TransferImageViewIterator method is:
1038%
1039% MagickBooleanType TransferImageViewIterator(ImageView *source,
1040% ImageView *destination,TransferImageViewMethod transfer,void *context)
1041%
1042% A description of each parameter follows:
1043%
1044% o source: the source image view.
1045%
1046% o destination: the destination image view.
1047%
1048% o transfer: the transfer callback method.
1049%
1050% o context: the user defined context.
1051%
1052*/
1053MagickExport MagickBooleanType TransferImageViewIterator(ImageView *source,
1054 ImageView *destination,TransferImageViewMethod transfer,void *context)
1055{
1057 *exception;
1058
1059 Image
1060 *destination_image,
1061 *source_image;
1062
1063 MagickBooleanType
1064 status;
1065
1066 MagickOffsetType
1067 progress;
1068
1069#if defined(MAGICKCORE_OPENMP_SUPPORT)
1070 size_t
1071 height;
1072#endif
1073
1074 ssize_t
1075 y;
1076
1077 assert(source != (ImageView *) NULL);
1078 assert(source->signature == MagickCoreSignature);
1079 if (transfer == (TransferImageViewMethod) NULL)
1080 return(MagickFalse);
1081 source_image=source->image;
1082 destination_image=destination->image;
1083 if (SetImageStorageClass(destination_image,DirectClass) == MagickFalse)
1084 return(MagickFalse);
1085 status=MagickTrue;
1086 progress=0;
1087 exception=destination->exception;
1088#if defined(MAGICKCORE_OPENMP_SUPPORT)
1089 height=(size_t) (source->extent.height-source->extent.y);
1090 #pragma omp parallel for schedule(static) shared(progress,status) \
1091 magick_number_threads(source_image,destination_image,height,1)
1092#endif
1093 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
1094 {
1095 const int
1096 id = GetOpenMPThreadId();
1097
1098 MagickBooleanType
1099 sync;
1100
1101 const PixelPacket
1102 *magick_restrict pixels;
1103
1105 *magick_restrict destination_pixels;
1106
1107 if (status == MagickFalse)
1108 continue;
1109 pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y,
1110 source->extent.width,1,source->exception);
1111 if (pixels == (const PixelPacket *) NULL)
1112 {
1113 status=MagickFalse;
1114 continue;
1115 }
1116 destination_pixels=GetCacheViewAuthenticPixels(destination->view,
1117 destination->extent.x,y,destination->extent.width,1,exception);
1118 if (destination_pixels == (PixelPacket *) NULL)
1119 {
1120 status=MagickFalse;
1121 continue;
1122 }
1123 if (transfer(source,destination,y,id,context) == MagickFalse)
1124 status=MagickFalse;
1125 sync=SyncCacheViewAuthenticPixels(destination->view,exception);
1126 if (sync == MagickFalse)
1127 {
1128 InheritException(destination->exception,GetCacheViewException(
1129 source->view));
1130 status=MagickFalse;
1131 }
1132 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
1133 {
1134 MagickBooleanType
1135 proceed;
1136
1137#if defined(MAGICKCORE_OPENMP_SUPPORT)
1138 #pragma omp atomic
1139#endif
1140 progress++;
1141 proceed=SetImageProgress(source_image,source->description,progress,
1142 source->extent.height);
1143 if (proceed == MagickFalse)
1144 status=MagickFalse;
1145 }
1146 }
1147 return(status);
1148}
1149
1150/*
1151%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1152% %
1153% %
1154% %
1155% U p d a t e I m a g e V i e w I t e r a t o r %
1156% %
1157% %
1158% %
1159%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1160%
1161% UpdateImageViewIterator() iterates over the image view in parallel and calls
1162% your update method for each scanline of the view. The pixel extent is
1163% confined to the image canvas-- that is no negative offsets or widths or
1164% heights that exceed the image dimension are permitted. Updates to pixels
1165% in your callback are automagically synced back to the image.
1166%
1167% The callback signature is:
1168%
1169% MagickBooleanType UpdateImageViewMethod(ImageView *source,
1170% const ssize_t y,const int thread_id,void *context)
1171%
1172% Use this pragma if the view is not single threaded:
1173%
1174% #pragma omp critical
1175%
1176% to define a section of code in your callback update method that must be
1177% executed by a single thread at a time.
1178%
1179% The format of the UpdateImageViewIterator method is:
1180%
1181% MagickBooleanType UpdateImageViewIterator(ImageView *source,
1182% UpdateImageViewMethod update,void *context)
1183%
1184% A description of each parameter follows:
1185%
1186% o source: the source image view.
1187%
1188% o update: the update callback method.
1189%
1190% o context: the user defined context.
1191%
1192*/
1193MagickExport MagickBooleanType UpdateImageViewIterator(ImageView *source,
1194 UpdateImageViewMethod update,void *context)
1195{
1197 *exception;
1198
1199 Image
1200 *source_image;
1201
1202 MagickBooleanType
1203 status;
1204
1205 MagickOffsetType
1206 progress;
1207
1208#if defined(MAGICKCORE_OPENMP_SUPPORT)
1209 size_t
1210 height;
1211#endif
1212
1213 ssize_t
1214 y;
1215
1216 assert(source != (ImageView *) NULL);
1217 assert(source->signature == MagickCoreSignature);
1218 if (update == (UpdateImageViewMethod) NULL)
1219 return(MagickFalse);
1220 source_image=source->image;
1221 if (SetImageStorageClass(source_image,DirectClass) == MagickFalse)
1222 return(MagickFalse);
1223 status=MagickTrue;
1224 progress=0;
1225 exception=source->exception;
1226#if defined(MAGICKCORE_OPENMP_SUPPORT)
1227 height=(size_t) (source->extent.height-source->extent.y);
1228 #pragma omp parallel for schedule(static) shared(progress,status) \
1229 magick_number_threads(source_image,source_image,height,1)
1230#endif
1231 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
1232 {
1233 const int
1234 id = GetOpenMPThreadId();
1235
1237 *magick_restrict pixels;
1238
1239 if (status == MagickFalse)
1240 continue;
1241 pixels=GetCacheViewAuthenticPixels(source->view,source->extent.x,y,
1242 source->extent.width,1,exception);
1243 if (pixels == (PixelPacket *) NULL)
1244 {
1245 InheritException(source->exception,GetCacheViewException(source->view));
1246 status=MagickFalse;
1247 continue;
1248 }
1249 if (update(source,y,id,context) == MagickFalse)
1250 status=MagickFalse;
1251 if (SyncCacheViewAuthenticPixels(source->view,exception) == MagickFalse)
1252 {
1253 InheritException(source->exception,GetCacheViewException(source->view));
1254 status=MagickFalse;
1255 }
1256 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
1257 {
1258 MagickBooleanType
1259 proceed;
1260
1261#if defined(MAGICKCORE_OPENMP_SUPPORT)
1262 #pragma omp atomic
1263#endif
1264 progress++;
1265 proceed=SetImageProgress(source_image,source->description,progress,
1266 source->extent.height);
1267 if (proceed == MagickFalse)
1268 status=MagickFalse;
1269 }
1270 }
1271 return(status);
1272}