2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % TTTTT RRRR AAA N N SSSSS FFFFF OOO RRRR M M %
7 % T R R A A NN N SS F O O R R MM MM %
8 % T RRRR AAAAA N N N SSS FFF O O RRRR M M M %
9 % T R R A A N NN SS F O O R R M M %
10 % T R R A A N N SSSSS F OOO R R M M %
13 % MagickCore Image Transform Methods %
20 % Copyright 1999-2014 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
42 #include "MagickCore/studio.h"
43 #include "MagickCore/attribute.h"
44 #include "MagickCore/cache.h"
45 #include "MagickCore/cache-view.h"
46 #include "MagickCore/color.h"
47 #include "MagickCore/color-private.h"
48 #include "MagickCore/colorspace-private.h"
49 #include "MagickCore/composite.h"
50 #include "MagickCore/distort.h"
51 #include "MagickCore/draw.h"
52 #include "MagickCore/effect.h"
53 #include "MagickCore/exception.h"
54 #include "MagickCore/exception-private.h"
55 #include "MagickCore/geometry.h"
56 #include "MagickCore/image.h"
57 #include "MagickCore/memory_.h"
58 #include "MagickCore/layer.h"
59 #include "MagickCore/list.h"
60 #include "MagickCore/monitor.h"
61 #include "MagickCore/monitor-private.h"
62 #include "MagickCore/pixel-accessor.h"
63 #include "MagickCore/resource_.h"
64 #include "MagickCore/resize.h"
65 #include "MagickCore/statistic.h"
66 #include "MagickCore/string_.h"
67 #include "MagickCore/thread-private.h"
68 #include "MagickCore/transform.h"
71 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
75 % A u t o O r i e n t I m a g e %
79 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
81 % AutoOrientImage() adjusts an image so that its orientation is suitable for
82 % viewing (i.e. top-left orientation).
84 % The format of the AutoOrientImage method is:
86 % Image *AutoOrientImage(const Image *image,
87 % const OrientationType orientation,ExceptionInfo *exception)
89 % A description of each parameter follows:
93 % o orientation: Current image orientation.
95 % o exception: Return any errors or warnings in this structure.
98 MagickExport Image *AutoOrientImage(const Image *image,
99 const OrientationType orientation,ExceptionInfo *exception)
104 assert(image != (const Image *) NULL);
105 assert(image->signature == MagickSignature);
106 assert(exception != (ExceptionInfo *) NULL);
107 assert(exception->signature == MagickSignature);
108 orient_image=(Image *) NULL;
111 case UndefinedOrientation:
112 case TopLeftOrientation:
115 orient_image=CloneImage(image,0,0,MagickTrue,exception);
118 case TopRightOrientation:
120 orient_image=FlopImage(image,exception);
123 case BottomRightOrientation:
125 orient_image=RotateImage(image,180.0,exception);
128 case BottomLeftOrientation:
130 orient_image=FlipImage(image,exception);
133 case LeftTopOrientation:
135 orient_image=TransposeImage(image,exception);
138 case RightTopOrientation:
140 orient_image=RotateImage(image,90.0,exception);
143 case RightBottomOrientation:
145 orient_image=TransverseImage(image,exception);
148 case LeftBottomOrientation:
150 orient_image=RotateImage(image,270.0,exception);
154 if (orient_image != (Image *) NULL)
155 orient_image->orientation=TopLeftOrientation;
156 return(orient_image);
160 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
164 % C h o p I m a g e %
168 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
170 % ChopImage() removes a region of an image and collapses the image to occupy
171 % the removed portion.
173 % The format of the ChopImage method is:
175 % Image *ChopImage(const Image *image,const RectangleInfo *chop_info)
176 % ExceptionInfo *exception)
178 % A description of each parameter follows:
180 % o image: the image.
182 % o chop_info: Define the region of the image to chop.
184 % o exception: return any errors or warnings in this structure.
187 MagickExport Image *ChopImage(const Image *image,const RectangleInfo *chop_info,
188 ExceptionInfo *exception)
190 #define ChopImageTag "Chop/Image"
214 assert(image != (const Image *) NULL);
215 assert(image->signature == MagickSignature);
216 if (image->debug != MagickFalse)
217 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
218 assert(exception != (ExceptionInfo *) NULL);
219 assert(exception->signature == MagickSignature);
220 assert(chop_info != (RectangleInfo *) NULL);
221 if (((chop_info->x+(ssize_t) chop_info->width) < 0) ||
222 ((chop_info->y+(ssize_t) chop_info->height) < 0) ||
223 (chop_info->x > (ssize_t) image->columns) ||
224 (chop_info->y > (ssize_t) image->rows))
225 ThrowImageException(OptionWarning,"GeometryDoesNotContainImage");
227 if ((extent.x+(ssize_t) extent.width) > (ssize_t) image->columns)
228 extent.width=(size_t) ((ssize_t) image->columns-extent.x);
229 if ((extent.y+(ssize_t) extent.height) > (ssize_t) image->rows)
230 extent.height=(size_t) ((ssize_t) image->rows-extent.y);
233 extent.width-=(size_t) (-extent.x);
238 extent.height-=(size_t) (-extent.y);
241 chop_image=CloneImage(image,image->columns-extent.width,image->rows-
242 extent.height,MagickTrue,exception);
243 if (chop_image == (Image *) NULL)
244 return((Image *) NULL);
250 image_view=AcquireVirtualCacheView(image,exception);
251 chop_view=AcquireAuthenticCacheView(chop_image,exception);
252 #if defined(MAGICKCORE_OPENMP_SUPPORT)
253 #pragma omp parallel for schedule(static,4) shared(status) \
254 magick_threads(image,chop_image,1,1)
256 for (y=0; y < (ssize_t) extent.y; y++)
258 register const Quantum
267 if (status == MagickFalse)
269 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
270 q=QueueCacheViewAuthenticPixels(chop_view,0,y,chop_image->columns,1,
272 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
277 for (x=0; x < (ssize_t) image->columns; x++)
279 if ((x < extent.x) || (x >= (ssize_t) (extent.x+extent.width)))
284 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
286 PixelChannel channel=GetPixelChannelChannel(image,i);
287 PixelTrait traits=GetPixelChannelTraits(image,channel);
288 PixelTrait chop_traits=GetPixelChannelTraits(chop_image,channel);
289 if ((traits == UndefinedPixelTrait) ||
290 (chop_traits == UndefinedPixelTrait))
292 SetPixelChannel(chop_image,channel,p[i],q);
294 q+=GetPixelChannels(chop_image);
296 p+=GetPixelChannels(image);
298 if (SyncCacheViewAuthenticPixels(chop_view,exception) == MagickFalse)
300 if (image->progress_monitor != (MagickProgressMonitor) NULL)
305 #if defined(MAGICKCORE_OPENMP_SUPPORT)
306 #pragma omp critical (MagickCore_ChopImage)
308 proceed=SetImageProgress(image,ChopImageTag,progress++,image->rows);
309 if (proceed == MagickFalse)
316 #if defined(MAGICKCORE_OPENMP_SUPPORT)
317 #pragma omp parallel for schedule(static,4) shared(progress,status) \
318 magick_threads(image,chop_image,1,1)
320 for (y=0; y < (ssize_t) (image->rows-(extent.y+extent.height)); y++)
322 register const Quantum
331 if (status == MagickFalse)
333 p=GetCacheViewVirtualPixels(image_view,0,extent.y+extent.height+y,
334 image->columns,1,exception);
335 q=QueueCacheViewAuthenticPixels(chop_view,0,extent.y+y,chop_image->columns,
337 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
342 for (x=0; x < (ssize_t) image->columns; x++)
344 if ((x < extent.x) || (x >= (ssize_t) (extent.x+extent.width)))
349 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
351 PixelChannel channel=GetPixelChannelChannel(image,i);
352 PixelTrait traits=GetPixelChannelTraits(image,channel);
353 PixelTrait chop_traits=GetPixelChannelTraits(chop_image,channel);
354 if ((traits == UndefinedPixelTrait) ||
355 (chop_traits == UndefinedPixelTrait))
357 SetPixelChannel(chop_image,channel,p[i],q);
359 q+=GetPixelChannels(chop_image);
361 p+=GetPixelChannels(image);
363 if (SyncCacheViewAuthenticPixels(chop_view,exception) == MagickFalse)
365 if (image->progress_monitor != (MagickProgressMonitor) NULL)
370 #if defined(MAGICKCORE_OPENMP_SUPPORT)
371 #pragma omp critical (MagickCore_ChopImage)
373 proceed=SetImageProgress(image,ChopImageTag,progress++,image->rows);
374 if (proceed == MagickFalse)
378 chop_view=DestroyCacheView(chop_view);
379 image_view=DestroyCacheView(image_view);
380 chop_image->type=image->type;
381 if (status == MagickFalse)
382 chop_image=DestroyImage(chop_image);
387 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
391 + C o n s o l i d a t e C M Y K I m a g e %
395 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
397 % ConsolidateCMYKImage() consolidates separate C, M, Y, and K planes into a
400 % The format of the ConsolidateCMYKImage method is:
402 % Image *ConsolidateCMYKImage(const Image *image,ExceptionInfo *exception)
404 % A description of each parameter follows:
406 % o image: the image sequence.
408 % o exception: return any errors or warnings in this structure.
411 MagickExport Image *ConsolidateCMYKImages(const Image *images,
412 ExceptionInfo *exception)
429 Consolidate separate C, M, Y, and K planes into a single image.
431 assert(images != (Image *) NULL);
432 assert(images->signature == MagickSignature);
433 if (images->debug != MagickFalse)
434 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
435 assert(exception != (ExceptionInfo *) NULL);
436 assert(exception->signature == MagickSignature);
437 cmyk_images=NewImageList();
438 for (j=0; j < (ssize_t) GetImageListLength(images); j+=4)
443 cmyk_image=CloneImage(images,images->columns,images->rows,MagickTrue,
445 if (cmyk_image == (Image *) NULL)
447 if (SetImageStorageClass(cmyk_image,DirectClass,exception) == MagickFalse)
449 (void) SetImageColorspace(cmyk_image,CMYKColorspace,exception);
450 for (i=0; i < 4; i++)
452 image_view=AcquireVirtualCacheView(images,exception);
453 cmyk_view=AcquireAuthenticCacheView(cmyk_image,exception);
454 for (y=0; y < (ssize_t) images->rows; y++)
456 register const Quantum
465 p=GetCacheViewVirtualPixels(image_view,0,y,images->columns,1,exception);
466 q=QueueCacheViewAuthenticPixels(cmyk_view,0,y,cmyk_image->columns,1,
468 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
470 for (x=0; x < (ssize_t) images->columns; x++)
475 pixel=QuantumRange-GetPixelIntensity(images,p);
478 case 0: SetPixelCyan(cmyk_image,pixel,q); break;
479 case 1: SetPixelMagenta(cmyk_image,pixel,q); break;
480 case 2: SetPixelYellow(cmyk_image,pixel,q); break;
481 case 3: SetPixelBlack(cmyk_image,pixel,q); break;
484 p+=GetPixelChannels(images);
485 q+=GetPixelChannels(cmyk_image);
487 if (SyncCacheViewAuthenticPixels(cmyk_view,exception) == MagickFalse)
490 cmyk_view=DestroyCacheView(cmyk_view);
491 image_view=DestroyCacheView(image_view);
492 images=GetNextImageInList(images);
493 if (images == (Image *) NULL)
496 AppendImageToList(&cmyk_images,cmyk_image);
502 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
506 % C r o p I m a g e %
510 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
512 % CropImage() extracts a region of the image starting at the offset defined
513 % by geometry. Region must be fully defined, and no special handling of
514 % geometry flags is performed.
516 % The format of the CropImage method is:
518 % Image *CropImage(const Image *image,const RectangleInfo *geometry,
519 % ExceptionInfo *exception)
521 % A description of each parameter follows:
523 % o image: the image.
525 % o geometry: Define the region of the image to crop with members
526 % x, y, width, and height.
528 % o exception: return any errors or warnings in this structure.
531 MagickExport Image *CropImage(const Image *image,const RectangleInfo *geometry,
532 ExceptionInfo *exception)
534 #define CropImageTag "Crop/Image"
562 assert(image != (const Image *) NULL);
563 assert(image->signature == MagickSignature);
564 if (image->debug != MagickFalse)
565 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
566 assert(geometry != (const RectangleInfo *) NULL);
567 assert(exception != (ExceptionInfo *) NULL);
568 assert(exception->signature == MagickSignature);
569 bounding_box=image->page;
570 if ((bounding_box.width == 0) || (bounding_box.height == 0))
572 bounding_box.width=image->columns;
573 bounding_box.height=image->rows;
577 page.width=bounding_box.width;
578 if (page.height == 0)
579 page.height=bounding_box.height;
580 if (((bounding_box.x-page.x) >= (ssize_t) page.width) ||
581 ((bounding_box.y-page.y) >= (ssize_t) page.height) ||
582 ((page.x-bounding_box.x) > (ssize_t) image->columns) ||
583 ((page.y-bounding_box.y) > (ssize_t) image->rows))
586 Crop is not within virtual canvas, return 1 pixel transparent image.
588 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
589 "GeometryDoesNotContainImage","`%s'",image->filename);
590 crop_image=CloneImage(image,1,1,MagickTrue,exception);
591 if (crop_image == (Image *) NULL)
592 return((Image *) NULL);
593 crop_image->background_color.alpha=(Quantum) TransparentAlpha;
594 crop_image->alpha_trait=BlendPixelTrait;
595 (void) SetImageBackgroundColor(crop_image,exception);
596 crop_image->page=bounding_box;
597 crop_image->page.x=(-1);
598 crop_image->page.y=(-1);
599 if (crop_image->dispose == BackgroundDispose)
600 crop_image->dispose=NoneDispose;
603 if ((page.x < 0) && (bounding_box.x >= 0))
605 page.width+=page.x-bounding_box.x;
610 page.width-=bounding_box.x-page.x;
611 page.x-=bounding_box.x;
615 if ((page.y < 0) && (bounding_box.y >= 0))
617 page.height+=page.y-bounding_box.y;
622 page.height-=bounding_box.y-page.y;
623 page.y-=bounding_box.y;
627 if ((size_t) (page.x+page.width) > image->columns)
628 page.width=image->columns-page.x;
629 if ((geometry->width != 0) && (page.width > geometry->width))
630 page.width=geometry->width;
631 if ((size_t) (page.y+page.height) > image->rows)
632 page.height=image->rows-page.y;
633 if ((geometry->height != 0) && (page.height > geometry->height))
634 page.height=geometry->height;
635 bounding_box.x+=page.x;
636 bounding_box.y+=page.y;
637 if ((page.width == 0) || (page.height == 0))
639 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
640 "GeometryDoesNotContainImage","`%s'",image->filename);
641 return((Image *) NULL);
644 Initialize crop image attributes.
646 crop_image=CloneImage(image,page.width,page.height,MagickTrue,exception);
647 if (crop_image == (Image *) NULL)
648 return((Image *) NULL);
649 crop_image->page.width=image->page.width;
650 crop_image->page.height=image->page.height;
651 offset.x=(ssize_t) (bounding_box.x+bounding_box.width);
652 offset.y=(ssize_t) (bounding_box.y+bounding_box.height);
653 if ((offset.x > (ssize_t) image->page.width) ||
654 (offset.y > (ssize_t) image->page.height))
656 crop_image->page.width=bounding_box.width;
657 crop_image->page.height=bounding_box.height;
659 crop_image->page.x=bounding_box.x;
660 crop_image->page.y=bounding_box.y;
666 image_view=AcquireVirtualCacheView(image,exception);
667 crop_view=AcquireAuthenticCacheView(crop_image,exception);
668 #if defined(MAGICKCORE_OPENMP_SUPPORT)
669 #pragma omp parallel for schedule(static,4) shared(status) \
670 magick_threads(image,crop_image,1,1)
672 for (y=0; y < (ssize_t) crop_image->rows; y++)
674 register const Quantum
683 if (status == MagickFalse)
685 p=GetCacheViewVirtualPixels(image_view,page.x,page.y+y,crop_image->columns,
687 q=QueueCacheViewAuthenticPixels(crop_view,0,y,crop_image->columns,1,
689 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
694 for (x=0; x < (ssize_t) crop_image->columns; x++)
699 if (GetPixelReadMask(image,p) == 0)
701 SetPixelBackgoundColor(crop_image,q);
702 p+=GetPixelChannels(image);
703 q+=GetPixelChannels(crop_image);
706 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
708 PixelChannel channel=GetPixelChannelChannel(image,i);
709 PixelTrait traits=GetPixelChannelTraits(image,channel);
710 PixelTrait crop_traits=GetPixelChannelTraits(crop_image,channel);
711 if ((traits == UndefinedPixelTrait) ||
712 (crop_traits == UndefinedPixelTrait))
714 SetPixelChannel(crop_image,channel,p[i],q);
716 p+=GetPixelChannels(image);
717 q+=GetPixelChannels(crop_image);
719 if (SyncCacheViewAuthenticPixels(crop_view,exception) == MagickFalse)
721 if (image->progress_monitor != (MagickProgressMonitor) NULL)
726 #if defined(MAGICKCORE_OPENMP_SUPPORT)
727 #pragma omp critical (MagickCore_CropImage)
729 proceed=SetImageProgress(image,CropImageTag,progress++,image->rows);
730 if (proceed == MagickFalse)
734 crop_view=DestroyCacheView(crop_view);
735 image_view=DestroyCacheView(image_view);
736 crop_image->type=image->type;
737 if (status == MagickFalse)
738 crop_image=DestroyImage(crop_image);
743 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
747 % C r o p I m a g e T o T i l e s %
751 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
753 % CropImageToTiles() crops a single image, into a possible list of tiles.
754 % This may include a single sub-region of the image. This basically applies
755 % all the normal geometry flags for Crop.
757 % Image *CropImageToTiles(const Image *image,
758 % const RectangleInfo *crop_geometry, ExceptionInfo *exception)
760 % A description of each parameter follows:
762 % o image: the image The transformed image is returned as this parameter.
764 % o crop_geometry: A crop geometry string.
766 % o exception: return any errors or warnings in this structure.
770 static inline double MagickRound(double x)
773 Round the fraction to nearest integer.
775 if ((x-floor(x)) < (ceil(x)-x))
780 MagickExport Image *CropImageToTiles(const Image *image,
781 const char *crop_geometry,ExceptionInfo *exception)
793 assert(image != (Image *) NULL);
794 assert(image->signature == MagickSignature);
795 if (image->debug != MagickFalse)
796 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
797 crop_image=NewImageList();
799 flags=ParseGravityGeometry(image,crop_geometry,&geometry,exception);
800 if ((flags & AreaValue) != 0)
814 Crop into NxM tiles (@ flag).
816 width=image->columns;
818 if (geometry.width == 0)
820 if (geometry.height == 0)
822 if ((flags & AspectValue) == 0)
824 width-=(geometry.x < 0 ? -1 : 1)*geometry.x;
825 height-=(geometry.y < 0 ? -1 : 1)*geometry.y;
829 width+=(geometry.x < 0 ? -1 : 1)*geometry.x;
830 height+=(geometry.y < 0 ? -1 : 1)*geometry.y;
832 delta.x=(double) width/geometry.width;
833 delta.y=(double) height/geometry.height;
838 for (offset.y=0; offset.y < (double) height; )
840 if ((flags & AspectValue) == 0)
842 crop.y=(ssize_t) MagickRound((double) (offset.y-
843 (geometry.y > 0 ? 0 : geometry.y)));
844 offset.y+=delta.y; /* increment now to find width */
845 crop.height=(size_t) MagickRound((double) (offset.y+
846 (geometry.y < 0 ? 0 : geometry.y)));
850 crop.y=(ssize_t) MagickRound((double) (offset.y-
851 (geometry.y > 0 ? geometry.y : 0)));
852 offset.y+=delta.y; /* increment now to find width */
853 crop.height=(size_t) MagickRound((double)
854 (offset.y+(geometry.y < -1 ? geometry.y : 0)));
857 crop.y+=image->page.y;
858 for (offset.x=0; offset.x < (double) width; )
860 if ((flags & AspectValue) == 0)
862 crop.x=(ssize_t) MagickRound((double) (offset.x-
863 (geometry.x > 0 ? 0 : geometry.x)));
864 offset.x+=delta.x; /* increment now to find height */
865 crop.width=(size_t) MagickRound((double) (offset.x+
866 (geometry.x < 0 ? 0 : geometry.x)));
870 crop.x=(ssize_t) MagickRound((double) (offset.x-
871 (geometry.x > 0 ? geometry.x : 0)));
872 offset.x+=delta.x; /* increment now to find height */
873 crop.width=(size_t) MagickRound((double) (offset.x+
874 (geometry.x < 0 ? geometry.x : 0)));
877 crop.x+=image->page.x;
878 next=CropImage(image,&crop,exception);
879 if (next == (Image *) NULL)
881 AppendImageToList(&crop_image,next);
883 if (next == (Image *) NULL)
886 ClearMagickException(exception);
889 if (((geometry.width == 0) && (geometry.height == 0)) ||
890 ((flags & XValue) != 0) || ((flags & YValue) != 0))
893 Crop a single region at +X+Y.
895 crop_image=CropImage(image,&geometry,exception);
896 if ((crop_image != (Image *) NULL) && ((flags & AspectValue) != 0))
898 crop_image->page.width=geometry.width;
899 crop_image->page.height=geometry.height;
900 crop_image->page.x-=geometry.x;
901 crop_image->page.y-=geometry.y;
905 if ((image->columns > geometry.width) || (image->rows > geometry.height))
919 Crop into tiles of fixed size WxH.
923 page.width=image->columns;
924 if (page.height == 0)
925 page.height=image->rows;
926 width=geometry.width;
929 height=geometry.height;
933 for (y=0; y < (ssize_t) page.height; y+=(ssize_t) height)
935 for (x=0; x < (ssize_t) page.width; x+=(ssize_t) width)
937 geometry.width=width;
938 geometry.height=height;
941 next=CropImage(image,&geometry,exception);
942 if (next == (Image *) NULL)
944 AppendImageToList(&crop_image,next);
946 if (next == (Image *) NULL)
951 return(CloneImage(image,0,0,MagickTrue,exception));
955 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
959 % E x c e r p t I m a g e %
963 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
965 % ExcerptImage() returns a excerpt of the image as defined by the geometry.
967 % The format of the ExcerptImage method is:
969 % Image *ExcerptImage(const Image *image,const RectangleInfo *geometry,
970 % ExceptionInfo *exception)
972 % A description of each parameter follows:
974 % o image: the image.
976 % o geometry: Define the region of the image to extend with members
977 % x, y, width, and height.
979 % o exception: return any errors or warnings in this structure.
982 MagickExport Image *ExcerptImage(const Image *image,
983 const RectangleInfo *geometry,ExceptionInfo *exception)
985 #define ExcerptImageTag "Excerpt/Image"
1004 Allocate excerpt image.
1006 assert(image != (const Image *) NULL);
1007 assert(image->signature == MagickSignature);
1008 if (image->debug != MagickFalse)
1009 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1010 assert(geometry != (const RectangleInfo *) NULL);
1011 assert(exception != (ExceptionInfo *) NULL);
1012 assert(exception->signature == MagickSignature);
1013 excerpt_image=CloneImage(image,geometry->width,geometry->height,MagickTrue,
1015 if (excerpt_image == (Image *) NULL)
1016 return((Image *) NULL);
1022 image_view=AcquireVirtualCacheView(image,exception);
1023 excerpt_view=AcquireAuthenticCacheView(excerpt_image,exception);
1024 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1025 #pragma omp parallel for schedule(static,4) shared(progress,status) \
1026 magick_threads(image,excerpt_image,excerpt_image->rows,1)
1028 for (y=0; y < (ssize_t) excerpt_image->rows; y++)
1030 register const Quantum
1039 if (status == MagickFalse)
1041 p=GetCacheViewVirtualPixels(image_view,geometry->x,geometry->y+y,
1042 geometry->width,1,exception);
1043 q=GetCacheViewAuthenticPixels(excerpt_view,0,y,excerpt_image->columns,1,
1045 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1050 for (x=0; x < (ssize_t) excerpt_image->columns; x++)
1055 if (GetPixelReadMask(image,p) == 0)
1057 SetPixelBackgoundColor(excerpt_image,q);
1058 p+=GetPixelChannels(image);
1059 q+=GetPixelChannels(excerpt_image);
1062 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1064 PixelChannel channel=GetPixelChannelChannel(image,i);
1065 PixelTrait traits=GetPixelChannelTraits(image,channel);
1066 PixelTrait excerpt_traits=GetPixelChannelTraits(excerpt_image,channel);
1067 if ((traits == UndefinedPixelTrait) ||
1068 (excerpt_traits == UndefinedPixelTrait))
1070 SetPixelChannel(excerpt_image,channel,p[i],q);
1072 p+=GetPixelChannels(image);
1073 q+=GetPixelChannels(excerpt_image);
1075 if (SyncCacheViewAuthenticPixels(excerpt_view,exception) == MagickFalse)
1077 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1082 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1083 #pragma omp critical (MagickCore_ExcerptImage)
1085 proceed=SetImageProgress(image,ExcerptImageTag,progress++,image->rows);
1086 if (proceed == MagickFalse)
1090 excerpt_view=DestroyCacheView(excerpt_view);
1091 image_view=DestroyCacheView(image_view);
1092 excerpt_image->type=image->type;
1093 if (status == MagickFalse)
1094 excerpt_image=DestroyImage(excerpt_image);
1095 return(excerpt_image);
1099 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1103 % E x t e n t I m a g e %
1107 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1109 % ExtentImage() extends the image as defined by the geometry, gravity, and
1110 % image background color. Set the (x,y) offset of the geometry to move the
1111 % original image relative to the extended image.
1113 % The format of the ExtentImage method is:
1115 % Image *ExtentImage(const Image *image,const RectangleInfo *geometry,
1116 % ExceptionInfo *exception)
1118 % A description of each parameter follows:
1120 % o image: the image.
1122 % o geometry: Define the region of the image to extend with members
1123 % x, y, width, and height.
1125 % o exception: return any errors or warnings in this structure.
1128 MagickExport Image *ExtentImage(const Image *image,
1129 const RectangleInfo *geometry,ExceptionInfo *exception)
1135 Allocate extent image.
1137 assert(image != (const Image *) NULL);
1138 assert(image->signature == MagickSignature);
1139 if (image->debug != MagickFalse)
1140 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1141 assert(geometry != (const RectangleInfo *) NULL);
1142 assert(exception != (ExceptionInfo *) NULL);
1143 assert(exception->signature == MagickSignature);
1144 extent_image=CloneImage(image,geometry->width,geometry->height,MagickTrue,
1146 if (extent_image == (Image *) NULL)
1147 return((Image *) NULL);
1148 if (SetImageStorageClass(extent_image,DirectClass,exception) == MagickFalse)
1150 extent_image=DestroyImage(extent_image);
1151 return((Image *) NULL);
1153 if (extent_image->background_color.alpha != OpaqueAlpha)
1154 extent_image->alpha_trait=BlendPixelTrait;
1155 (void) SetImageBackgroundColor(extent_image,exception);
1156 (void) CompositeImage(extent_image,image,image->compose,MagickTrue,
1157 -geometry->x,-geometry->y,exception);
1158 return(extent_image);
1162 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1166 % F l i p I m a g e %
1170 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1172 % FlipImage() creates a vertical mirror image by reflecting the pixels
1173 % around the central x-axis.
1175 % The format of the FlipImage method is:
1177 % Image *FlipImage(const Image *image,ExceptionInfo *exception)
1179 % A description of each parameter follows:
1181 % o image: the image.
1183 % o exception: return any errors or warnings in this structure.
1186 MagickExport Image *FlipImage(const Image *image,ExceptionInfo *exception)
1188 #define FlipImageTag "Flip/Image"
1209 assert(image != (const Image *) NULL);
1210 assert(image->signature == MagickSignature);
1211 if (image->debug != MagickFalse)
1212 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1213 assert(exception != (ExceptionInfo *) NULL);
1214 assert(exception->signature == MagickSignature);
1215 flip_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
1216 if (flip_image == (Image *) NULL)
1217 return((Image *) NULL);
1224 image_view=AcquireVirtualCacheView(image,exception);
1225 flip_view=AcquireAuthenticCacheView(flip_image,exception);
1226 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1227 #pragma omp parallel for schedule(static,4) shared(status) \
1228 magick_threads(image,flip_image,1,1)
1230 for (y=0; y < (ssize_t) flip_image->rows; y++)
1232 register const Quantum
1241 if (status == MagickFalse)
1243 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1244 q=QueueCacheViewAuthenticPixels(flip_view,0,(ssize_t) (flip_image->rows-y-
1245 1),flip_image->columns,1,exception);
1246 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1251 for (x=0; x < (ssize_t) flip_image->columns; x++)
1256 if (GetPixelReadMask(image,p) == 0)
1258 SetPixelBackgoundColor(flip_image,q);
1259 p+=GetPixelChannels(image);
1260 q+=GetPixelChannels(flip_image);
1263 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1265 PixelChannel channel=GetPixelChannelChannel(image,i);
1266 PixelTrait traits=GetPixelChannelTraits(image,channel);
1267 PixelTrait flip_traits=GetPixelChannelTraits(flip_image,channel);
1268 if ((traits == UndefinedPixelTrait) ||
1269 (flip_traits == UndefinedPixelTrait))
1271 SetPixelChannel(flip_image,channel,p[i],q);
1273 p+=GetPixelChannels(image);
1274 q+=GetPixelChannels(flip_image);
1276 if (SyncCacheViewAuthenticPixels(flip_view,exception) == MagickFalse)
1278 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1283 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1284 #pragma omp critical (MagickCore_FlipImage)
1286 proceed=SetImageProgress(image,FlipImageTag,progress++,image->rows);
1287 if (proceed == MagickFalse)
1291 flip_view=DestroyCacheView(flip_view);
1292 image_view=DestroyCacheView(image_view);
1293 flip_image->type=image->type;
1294 if (page.height != 0)
1295 page.y=(ssize_t) (page.height-flip_image->rows-page.y);
1296 flip_image->page=page;
1297 if (status == MagickFalse)
1298 flip_image=DestroyImage(flip_image);
1303 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1307 % F l o p I m a g e %
1311 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1313 % FlopImage() creates a horizontal mirror image by reflecting the pixels
1314 % around the central y-axis.
1316 % The format of the FlopImage method is:
1318 % Image *FlopImage(const Image *image,ExceptionInfo *exception)
1320 % A description of each parameter follows:
1322 % o image: the image.
1324 % o exception: return any errors or warnings in this structure.
1327 MagickExport Image *FlopImage(const Image *image,ExceptionInfo *exception)
1329 #define FlopImageTag "Flop/Image"
1350 assert(image != (const Image *) NULL);
1351 assert(image->signature == MagickSignature);
1352 if (image->debug != MagickFalse)
1353 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1354 assert(exception != (ExceptionInfo *) NULL);
1355 assert(exception->signature == MagickSignature);
1356 flop_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
1357 if (flop_image == (Image *) NULL)
1358 return((Image *) NULL);
1365 image_view=AcquireVirtualCacheView(image,exception);
1366 flop_view=AcquireAuthenticCacheView(flop_image,exception);
1367 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1368 #pragma omp parallel for schedule(static,4) shared(status) \
1369 magick_threads(image,flop_image,1,1)
1371 for (y=0; y < (ssize_t) flop_image->rows; y++)
1373 register const Quantum
1382 if (status == MagickFalse)
1384 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1385 q=QueueCacheViewAuthenticPixels(flop_view,0,y,flop_image->columns,1,
1387 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1392 q+=GetPixelChannels(flop_image)*flop_image->columns;
1393 for (x=0; x < (ssize_t) flop_image->columns; x++)
1398 q-=GetPixelChannels(flop_image);
1399 if (GetPixelReadMask(image,p) == 0)
1401 p+=GetPixelChannels(image);
1404 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1406 PixelChannel channel=GetPixelChannelChannel(image,i);
1407 PixelTrait traits=GetPixelChannelTraits(image,channel);
1408 PixelTrait flop_traits=GetPixelChannelTraits(flop_image,channel);
1409 if ((traits == UndefinedPixelTrait) ||
1410 (flop_traits == UndefinedPixelTrait))
1412 SetPixelChannel(flop_image,channel,p[i],q);
1414 p+=GetPixelChannels(image);
1416 if (SyncCacheViewAuthenticPixels(flop_view,exception) == MagickFalse)
1418 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1423 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1424 #pragma omp critical (MagickCore_FlopImage)
1426 proceed=SetImageProgress(image,FlopImageTag,progress++,image->rows);
1427 if (proceed == MagickFalse)
1431 flop_view=DestroyCacheView(flop_view);
1432 image_view=DestroyCacheView(image_view);
1433 flop_image->type=image->type;
1434 if (page.width != 0)
1435 page.x=(ssize_t) (page.width-flop_image->columns-page.x);
1436 flop_image->page=page;
1437 if (status == MagickFalse)
1438 flop_image=DestroyImage(flop_image);
1443 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1447 % R o l l I m a g e %
1451 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1453 % RollImage() offsets an image as defined by x_offset and y_offset.
1455 % The format of the RollImage method is:
1457 % Image *RollImage(const Image *image,const ssize_t x_offset,
1458 % const ssize_t y_offset,ExceptionInfo *exception)
1460 % A description of each parameter follows:
1462 % o image: the image.
1464 % o x_offset: the number of columns to roll in the horizontal direction.
1466 % o y_offset: the number of rows to roll in the vertical direction.
1468 % o exception: return any errors or warnings in this structure.
1472 static inline MagickBooleanType CopyImageRegion(Image *destination,
1473 const Image *source,const size_t columns,const size_t rows,
1474 const ssize_t sx,const ssize_t sy,const ssize_t dx,const ssize_t dy,
1475 ExceptionInfo *exception)
1490 source_view=AcquireVirtualCacheView(source,exception);
1491 destination_view=AcquireAuthenticCacheView(destination,exception);
1492 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1493 #pragma omp parallel for schedule(static,4) shared(status) \
1494 magick_threads(source,destination,rows,1)
1496 for (y=0; y < (ssize_t) rows; y++)
1501 register const Quantum
1513 if (status == MagickFalse)
1515 p=GetCacheViewVirtualPixels(source_view,sx,sy+y,columns,1,exception);
1516 q=GetCacheViewAuthenticPixels(destination_view,dx,dy+y,columns,1,exception);
1517 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1522 for (x=0; x < (ssize_t) columns; x++)
1527 if (GetPixelReadMask(source,p) == 0)
1529 SetPixelBackgoundColor(destination,q);
1530 p+=GetPixelChannels(source);
1531 q+=GetPixelChannels(destination);
1534 for (i=0; i < (ssize_t) GetPixelChannels(source); i++)
1536 PixelChannel channel=GetPixelChannelChannel(source,i);
1537 PixelTrait source_traits=GetPixelChannelTraits(source,channel);
1538 PixelTrait destination_traits=GetPixelChannelTraits(destination,
1540 if ((source_traits == UndefinedPixelTrait) ||
1541 (destination_traits == UndefinedPixelTrait))
1543 SetPixelChannel(destination,channel,p[i],q);
1545 p+=GetPixelChannels(source);
1546 q+=GetPixelChannels(destination);
1548 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
1549 if (sync == MagickFalse)
1552 destination_view=DestroyCacheView(destination_view);
1553 source_view=DestroyCacheView(source_view);
1557 MagickExport Image *RollImage(const Image *image,const ssize_t x_offset,
1558 const ssize_t y_offset,ExceptionInfo *exception)
1560 #define RollImageTag "Roll/Image"
1572 Initialize roll image attributes.
1574 assert(image != (const Image *) NULL);
1575 assert(image->signature == MagickSignature);
1576 if (image->debug != MagickFalse)
1577 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1578 assert(exception != (ExceptionInfo *) NULL);
1579 assert(exception->signature == MagickSignature);
1580 roll_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
1581 if (roll_image == (Image *) NULL)
1582 return((Image *) NULL);
1585 while (offset.x < 0)
1586 offset.x+=(ssize_t) image->columns;
1587 while (offset.x >= (ssize_t) image->columns)
1588 offset.x-=(ssize_t) image->columns;
1589 while (offset.y < 0)
1590 offset.y+=(ssize_t) image->rows;
1591 while (offset.y >= (ssize_t) image->rows)
1592 offset.y-=(ssize_t) image->rows;
1596 status=CopyImageRegion(roll_image,image,(size_t) offset.x,
1597 (size_t) offset.y,(ssize_t) image->columns-offset.x,(ssize_t) image->rows-
1598 offset.y,0,0,exception);
1599 (void) SetImageProgress(image,RollImageTag,0,3);
1600 status&=CopyImageRegion(roll_image,image,image->columns-offset.x,
1601 (size_t) offset.y,0,(ssize_t) image->rows-offset.y,offset.x,0,
1603 (void) SetImageProgress(image,RollImageTag,1,3);
1604 status&=CopyImageRegion(roll_image,image,(size_t) offset.x,image->rows-
1605 offset.y,(ssize_t) image->columns-offset.x,0,0,offset.y,exception);
1606 (void) SetImageProgress(image,RollImageTag,2,3);
1607 status&=CopyImageRegion(roll_image,image,image->columns-offset.x,image->rows-
1608 offset.y,0,0,offset.x,offset.y,exception);
1609 (void) SetImageProgress(image,RollImageTag,3,3);
1610 roll_image->type=image->type;
1611 if (status == MagickFalse)
1612 roll_image=DestroyImage(roll_image);
1617 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1621 % S h a v e I m a g e %
1625 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1627 % ShaveImage() shaves pixels from the image edges. It allocates the memory
1628 % necessary for the new Image structure and returns a pointer to the new
1631 % The format of the ShaveImage method is:
1633 % Image *ShaveImage(const Image *image,const RectangleInfo *shave_info,
1634 % ExceptionInfo *exception)
1636 % A description of each parameter follows:
1638 % o shave_image: Method ShaveImage returns a pointer to the shaved
1639 % image. A null image is returned if there is a memory shortage or
1640 % if the image width or height is zero.
1642 % o image: the image.
1644 % o shave_info: Specifies a pointer to a RectangleInfo which defines the
1645 % region of the image to crop.
1647 % o exception: return any errors or warnings in this structure.
1650 MagickExport Image *ShaveImage(const Image *image,
1651 const RectangleInfo *shave_info,ExceptionInfo *exception)
1659 assert(image != (const Image *) NULL);
1660 assert(image->signature == MagickSignature);
1661 if (image->debug != MagickFalse)
1662 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1663 if (((2*shave_info->width) >= image->columns) ||
1664 ((2*shave_info->height) >= image->rows))
1665 ThrowImageException(OptionWarning,"GeometryDoesNotContainImage");
1666 SetGeometry(image,&geometry);
1667 geometry.width-=2*shave_info->width;
1668 geometry.height-=2*shave_info->height;
1669 geometry.x=(ssize_t) shave_info->width+image->page.x;
1670 geometry.y=(ssize_t) shave_info->height+image->page.y;
1671 shave_image=CropImage(image,&geometry,exception);
1672 if (shave_image == (Image *) NULL)
1673 return((Image *) NULL);
1674 shave_image->page.width-=2*shave_info->width;
1675 shave_image->page.height-=2*shave_info->height;
1676 shave_image->page.x-=(ssize_t) shave_info->width;
1677 shave_image->page.y-=(ssize_t) shave_info->height;
1678 return(shave_image);
1682 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1686 % S p l i c e I m a g e %
1690 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1692 % SpliceImage() splices a solid color into the image as defined by the
1695 % The format of the SpliceImage method is:
1697 % Image *SpliceImage(const Image *image,const RectangleInfo *geometry,
1698 % ExceptionInfo *exception)
1700 % A description of each parameter follows:
1702 % o image: the image.
1704 % o geometry: Define the region of the image to splice with members
1705 % x, y, width, and height.
1707 % o exception: return any errors or warnings in this structure.
1710 MagickExport Image *SpliceImage(const Image *image,
1711 const RectangleInfo *geometry,ExceptionInfo *exception)
1713 #define SpliceImageTag "Splice/Image"
1735 Allocate splice image.
1737 assert(image != (const Image *) NULL);
1738 assert(image->signature == MagickSignature);
1739 if (image->debug != MagickFalse)
1740 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1741 assert(geometry != (const RectangleInfo *) NULL);
1742 assert(exception != (ExceptionInfo *) NULL);
1743 assert(exception->signature == MagickSignature);
1744 splice_geometry=(*geometry);
1745 splice_image=CloneImage(image,image->columns+splice_geometry.width,
1746 image->rows+splice_geometry.height,MagickTrue,exception);
1747 if (splice_image == (Image *) NULL)
1748 return((Image *) NULL);
1749 if (SetImageStorageClass(splice_image,DirectClass,exception) == MagickFalse)
1751 splice_image=DestroyImage(splice_image);
1752 return((Image *) NULL);
1754 (void) SetImageBackgroundColor(splice_image,exception);
1756 Respect image geometry.
1758 switch (image->gravity)
1761 case UndefinedGravity:
1762 case NorthWestGravity:
1766 splice_geometry.x+=(ssize_t) splice_geometry.width/2;
1769 case NorthEastGravity:
1771 splice_geometry.x+=(ssize_t) splice_geometry.width;
1776 splice_geometry.y+=(ssize_t) splice_geometry.width/2;
1781 splice_geometry.x+=(ssize_t) splice_geometry.width/2;
1782 splice_geometry.y+=(ssize_t) splice_geometry.height/2;
1787 splice_geometry.x+=(ssize_t) splice_geometry.width;
1788 splice_geometry.y+=(ssize_t) splice_geometry.height/2;
1791 case SouthWestGravity:
1793 splice_geometry.y+=(ssize_t) splice_geometry.height;
1798 splice_geometry.x+=(ssize_t) splice_geometry.width/2;
1799 splice_geometry.y+=(ssize_t) splice_geometry.height;
1802 case SouthEastGravity:
1804 splice_geometry.x+=(ssize_t) splice_geometry.width;
1805 splice_geometry.y+=(ssize_t) splice_geometry.height;
1814 image_view=AcquireVirtualCacheView(image,exception);
1815 splice_view=AcquireAuthenticCacheView(splice_image,exception);
1816 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1817 #pragma omp parallel for schedule(static,4) shared(progress,status) \
1818 magick_threads(image,splice_image,1,1)
1820 for (y=0; y < (ssize_t) splice_geometry.y; y++)
1822 register const Quantum
1831 if (status == MagickFalse)
1833 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1834 q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1,
1836 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1841 for (x=0; x < splice_geometry.x; x++)
1846 if (GetPixelReadMask(image,p) == 0)
1848 SetPixelBackgoundColor(splice_image,q);
1849 p+=GetPixelChannels(image);
1850 q+=GetPixelChannels(splice_image);
1853 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1855 PixelChannel channel=GetPixelChannelChannel(image,i);
1856 PixelTrait traits=GetPixelChannelTraits(image,channel);
1857 PixelTrait splice_traits=GetPixelChannelTraits(splice_image,channel);
1858 if ((traits == UndefinedPixelTrait) ||
1859 (splice_traits == UndefinedPixelTrait))
1861 SetPixelChannel(splice_image,channel,p[i],q);
1863 p+=GetPixelChannels(image);
1864 q+=GetPixelChannels(splice_image);
1866 for ( ; x < (ssize_t) (splice_geometry.x+splice_geometry.width); x++)
1867 q+=GetPixelChannels(splice_image);
1868 for ( ; x < (ssize_t) splice_image->columns; x++)
1873 if (GetPixelReadMask(image,p) == 0)
1875 SetPixelBackgoundColor(splice_image,q);
1876 p+=GetPixelChannels(image);
1877 q+=GetPixelChannels(splice_image);
1880 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1882 PixelChannel channel=GetPixelChannelChannel(image,i);
1883 PixelTrait traits=GetPixelChannelTraits(image,channel);
1884 PixelTrait splice_traits=GetPixelChannelTraits(splice_image,channel);
1885 if ((traits == UndefinedPixelTrait) ||
1886 (splice_traits == UndefinedPixelTrait))
1888 SetPixelChannel(splice_image,channel,p[i],q);
1890 p+=GetPixelChannels(image);
1891 q+=GetPixelChannels(splice_image);
1893 if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse)
1895 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1900 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1901 #pragma omp critical (MagickCore_TransposeImage)
1903 proceed=SetImageProgress(image,SpliceImageTag,progress++,
1904 splice_image->rows);
1905 if (proceed == MagickFalse)
1909 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1910 #pragma omp parallel for schedule(static,4) shared(progress,status) \
1911 magick_threads(image,splice_image,1,1)
1913 for (y=(ssize_t) (splice_geometry.y+splice_geometry.height);
1914 y < (ssize_t) splice_image->rows; y++)
1916 register const Quantum
1925 if (status == MagickFalse)
1927 p=GetCacheViewVirtualPixels(image_view,0,y-(ssize_t) splice_geometry.height,
1928 image->columns,1,exception);
1929 if ((y < 0) || (y >= (ssize_t) splice_image->rows))
1931 q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1,
1933 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1938 for (x=0; x < splice_geometry.x; x++)
1943 if (GetPixelReadMask(image,q) == 0)
1945 SetPixelBackgoundColor(splice_image,q);
1946 p+=GetPixelChannels(image);
1947 q+=GetPixelChannels(splice_image);
1950 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1952 PixelChannel channel=GetPixelChannelChannel(image,i);
1953 PixelTrait traits=GetPixelChannelTraits(image,channel);
1954 PixelTrait splice_traits=GetPixelChannelTraits(splice_image,channel);
1955 if ((traits == UndefinedPixelTrait) ||
1956 (splice_traits == UndefinedPixelTrait))
1958 SetPixelChannel(splice_image,channel,p[i],q);
1960 p+=GetPixelChannels(image);
1961 q+=GetPixelChannels(splice_image);
1963 for ( ; x < (ssize_t) (splice_geometry.x+splice_geometry.width); x++)
1964 q+=GetPixelChannels(splice_image);
1965 for ( ; x < (ssize_t) splice_image->columns; x++)
1970 if (GetPixelReadMask(image,q) == 0)
1972 SetPixelBackgoundColor(splice_image,q);
1973 p+=GetPixelChannels(image);
1974 q+=GetPixelChannels(splice_image);
1977 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1979 PixelChannel channel=GetPixelChannelChannel(image,i);
1980 PixelTrait traits=GetPixelChannelTraits(image,channel);
1981 PixelTrait splice_traits=GetPixelChannelTraits(splice_image,channel);
1982 if ((traits == UndefinedPixelTrait) ||
1983 (splice_traits == UndefinedPixelTrait))
1985 SetPixelChannel(splice_image,channel,p[i],q);
1987 p+=GetPixelChannels(image);
1988 q+=GetPixelChannels(splice_image);
1990 if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse)
1992 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1997 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1998 #pragma omp critical (MagickCore_TransposeImage)
2000 proceed=SetImageProgress(image,SpliceImageTag,progress++,
2001 splice_image->rows);
2002 if (proceed == MagickFalse)
2006 splice_view=DestroyCacheView(splice_view);
2007 image_view=DestroyCacheView(image_view);
2008 if (status == MagickFalse)
2009 splice_image=DestroyImage(splice_image);
2010 return(splice_image);
2014 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2018 % T r a n s f o r m I m a g e %
2022 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2024 % TransformImage() is a convenience method that behaves like ResizeImage() or
2025 % CropImage() but accepts scaling and/or cropping information as a region
2026 % geometry specification. If the operation fails, the original image handle
2029 % This should only be used for single images.
2031 % This function destroys what it assumes to be a single image list.
2032 % If the input image is part of a larger list, all other images in that list
2033 % will be simply 'lost', not destroyed.
2035 % Also if the crop generates a list of images only the first image is resized.
2036 % And finally if the crop succeeds and the resize failed, you will get a
2037 % cropped image, as well as a 'false' or 'failed' report.
2039 % This function and should probably be depreciated in favor of direct calls
2040 % to CropImageToTiles() or ResizeImage(), as appropriate.
2042 % The format of the TransformImage method is:
2044 % MagickBooleanType TransformImage(Image **image,const char *crop_geometry,
2045 % const char *image_geometry,ExceptionInfo *exception)
2047 % A description of each parameter follows:
2049 % o image: the image The transformed image is returned as this parameter.
2051 % o crop_geometry: A crop geometry string. This geometry defines a
2052 % subregion of the image to crop.
2054 % o image_geometry: An image geometry string. This geometry defines the
2055 % final size of the image.
2057 % o exception: return any errors or warnings in this structure.
2060 MagickExport MagickBooleanType TransformImage(Image **image,
2061 const char *crop_geometry,const char *image_geometry,ExceptionInfo *exception)
2073 assert(image != (Image **) NULL);
2074 assert((*image)->signature == MagickSignature);
2075 if ((*image)->debug != MagickFalse)
2076 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
2077 transform_image=(*image);
2078 if (crop_geometry != (const char *) NULL)
2084 Crop image to a user specified size.
2086 crop_image=CropImageToTiles(*image,crop_geometry,exception);
2087 if (crop_image == (Image *) NULL)
2088 transform_image=CloneImage(*image,0,0,MagickTrue,exception);
2091 transform_image=DestroyImage(transform_image);
2092 transform_image=GetFirstImageInList(crop_image);
2094 *image=transform_image;
2096 if (image_geometry == (const char *) NULL)
2100 Scale image to a user specified size.
2102 flags=ParseRegionGeometry(transform_image,image_geometry,&geometry,exception);
2104 if ((transform_image->columns == geometry.width) &&
2105 (transform_image->rows == geometry.height))
2107 resize_image=ResizeImage(transform_image,geometry.width,geometry.height,
2108 transform_image->filter,exception);
2109 if (resize_image == (Image *) NULL)
2110 return(MagickFalse);
2111 transform_image=DestroyImage(transform_image);
2112 transform_image=resize_image;
2113 *image=transform_image;
2118 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2122 % T r a n s f o r m I m a g e s %
2126 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2128 % TransformImages() calls TransformImage() on each image of a sequence.
2130 % The format of the TransformImage method is:
2132 % MagickBooleanType TransformImages(Image **image,
2133 % const char *crop_geometry,const char *image_geometry,
2134 % ExceptionInfo *exception)
2136 % A description of each parameter follows:
2138 % o image: the image The transformed image is returned as this parameter.
2140 % o crop_geometry: A crop geometry string. This geometry defines a
2141 % subregion of the image to crop.
2143 % o image_geometry: An image geometry string. This geometry defines the
2144 % final size of the image.
2146 % o exception: return any errors or warnings in this structure.
2149 MagickExport MagickBooleanType TransformImages(Image **images,
2150 const char *crop_geometry,const char *image_geometry,ExceptionInfo *exception)
2163 assert(images != (Image **) NULL);
2164 assert((*images)->signature == MagickSignature);
2165 if ((*images)->debug != MagickFalse)
2166 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2167 (*images)->filename);
2168 image_list=ImageListToArray(*images,exception);
2169 if (image_list == (Image **) NULL)
2170 return(MagickFalse);
2172 transform_images=NewImageList();
2173 for (i=0; image_list[i] != (Image *) NULL; i++)
2175 image=image_list[i];
2176 status&=TransformImage(&image,crop_geometry,image_geometry,exception);
2177 AppendImageToList(&transform_images,image);
2179 *images=transform_images;
2180 image_list=(Image **) RelinquishMagickMemory(image_list);
2181 return(status != 0 ? MagickTrue : MagickFalse);
2185 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2189 % T r a n s p o s e I m a g e %
2193 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2195 % TransposeImage() creates a horizontal mirror image by reflecting the pixels
2196 % around the central y-axis while rotating them by 90 degrees.
2198 % The format of the TransposeImage method is:
2200 % Image *TransposeImage(const Image *image,ExceptionInfo *exception)
2202 % A description of each parameter follows:
2204 % o image: the image.
2206 % o exception: return any errors or warnings in this structure.
2209 MagickExport Image *TransposeImage(const Image *image,ExceptionInfo *exception)
2211 #define TransposeImageTag "Transpose/Image"
2232 assert(image != (const Image *) NULL);
2233 assert(image->signature == MagickSignature);
2234 if (image->debug != MagickFalse)
2235 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2236 assert(exception != (ExceptionInfo *) NULL);
2237 assert(exception->signature == MagickSignature);
2238 transpose_image=CloneImage(image,image->rows,image->columns,MagickTrue,
2240 if (transpose_image == (Image *) NULL)
2241 return((Image *) NULL);
2247 image_view=AcquireVirtualCacheView(image,exception);
2248 transpose_view=AcquireAuthenticCacheView(transpose_image,exception);
2249 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2250 #pragma omp parallel for schedule(static,4) shared(progress,status) \
2251 magick_threads(image,transpose_image,image->rows,1)
2253 for (y=0; y < (ssize_t) image->rows; y++)
2255 register const Quantum
2264 if (status == MagickFalse)
2266 p=GetCacheViewVirtualPixels(image_view,0,(ssize_t) image->rows-y-1,
2267 image->columns,1,exception);
2268 q=QueueCacheViewAuthenticPixels(transpose_view,(ssize_t) (image->rows-y-1),
2269 0,1,transpose_image->rows,exception);
2270 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2275 for (x=0; x < (ssize_t) image->columns; x++)
2280 if (GetPixelReadMask(image,q) == 0)
2282 SetPixelBackgoundColor(transpose_image,q);
2283 p+=GetPixelChannels(image);
2284 q+=GetPixelChannels(transpose_image);
2287 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2289 PixelChannel channel=GetPixelChannelChannel(image,i);
2290 PixelTrait traits=GetPixelChannelTraits(image,channel);
2291 PixelTrait transpose_traits=GetPixelChannelTraits(transpose_image,
2293 if ((traits == UndefinedPixelTrait) ||
2294 (transpose_traits == UndefinedPixelTrait))
2296 SetPixelChannel(transpose_image,channel,p[i],q);
2298 p+=GetPixelChannels(image);
2299 q+=GetPixelChannels(transpose_image);
2301 if (SyncCacheViewAuthenticPixels(transpose_view,exception) == MagickFalse)
2303 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2308 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2309 #pragma omp critical (MagickCore_TransposeImage)
2311 proceed=SetImageProgress(image,TransposeImageTag,progress++,
2313 if (proceed == MagickFalse)
2317 transpose_view=DestroyCacheView(transpose_view);
2318 image_view=DestroyCacheView(image_view);
2319 transpose_image->type=image->type;
2320 page=transpose_image->page;
2321 Swap(page.width,page.height);
2322 Swap(page.x,page.y);
2323 transpose_image->page=page;
2324 if (status == MagickFalse)
2325 transpose_image=DestroyImage(transpose_image);
2326 return(transpose_image);
2330 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2334 % T r a n s v e r s e I m a g e %
2338 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2340 % TransverseImage() creates a vertical mirror image by reflecting the pixels
2341 % around the central x-axis while rotating them by 270 degrees.
2343 % The format of the TransverseImage method is:
2345 % Image *TransverseImage(const Image *image,ExceptionInfo *exception)
2347 % A description of each parameter follows:
2349 % o image: the image.
2351 % o exception: return any errors or warnings in this structure.
2354 MagickExport Image *TransverseImage(const Image *image,ExceptionInfo *exception)
2356 #define TransverseImageTag "Transverse/Image"
2377 assert(image != (const Image *) NULL);
2378 assert(image->signature == MagickSignature);
2379 if (image->debug != MagickFalse)
2380 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2381 assert(exception != (ExceptionInfo *) NULL);
2382 assert(exception->signature == MagickSignature);
2383 transverse_image=CloneImage(image,image->rows,image->columns,MagickTrue,
2385 if (transverse_image == (Image *) NULL)
2386 return((Image *) NULL);
2392 image_view=AcquireVirtualCacheView(image,exception);
2393 transverse_view=AcquireAuthenticCacheView(transverse_image,exception);
2394 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2395 #pragma omp parallel for schedule(static,4) shared(progress,status) \
2396 magick_threads(image,transverse_image,image->rows,1)
2398 for (y=0; y < (ssize_t) image->rows; y++)
2403 register const Quantum
2412 if (status == MagickFalse)
2414 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2415 q=QueueCacheViewAuthenticPixels(transverse_view,(ssize_t) (image->rows-y-1),
2416 0,1,transverse_image->rows,exception);
2417 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2422 q+=GetPixelChannels(transverse_image)*image->columns;
2423 for (x=0; x < (ssize_t) image->columns; x++)
2428 q-=GetPixelChannels(transverse_image);
2429 if (GetPixelReadMask(image,p) == 0)
2431 p+=GetPixelChannels(image);
2434 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2436 PixelChannel channel=GetPixelChannelChannel(image,i);
2437 PixelTrait traits=GetPixelChannelTraits(image,channel);
2438 PixelTrait transverse_traits=GetPixelChannelTraits(transverse_image,
2440 if ((traits == UndefinedPixelTrait) ||
2441 (transverse_traits == UndefinedPixelTrait))
2443 SetPixelChannel(transverse_image,channel,p[i],q);
2445 p+=GetPixelChannels(image);
2447 sync=SyncCacheViewAuthenticPixels(transverse_view,exception);
2448 if (sync == MagickFalse)
2450 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2455 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2456 #pragma omp critical (MagickCore_TransverseImage)
2458 proceed=SetImageProgress(image,TransverseImageTag,progress++,
2460 if (proceed == MagickFalse)
2464 transverse_view=DestroyCacheView(transverse_view);
2465 image_view=DestroyCacheView(image_view);
2466 transverse_image->type=image->type;
2467 page=transverse_image->page;
2468 Swap(page.width,page.height);
2469 Swap(page.x,page.y);
2470 if (page.width != 0)
2471 page.x=(ssize_t) (page.width-transverse_image->columns-page.x);
2472 if (page.height != 0)
2473 page.y=(ssize_t) (page.height-transverse_image->rows-page.y);
2474 transverse_image->page=page;
2475 if (status == MagickFalse)
2476 transverse_image=DestroyImage(transverse_image);
2477 return(transverse_image);
2481 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2485 % T r i m I m a g e %
2489 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2491 % TrimImage() trims pixels from the image edges. It allocates the memory
2492 % necessary for the new Image structure and returns a pointer to the new
2495 % The format of the TrimImage method is:
2497 % Image *TrimImage(const Image *image,ExceptionInfo *exception)
2499 % A description of each parameter follows:
2501 % o image: the image.
2503 % o exception: return any errors or warnings in this structure.
2506 MagickExport Image *TrimImage(const Image *image,ExceptionInfo *exception)
2511 assert(image != (const Image *) NULL);
2512 assert(image->signature == MagickSignature);
2513 if (image->debug != MagickFalse)
2514 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2515 geometry=GetImageBoundingBox(image,exception);
2516 if ((geometry.width == 0) || (geometry.height == 0))
2521 crop_image=CloneImage(image,1,1,MagickTrue,exception);
2522 if (crop_image == (Image *) NULL)
2523 return((Image *) NULL);
2524 crop_image->background_color.alpha=(Quantum) TransparentAlpha;
2525 crop_image->alpha_trait=BlendPixelTrait;
2526 (void) SetImageBackgroundColor(crop_image,exception);
2527 crop_image->page=image->page;
2528 crop_image->page.x=(-1);
2529 crop_image->page.y=(-1);
2532 geometry.x+=image->page.x;
2533 geometry.y+=image->page.y;
2534 return(CropImage(image,&geometry,exception));