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