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-2013 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 (void) SetImageBackgroundColor(crop_image,exception);
595 crop_image->page=bounding_box;
596 crop_image->page.x=(-1);
597 crop_image->page.y=(-1);
598 if (crop_image->dispose == BackgroundDispose)
599 crop_image->dispose=NoneDispose;
602 if ((page.x < 0) && (bounding_box.x >= 0))
604 page.width+=page.x-bounding_box.x;
609 page.width-=bounding_box.x-page.x;
610 page.x-=bounding_box.x;
614 if ((page.y < 0) && (bounding_box.y >= 0))
616 page.height+=page.y-bounding_box.y;
621 page.height-=bounding_box.y-page.y;
622 page.y-=bounding_box.y;
626 if ((size_t) (page.x+page.width) > image->columns)
627 page.width=image->columns-page.x;
628 if ((geometry->width != 0) && (page.width > geometry->width))
629 page.width=geometry->width;
630 if ((size_t) (page.y+page.height) > image->rows)
631 page.height=image->rows-page.y;
632 if ((geometry->height != 0) && (page.height > geometry->height))
633 page.height=geometry->height;
634 bounding_box.x+=page.x;
635 bounding_box.y+=page.y;
636 if ((page.width == 0) || (page.height == 0))
638 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
639 "GeometryDoesNotContainImage","`%s'",image->filename);
640 return((Image *) NULL);
643 Initialize crop image attributes.
645 crop_image=CloneImage(image,page.width,page.height,MagickTrue,exception);
646 if (crop_image == (Image *) NULL)
647 return((Image *) NULL);
648 crop_image->page.width=image->page.width;
649 crop_image->page.height=image->page.height;
650 offset.x=(ssize_t) (bounding_box.x+bounding_box.width);
651 offset.y=(ssize_t) (bounding_box.y+bounding_box.height);
652 if ((offset.x > (ssize_t) image->page.width) ||
653 (offset.y > (ssize_t) image->page.height))
655 crop_image->page.width=bounding_box.width;
656 crop_image->page.height=bounding_box.height;
658 crop_image->page.x=bounding_box.x;
659 crop_image->page.y=bounding_box.y;
665 image_view=AcquireVirtualCacheView(image,exception);
666 crop_view=AcquireAuthenticCacheView(crop_image,exception);
667 #if defined(MAGICKCORE_OPENMP_SUPPORT)
668 #pragma omp parallel for schedule(static,4) shared(status) \
669 magick_threads(image,crop_image,1,1)
671 for (y=0; y < (ssize_t) crop_image->rows; y++)
673 register const Quantum
682 if (status == MagickFalse)
684 p=GetCacheViewVirtualPixels(image_view,page.x,page.y+y,crop_image->columns,
686 q=QueueCacheViewAuthenticPixels(crop_view,0,y,crop_image->columns,1,
688 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
693 for (x=0; x < (ssize_t) crop_image->columns; x++)
698 if (GetPixelMask(image,p) != 0)
700 p+=GetPixelChannels(image);
701 q+=GetPixelChannels(crop_image);
704 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
706 PixelChannel channel=GetPixelChannelChannel(image,i);
707 PixelTrait traits=GetPixelChannelTraits(image,channel);
708 PixelTrait crop_traits=GetPixelChannelTraits(crop_image,channel);
709 if ((traits == UndefinedPixelTrait) ||
710 (crop_traits == UndefinedPixelTrait))
712 SetPixelChannel(crop_image,channel,p[i],q);
714 p+=GetPixelChannels(image);
715 q+=GetPixelChannels(crop_image);
717 if (SyncCacheViewAuthenticPixels(crop_view,exception) == MagickFalse)
719 if (image->progress_monitor != (MagickProgressMonitor) NULL)
724 #if defined(MAGICKCORE_OPENMP_SUPPORT)
725 #pragma omp critical (MagickCore_CropImage)
727 proceed=SetImageProgress(image,CropImageTag,progress++,image->rows);
728 if (proceed == MagickFalse)
732 crop_view=DestroyCacheView(crop_view);
733 image_view=DestroyCacheView(image_view);
734 crop_image->type=image->type;
735 if (status == MagickFalse)
736 crop_image=DestroyImage(crop_image);
741 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
745 % C r o p I m a g e T o T i l e s %
749 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
751 % CropImageToTiles() crops a single image, into a possible list of tiles.
752 % This may include a single sub-region of the image. This basically applies
753 % all the normal geometry flags for Crop.
755 % Image *CropImageToTiles(const Image *image,
756 % const RectangleInfo *crop_geometry, ExceptionInfo *exception)
758 % A description of each parameter follows:
760 % o image: the image The transformed image is returned as this parameter.
762 % o crop_geometry: A crop geometry string.
764 % o exception: return any errors or warnings in this structure.
768 static inline ssize_t MagickRound(double x)
771 Round the fraction to nearest integer.
774 return((ssize_t) (x+0.5));
775 return((ssize_t) (x-0.5));
778 MagickExport Image *CropImageToTiles(const Image *image,
779 const char *crop_geometry,ExceptionInfo *exception)
791 assert(image != (Image *) NULL);
792 assert(image->signature == MagickSignature);
793 if (image->debug != MagickFalse)
794 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
795 crop_image=NewImageList();
797 flags=ParseGravityGeometry(image,crop_geometry,&geometry,exception);
798 if ((flags & AreaValue) != 0)
812 Crop into NxM tiles (@ flag).
814 width=image->columns;
816 if (geometry.width == 0)
818 if (geometry.height == 0)
820 if ((flags & AspectValue) == 0)
822 width-=(geometry.x < 0 ? -1 : 1)*geometry.x;
823 height-=(geometry.y < 0 ? -1 : 1)*geometry.y;
827 width+=(geometry.x < 0 ? -1 : 1)*geometry.x;
828 height+=(geometry.y < 0 ? -1 : 1)*geometry.y;
830 delta.x=(double) width/geometry.width;
831 delta.y=(double) height/geometry.height;
836 for (offset.y=0; offset.y < (double) height; )
838 if ((flags & AspectValue) == 0)
840 crop.y=(ssize_t) MagickRound((double) (offset.y-
841 (geometry.y > 0 ? 0 : geometry.y)));
842 offset.y+=delta.y; /* increment now to find width */
843 crop.height=(size_t) MagickRound((double) (offset.y+
844 (geometry.y < 0 ? 0 : geometry.y)));
848 crop.y=(ssize_t) MagickRound((double) (offset.y-
849 (geometry.y > 0 ? geometry.y : 0)));
850 offset.y+=delta.y; /* increment now to find width */
851 crop.height=(size_t) MagickRound((double)
852 (offset.y+(geometry.y < -1 ? geometry.y : 0)));
855 crop.y+=image->page.y;
856 for (offset.x=0; offset.x < (double) width; )
858 if ((flags & AspectValue) == 0)
860 crop.x=(ssize_t) MagickRound((double) (offset.x-
861 (geometry.x > 0 ? 0 : geometry.x)));
862 offset.x+=delta.x; /* increment now to find height */
863 crop.width=(size_t) MagickRound((double) (offset.x+
864 (geometry.x < 0 ? 0 : geometry.x)));
868 crop.x=(ssize_t) MagickRound((double) (offset.x-
869 (geometry.x > 0 ? geometry.x : 0)));
870 offset.x+=delta.x; /* increment now to find height */
871 crop.width=(size_t) MagickRound((double) (offset.x+
872 (geometry.x < 0 ? geometry.x : 0)));
875 crop.x+=image->page.x;
876 next=CropImage(image,&crop,exception);
877 if (next == (Image *) NULL)
879 AppendImageToList(&crop_image,next);
881 if (next == (Image *) NULL)
884 ClearMagickException(exception);
887 if (((geometry.width == 0) && (geometry.height == 0)) ||
888 ((flags & XValue) != 0) || ((flags & YValue) != 0))
891 Crop a single region at +X+Y.
893 crop_image=CropImage(image,&geometry,exception);
894 if ((crop_image != (Image *) NULL) && ((flags & AspectValue) != 0))
896 crop_image->page.width=geometry.width;
897 crop_image->page.height=geometry.height;
898 crop_image->page.x-=geometry.x;
899 crop_image->page.y-=geometry.y;
903 if ((image->columns > geometry.width) || (image->rows > geometry.height))
917 Crop into tiles of fixed size WxH.
921 page.width=image->columns;
922 if (page.height == 0)
923 page.height=image->rows;
924 width=geometry.width;
927 height=geometry.height;
931 for (y=0; y < (ssize_t) page.height; y+=(ssize_t) height)
933 for (x=0; x < (ssize_t) page.width; x+=(ssize_t) width)
935 geometry.width=width;
936 geometry.height=height;
939 next=CropImage(image,&geometry,exception);
940 if (next == (Image *) NULL)
942 AppendImageToList(&crop_image,next);
944 if (next == (Image *) NULL)
949 return(CloneImage(image,0,0,MagickTrue,exception));
953 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
957 % E x c e r p t I m a g e %
961 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
963 % ExcerptImage() returns a excerpt of the image as defined by the geometry.
965 % The format of the ExcerptImage method is:
967 % Image *ExcerptImage(const Image *image,const RectangleInfo *geometry,
968 % ExceptionInfo *exception)
970 % A description of each parameter follows:
972 % o image: the image.
974 % o geometry: Define the region of the image to extend with members
975 % x, y, width, and height.
977 % o exception: return any errors or warnings in this structure.
980 MagickExport Image *ExcerptImage(const Image *image,
981 const RectangleInfo *geometry,ExceptionInfo *exception)
983 #define ExcerptImageTag "Excerpt/Image"
1002 Allocate excerpt image.
1004 assert(image != (const Image *) NULL);
1005 assert(image->signature == MagickSignature);
1006 if (image->debug != MagickFalse)
1007 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1008 assert(geometry != (const RectangleInfo *) NULL);
1009 assert(exception != (ExceptionInfo *) NULL);
1010 assert(exception->signature == MagickSignature);
1011 excerpt_image=CloneImage(image,geometry->width,geometry->height,MagickTrue,
1013 if (excerpt_image == (Image *) NULL)
1014 return((Image *) NULL);
1020 image_view=AcquireVirtualCacheView(image,exception);
1021 excerpt_view=AcquireAuthenticCacheView(excerpt_image,exception);
1022 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1023 #pragma omp parallel for schedule(static,4) shared(progress,status) \
1024 magick_threads(image,excerpt_image,excerpt_image->rows,1)
1026 for (y=0; y < (ssize_t) excerpt_image->rows; y++)
1028 register const Quantum
1037 if (status == MagickFalse)
1039 p=GetCacheViewVirtualPixels(image_view,geometry->x,geometry->y+y,
1040 geometry->width,1,exception);
1041 q=GetCacheViewAuthenticPixels(excerpt_view,0,y,excerpt_image->columns,1,
1043 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1048 for (x=0; x < (ssize_t) excerpt_image->columns; x++)
1053 if (GetPixelMask(image,p) != 0)
1055 p+=GetPixelChannels(image);
1056 q+=GetPixelChannels(excerpt_image);
1059 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1061 PixelChannel channel=GetPixelChannelChannel(image,i);
1062 PixelTrait traits=GetPixelChannelTraits(image,channel);
1063 PixelTrait excerpt_traits=GetPixelChannelTraits(excerpt_image,channel);
1064 if ((traits == UndefinedPixelTrait) ||
1065 (excerpt_traits == UndefinedPixelTrait))
1067 SetPixelChannel(excerpt_image,channel,p[i],q);
1069 p+=GetPixelChannels(image);
1070 q+=GetPixelChannels(excerpt_image);
1072 if (SyncCacheViewAuthenticPixels(excerpt_view,exception) == MagickFalse)
1074 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1079 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1080 #pragma omp critical (MagickCore_ExcerptImage)
1082 proceed=SetImageProgress(image,ExcerptImageTag,progress++,image->rows);
1083 if (proceed == MagickFalse)
1087 excerpt_view=DestroyCacheView(excerpt_view);
1088 image_view=DestroyCacheView(image_view);
1089 excerpt_image->type=image->type;
1090 if (status == MagickFalse)
1091 excerpt_image=DestroyImage(excerpt_image);
1092 return(excerpt_image);
1096 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1100 % E x t e n t I m a g e %
1104 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1106 % ExtentImage() extends the image as defined by the geometry, gravity, and
1107 % image background color. Set the (x,y) offset of the geometry to move the
1108 % original image relative to the extended image.
1110 % The format of the ExtentImage method is:
1112 % Image *ExtentImage(const Image *image,const RectangleInfo *geometry,
1113 % ExceptionInfo *exception)
1115 % A description of each parameter follows:
1117 % o image: the image.
1119 % o geometry: Define the region of the image to extend with members
1120 % x, y, width, and height.
1122 % o exception: return any errors or warnings in this structure.
1125 MagickExport Image *ExtentImage(const Image *image,
1126 const RectangleInfo *geometry,ExceptionInfo *exception)
1132 Allocate extent image.
1134 assert(image != (const Image *) NULL);
1135 assert(image->signature == MagickSignature);
1136 if (image->debug != MagickFalse)
1137 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1138 assert(geometry != (const RectangleInfo *) NULL);
1139 assert(exception != (ExceptionInfo *) NULL);
1140 assert(exception->signature == MagickSignature);
1141 extent_image=CloneImage(image,geometry->width,geometry->height,MagickTrue,
1143 if (extent_image == (Image *) NULL)
1144 return((Image *) NULL);
1145 if (SetImageStorageClass(extent_image,DirectClass,exception) == MagickFalse)
1147 extent_image=DestroyImage(extent_image);
1148 return((Image *) NULL);
1150 if (extent_image->background_color.alpha != OpaqueAlpha)
1151 extent_image->alpha_trait=BlendPixelTrait;
1152 (void) SetImageBackgroundColor(extent_image,exception);
1153 (void) CompositeImage(extent_image,image,image->compose,MagickTrue,
1154 -geometry->x,-geometry->y,exception);
1155 return(extent_image);
1159 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1163 % F l i p I m a g e %
1167 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1169 % FlipImage() creates a vertical mirror image by reflecting the pixels
1170 % around the central x-axis.
1172 % The format of the FlipImage method is:
1174 % Image *FlipImage(const Image *image,ExceptionInfo *exception)
1176 % A description of each parameter follows:
1178 % o image: the image.
1180 % o exception: return any errors or warnings in this structure.
1183 MagickExport Image *FlipImage(const Image *image,ExceptionInfo *exception)
1185 #define FlipImageTag "Flip/Image"
1206 assert(image != (const Image *) NULL);
1207 assert(image->signature == MagickSignature);
1208 if (image->debug != MagickFalse)
1209 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1210 assert(exception != (ExceptionInfo *) NULL);
1211 assert(exception->signature == MagickSignature);
1212 flip_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
1213 if (flip_image == (Image *) NULL)
1214 return((Image *) NULL);
1221 image_view=AcquireVirtualCacheView(image,exception);
1222 flip_view=AcquireAuthenticCacheView(flip_image,exception);
1223 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1224 #pragma omp parallel for schedule(static,4) shared(status) \
1225 magick_threads(image,flip_image,1,1)
1227 for (y=0; y < (ssize_t) flip_image->rows; y++)
1229 register const Quantum
1238 if (status == MagickFalse)
1240 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1241 q=QueueCacheViewAuthenticPixels(flip_view,0,(ssize_t) (flip_image->rows-y-
1242 1),flip_image->columns,1,exception);
1243 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1248 for (x=0; x < (ssize_t) flip_image->columns; x++)
1253 if (GetPixelMask(image,p) != 0)
1255 p+=GetPixelChannels(image);
1256 q+=GetPixelChannels(flip_image);
1259 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1261 PixelChannel channel=GetPixelChannelChannel(image,i);
1262 PixelTrait traits=GetPixelChannelTraits(image,channel);
1263 PixelTrait flip_traits=GetPixelChannelTraits(flip_image,channel);
1264 if ((traits == UndefinedPixelTrait) ||
1265 (flip_traits == UndefinedPixelTrait))
1267 SetPixelChannel(flip_image,channel,p[i],q);
1269 p+=GetPixelChannels(image);
1270 q+=GetPixelChannels(flip_image);
1272 if (SyncCacheViewAuthenticPixels(flip_view,exception) == MagickFalse)
1274 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1279 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1280 #pragma omp critical (MagickCore_FlipImage)
1282 proceed=SetImageProgress(image,FlipImageTag,progress++,image->rows);
1283 if (proceed == MagickFalse)
1287 flip_view=DestroyCacheView(flip_view);
1288 image_view=DestroyCacheView(image_view);
1289 flip_image->type=image->type;
1290 if (page.height != 0)
1291 page.y=(ssize_t) (page.height-flip_image->rows-page.y);
1292 flip_image->page=page;
1293 if (status == MagickFalse)
1294 flip_image=DestroyImage(flip_image);
1299 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1303 % F l o p I m a g e %
1307 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1309 % FlopImage() creates a horizontal mirror image by reflecting the pixels
1310 % around the central y-axis.
1312 % The format of the FlopImage method is:
1314 % Image *FlopImage(const Image *image,ExceptionInfo *exception)
1316 % A description of each parameter follows:
1318 % o image: the image.
1320 % o exception: return any errors or warnings in this structure.
1323 MagickExport Image *FlopImage(const Image *image,ExceptionInfo *exception)
1325 #define FlopImageTag "Flop/Image"
1346 assert(image != (const Image *) NULL);
1347 assert(image->signature == MagickSignature);
1348 if (image->debug != MagickFalse)
1349 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1350 assert(exception != (ExceptionInfo *) NULL);
1351 assert(exception->signature == MagickSignature);
1352 flop_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
1353 if (flop_image == (Image *) NULL)
1354 return((Image *) NULL);
1361 image_view=AcquireVirtualCacheView(image,exception);
1362 flop_view=AcquireAuthenticCacheView(flop_image,exception);
1363 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1364 #pragma omp parallel for schedule(static,4) shared(status) \
1365 magick_threads(image,flop_image,1,1)
1367 for (y=0; y < (ssize_t) flop_image->rows; y++)
1369 register const Quantum
1378 if (status == MagickFalse)
1380 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1381 q=QueueCacheViewAuthenticPixels(flop_view,0,y,flop_image->columns,1,
1383 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1388 q+=GetPixelChannels(flop_image)*flop_image->columns;
1389 for (x=0; x < (ssize_t) flop_image->columns; x++)
1394 q-=GetPixelChannels(flop_image);
1395 if (GetPixelMask(image,p) != 0)
1397 p+=GetPixelChannels(image);
1400 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1402 PixelChannel channel=GetPixelChannelChannel(image,i);
1403 PixelTrait traits=GetPixelChannelTraits(image,channel);
1404 PixelTrait flop_traits=GetPixelChannelTraits(flop_image,channel);
1405 if ((traits == UndefinedPixelTrait) ||
1406 (flop_traits == UndefinedPixelTrait))
1408 SetPixelChannel(flop_image,channel,p[i],q);
1410 p+=GetPixelChannels(image);
1412 if (SyncCacheViewAuthenticPixels(flop_view,exception) == MagickFalse)
1414 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1419 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1420 #pragma omp critical (MagickCore_FlopImage)
1422 proceed=SetImageProgress(image,FlopImageTag,progress++,image->rows);
1423 if (proceed == MagickFalse)
1427 flop_view=DestroyCacheView(flop_view);
1428 image_view=DestroyCacheView(image_view);
1429 flop_image->type=image->type;
1430 if (page.width != 0)
1431 page.x=(ssize_t) (page.width-flop_image->columns-page.x);
1432 flop_image->page=page;
1433 if (status == MagickFalse)
1434 flop_image=DestroyImage(flop_image);
1439 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1443 % R o l l I m a g e %
1447 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1449 % RollImage() offsets an image as defined by x_offset and y_offset.
1451 % The format of the RollImage method is:
1453 % Image *RollImage(const Image *image,const ssize_t x_offset,
1454 % const ssize_t y_offset,ExceptionInfo *exception)
1456 % A description of each parameter follows:
1458 % o image: the image.
1460 % o x_offset: the number of columns to roll in the horizontal direction.
1462 % o y_offset: the number of rows to roll in the vertical direction.
1464 % o exception: return any errors or warnings in this structure.
1468 static inline MagickBooleanType CopyImageRegion(Image *destination,
1469 const Image *source,const size_t columns,const size_t rows,
1470 const ssize_t sx,const ssize_t sy,const ssize_t dx,const ssize_t dy,
1471 ExceptionInfo *exception)
1484 source_view=AcquireVirtualCacheView(source,exception);
1485 destination_view=AcquireAuthenticCacheView(destination,exception);
1486 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1487 #pragma omp parallel for schedule(static,4) shared(status) \
1488 magick_threads(source,destination,rows,1)
1490 for (y=0; y < (ssize_t) rows; y++)
1495 register const Quantum
1507 if (status == MagickFalse)
1509 p=GetCacheViewVirtualPixels(source_view,sx,sy+y,columns,1,exception);
1510 q=GetCacheViewAuthenticPixels(destination_view,dx,dy+y,columns,1,exception);
1511 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1516 for (x=0; x < (ssize_t) columns; x++)
1521 if (GetPixelMask(source,p) != 0)
1523 p+=GetPixelChannels(source);
1524 q+=GetPixelChannels(destination);
1527 for (i=0; i < (ssize_t) GetPixelChannels(source); i++)
1529 PixelChannel channel=GetPixelChannelChannel(source,i);
1530 PixelTrait source_traits=GetPixelChannelTraits(source,channel);
1531 PixelTrait destination_traits=GetPixelChannelTraits(destination,
1533 if ((source_traits == UndefinedPixelTrait) ||
1534 (destination_traits == UndefinedPixelTrait))
1536 SetPixelChannel(destination,channel,p[i],q);
1538 p+=GetPixelChannels(source);
1539 q+=GetPixelChannels(destination);
1541 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
1542 if (sync == MagickFalse)
1545 destination_view=DestroyCacheView(destination_view);
1546 source_view=DestroyCacheView(source_view);
1550 MagickExport Image *RollImage(const Image *image,const ssize_t x_offset,
1551 const ssize_t y_offset,ExceptionInfo *exception)
1553 #define RollImageTag "Roll/Image"
1565 Initialize roll image attributes.
1567 assert(image != (const Image *) NULL);
1568 assert(image->signature == MagickSignature);
1569 if (image->debug != MagickFalse)
1570 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1571 assert(exception != (ExceptionInfo *) NULL);
1572 assert(exception->signature == MagickSignature);
1573 roll_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
1574 if (roll_image == (Image *) NULL)
1575 return((Image *) NULL);
1578 while (offset.x < 0)
1579 offset.x+=(ssize_t) image->columns;
1580 while (offset.x >= (ssize_t) image->columns)
1581 offset.x-=(ssize_t) image->columns;
1582 while (offset.y < 0)
1583 offset.y+=(ssize_t) image->rows;
1584 while (offset.y >= (ssize_t) image->rows)
1585 offset.y-=(ssize_t) image->rows;
1589 status=CopyImageRegion(roll_image,image,(size_t) offset.x,
1590 (size_t) offset.y,(ssize_t) image->columns-offset.x,(ssize_t) image->rows-
1591 offset.y,0,0,exception);
1592 (void) SetImageProgress(image,RollImageTag,0,3);
1593 status|=CopyImageRegion(roll_image,image,image->columns-offset.x,
1594 (size_t) offset.y,0,(ssize_t) image->rows-offset.y,offset.x,0,
1596 (void) SetImageProgress(image,RollImageTag,1,3);
1597 status|=CopyImageRegion(roll_image,image,(size_t) offset.x,image->rows-
1598 offset.y,(ssize_t) image->columns-offset.x,0,0,offset.y,exception);
1599 (void) SetImageProgress(image,RollImageTag,2,3);
1600 status|=CopyImageRegion(roll_image,image,image->columns-offset.x,image->rows-
1601 offset.y,0,0,offset.x,offset.y,exception);
1602 (void) SetImageProgress(image,RollImageTag,3,3);
1603 roll_image->type=image->type;
1604 if (status == MagickFalse)
1605 roll_image=DestroyImage(roll_image);
1610 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1614 % S h a v e I m a g e %
1618 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1620 % ShaveImage() shaves pixels from the image edges. It allocates the memory
1621 % necessary for the new Image structure and returns a pointer to the new
1624 % The format of the ShaveImage method is:
1626 % Image *ShaveImage(const Image *image,const RectangleInfo *shave_info,
1627 % ExceptionInfo *exception)
1629 % A description of each parameter follows:
1631 % o shave_image: Method ShaveImage returns a pointer to the shaved
1632 % image. A null image is returned if there is a memory shortage or
1633 % if the image width or height is zero.
1635 % o image: the image.
1637 % o shave_info: Specifies a pointer to a RectangleInfo which defines the
1638 % region of the image to crop.
1640 % o exception: return any errors or warnings in this structure.
1643 MagickExport Image *ShaveImage(const Image *image,
1644 const RectangleInfo *shave_info,ExceptionInfo *exception)
1652 assert(image != (const Image *) NULL);
1653 assert(image->signature == MagickSignature);
1654 if (image->debug != MagickFalse)
1655 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1656 if (((2*shave_info->width) >= image->columns) ||
1657 ((2*shave_info->height) >= image->rows))
1658 ThrowImageException(OptionWarning,"GeometryDoesNotContainImage");
1659 SetGeometry(image,&geometry);
1660 geometry.width-=2*shave_info->width;
1661 geometry.height-=2*shave_info->height;
1662 geometry.x=(ssize_t) shave_info->width+image->page.x;
1663 geometry.y=(ssize_t) shave_info->height+image->page.y;
1664 shave_image=CropImage(image,&geometry,exception);
1665 if (shave_image == (Image *) NULL)
1666 return((Image *) NULL);
1667 shave_image->page.width-=2*shave_info->width;
1668 shave_image->page.height-=2*shave_info->height;
1669 shave_image->page.x-=(ssize_t) shave_info->width;
1670 shave_image->page.y-=(ssize_t) shave_info->height;
1671 return(shave_image);
1675 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1679 % S p l i c e I m a g e %
1683 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1685 % SpliceImage() splices a solid color into the image as defined by the
1688 % The format of the SpliceImage method is:
1690 % Image *SpliceImage(const Image *image,const RectangleInfo *geometry,
1691 % ExceptionInfo *exception)
1693 % A description of each parameter follows:
1695 % o image: the image.
1697 % o geometry: Define the region of the image to splice with members
1698 % x, y, width, and height.
1700 % o exception: return any errors or warnings in this structure.
1703 MagickExport Image *SpliceImage(const Image *image,
1704 const RectangleInfo *geometry,ExceptionInfo *exception)
1706 #define SpliceImageTag "Splice/Image"
1728 Allocate splice image.
1730 assert(image != (const Image *) NULL);
1731 assert(image->signature == MagickSignature);
1732 if (image->debug != MagickFalse)
1733 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1734 assert(geometry != (const RectangleInfo *) NULL);
1735 assert(exception != (ExceptionInfo *) NULL);
1736 assert(exception->signature == MagickSignature);
1737 splice_geometry=(*geometry);
1738 splice_image=CloneImage(image,image->columns+splice_geometry.width,
1739 image->rows+splice_geometry.height,MagickTrue,exception);
1740 if (splice_image == (Image *) NULL)
1741 return((Image *) NULL);
1742 if (SetImageStorageClass(splice_image,DirectClass,exception) == MagickFalse)
1744 splice_image=DestroyImage(splice_image);
1745 return((Image *) NULL);
1747 (void) SetImageBackgroundColor(splice_image,exception);
1749 Respect image geometry.
1751 switch (image->gravity)
1754 case UndefinedGravity:
1755 case NorthWestGravity:
1759 splice_geometry.x+=(ssize_t) splice_geometry.width/2;
1762 case NorthEastGravity:
1764 splice_geometry.x+=(ssize_t) splice_geometry.width;
1769 splice_geometry.y+=(ssize_t) splice_geometry.width/2;
1774 splice_geometry.x+=(ssize_t) splice_geometry.width/2;
1775 splice_geometry.y+=(ssize_t) splice_geometry.height/2;
1780 splice_geometry.x+=(ssize_t) splice_geometry.width;
1781 splice_geometry.y+=(ssize_t) splice_geometry.height/2;
1784 case SouthWestGravity:
1786 splice_geometry.y+=(ssize_t) splice_geometry.height;
1791 splice_geometry.x+=(ssize_t) splice_geometry.width/2;
1792 splice_geometry.y+=(ssize_t) splice_geometry.height;
1795 case SouthEastGravity:
1797 splice_geometry.x+=(ssize_t) splice_geometry.width;
1798 splice_geometry.y+=(ssize_t) splice_geometry.height;
1807 image_view=AcquireVirtualCacheView(image,exception);
1808 splice_view=AcquireAuthenticCacheView(splice_image,exception);
1809 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1810 #pragma omp parallel for schedule(static,4) shared(progress,status) \
1811 magick_threads(image,splice_image,1,1)
1813 for (y=0; y < (ssize_t) splice_geometry.y; y++)
1815 register const Quantum
1824 if (status == MagickFalse)
1826 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1827 q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1,
1829 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1834 for (x=0; x < splice_geometry.x; x++)
1839 if (GetPixelMask(image,p) != 0)
1841 p+=GetPixelChannels(image);
1842 q+=GetPixelChannels(splice_image);
1845 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1847 PixelChannel channel=GetPixelChannelChannel(image,i);
1848 PixelTrait traits=GetPixelChannelTraits(image,channel);
1849 PixelTrait splice_traits=GetPixelChannelTraits(splice_image,channel);
1850 if ((traits == UndefinedPixelTrait) ||
1851 (splice_traits == UndefinedPixelTrait))
1853 SetPixelChannel(splice_image,channel,p[i],q);
1855 p+=GetPixelChannels(image);
1856 q+=GetPixelChannels(splice_image);
1858 for ( ; x < (ssize_t) (splice_geometry.x+splice_geometry.width); x++)
1859 q+=GetPixelChannels(splice_image);
1860 for ( ; x < (ssize_t) splice_image->columns; x++)
1865 if (GetPixelMask(image,p) != 0)
1867 p+=GetPixelChannels(image);
1868 q+=GetPixelChannels(splice_image);
1871 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1873 PixelChannel channel=GetPixelChannelChannel(image,i);
1874 PixelTrait traits=GetPixelChannelTraits(image,channel);
1875 PixelTrait splice_traits=GetPixelChannelTraits(splice_image,channel);
1876 if ((traits == UndefinedPixelTrait) ||
1877 (splice_traits == UndefinedPixelTrait))
1879 SetPixelChannel(splice_image,channel,p[i],q);
1881 p+=GetPixelChannels(image);
1882 q+=GetPixelChannels(splice_image);
1884 if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse)
1886 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1891 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1892 #pragma omp critical (MagickCore_TransposeImage)
1894 proceed=SetImageProgress(image,SpliceImageTag,progress++,
1895 splice_image->rows);
1896 if (proceed == MagickFalse)
1900 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1901 #pragma omp parallel for schedule(static,4) shared(progress,status) \
1902 magick_threads(image,splice_image,1,1)
1904 for (y=(ssize_t) (splice_geometry.y+splice_geometry.height);
1905 y < (ssize_t) splice_image->rows; y++)
1907 register const Quantum
1916 if (status == MagickFalse)
1918 p=GetCacheViewVirtualPixels(image_view,0,y-(ssize_t) splice_geometry.height,
1919 image->columns,1,exception);
1920 if ((y < 0) || (y >= (ssize_t) splice_image->rows))
1922 q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1,
1924 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1929 for (x=0; x < splice_geometry.x; x++)
1934 if (GetPixelMask(image,q) != 0)
1936 p+=GetPixelChannels(image);
1937 q+=GetPixelChannels(splice_image);
1940 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1942 PixelChannel channel=GetPixelChannelChannel(image,i);
1943 PixelTrait traits=GetPixelChannelTraits(image,channel);
1944 PixelTrait splice_traits=GetPixelChannelTraits(splice_image,channel);
1945 if ((traits == UndefinedPixelTrait) ||
1946 (splice_traits == UndefinedPixelTrait))
1948 SetPixelChannel(splice_image,channel,p[i],q);
1950 p+=GetPixelChannels(image);
1951 q+=GetPixelChannels(splice_image);
1953 for ( ; x < (ssize_t) (splice_geometry.x+splice_geometry.width); x++)
1954 q+=GetPixelChannels(splice_image);
1955 for ( ; x < (ssize_t) splice_image->columns; x++)
1960 if (GetPixelMask(image,q) != 0)
1962 p+=GetPixelChannels(image);
1963 q+=GetPixelChannels(splice_image);
1966 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1968 PixelChannel channel=GetPixelChannelChannel(image,i);
1969 PixelTrait traits=GetPixelChannelTraits(image,channel);
1970 PixelTrait splice_traits=GetPixelChannelTraits(splice_image,channel);
1971 if ((traits == UndefinedPixelTrait) ||
1972 (splice_traits == UndefinedPixelTrait))
1974 SetPixelChannel(splice_image,channel,p[i],q);
1976 p+=GetPixelChannels(image);
1977 q+=GetPixelChannels(splice_image);
1979 if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse)
1981 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1986 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1987 #pragma omp critical (MagickCore_TransposeImage)
1989 proceed=SetImageProgress(image,SpliceImageTag,progress++,
1990 splice_image->rows);
1991 if (proceed == MagickFalse)
1995 splice_view=DestroyCacheView(splice_view);
1996 image_view=DestroyCacheView(image_view);
1997 if (status == MagickFalse)
1998 splice_image=DestroyImage(splice_image);
1999 return(splice_image);
2003 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2007 % T r a n s f o r m I m a g e %
2011 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2013 % TransformImage() is a convenience method that behaves like ResizeImage() or
2014 % CropImage() but accepts scaling and/or cropping information as a region
2015 % geometry specification. If the operation fails, the original image handle
2018 % This should only be used for single images.
2020 % This function destroys what it assumes to be a single image list.
2021 % If the input image is part of a larger list, all other images in that list
2022 % will be simply 'lost', not destroyed.
2024 % Also if the crop generates a list of images only the first image is resized.
2025 % And finally if the crop succeeds and the resize failed, you will get a
2026 % cropped image, as well as a 'false' or 'failed' report.
2028 % This function and should probably be depreciated in favor of direct calls
2029 % to CropImageToTiles() or ResizeImage(), as appropriate.
2031 % The format of the TransformImage method is:
2033 % MagickBooleanType TransformImage(Image **image,const char *crop_geometry,
2034 % const char *image_geometry,ExceptionInfo *exception)
2036 % A description of each parameter follows:
2038 % o image: the image The transformed image is returned as this parameter.
2040 % o crop_geometry: A crop geometry string. This geometry defines a
2041 % subregion of the image to crop.
2043 % o image_geometry: An image geometry string. This geometry defines the
2044 % final size of the image.
2046 % o exception: return any errors or warnings in this structure.
2049 MagickExport MagickBooleanType TransformImage(Image **image,
2050 const char *crop_geometry,const char *image_geometry,ExceptionInfo *exception)
2062 assert(image != (Image **) NULL);
2063 assert((*image)->signature == MagickSignature);
2064 if ((*image)->debug != MagickFalse)
2065 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
2066 transform_image=(*image);
2067 if (crop_geometry != (const char *) NULL)
2073 Crop image to a user specified size.
2075 crop_image=CropImageToTiles(*image,crop_geometry,exception);
2076 if (crop_image == (Image *) NULL)
2077 transform_image=CloneImage(*image,0,0,MagickTrue,exception);
2080 transform_image=DestroyImage(transform_image);
2081 transform_image=GetFirstImageInList(crop_image);
2083 *image=transform_image;
2085 if (image_geometry == (const char *) NULL)
2089 Scale image to a user specified size.
2091 flags=ParseRegionGeometry(transform_image,image_geometry,&geometry,exception);
2093 if ((transform_image->columns == geometry.width) &&
2094 (transform_image->rows == geometry.height))
2096 resize_image=ResizeImage(transform_image,geometry.width,geometry.height,
2097 transform_image->filter,exception);
2098 if (resize_image == (Image *) NULL)
2099 return(MagickFalse);
2100 transform_image=DestroyImage(transform_image);
2101 transform_image=resize_image;
2102 *image=transform_image;
2107 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2111 % T r a n s f o r m I m a g e s %
2115 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2117 % TransformImages() calls TransformImage() on each image of a sequence.
2119 % The format of the TransformImage method is:
2121 % MagickBooleanType TransformImages(Image **image,
2122 % const char *crop_geometry,const char *image_geometry,
2123 % ExceptionInfo *exception)
2125 % A description of each parameter follows:
2127 % o image: the image The transformed image is returned as this parameter.
2129 % o crop_geometry: A crop geometry string. This geometry defines a
2130 % subregion of the image to crop.
2132 % o image_geometry: An image geometry string. This geometry defines the
2133 % final size of the image.
2135 % o exception: return any errors or warnings in this structure.
2138 MagickExport MagickBooleanType TransformImages(Image **images,
2139 const char *crop_geometry,const char *image_geometry,ExceptionInfo *exception)
2152 assert(images != (Image **) NULL);
2153 assert((*images)->signature == MagickSignature);
2154 if ((*images)->debug != MagickFalse)
2155 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2156 (*images)->filename);
2157 image_list=ImageListToArray(*images,exception);
2158 if (image_list == (Image **) NULL)
2159 return(MagickFalse);
2161 transform_images=NewImageList();
2162 for (i=0; image_list[i] != (Image *) NULL; i++)
2164 image=image_list[i];
2165 status|=TransformImage(&image,crop_geometry,image_geometry,exception);
2166 AppendImageToList(&transform_images,image);
2168 *images=transform_images;
2169 image_list=(Image **) RelinquishMagickMemory(image_list);
2170 return(status != 0 ? MagickTrue : MagickFalse);
2174 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2178 % T r a n s p o s e I m a g e %
2182 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2184 % TransposeImage() creates a horizontal mirror image by reflecting the pixels
2185 % around the central y-axis while rotating them by 90 degrees.
2187 % The format of the TransposeImage method is:
2189 % Image *TransposeImage(const Image *image,ExceptionInfo *exception)
2191 % A description of each parameter follows:
2193 % o image: the image.
2195 % o exception: return any errors or warnings in this structure.
2198 MagickExport Image *TransposeImage(const Image *image,ExceptionInfo *exception)
2200 #define TransposeImageTag "Transpose/Image"
2221 assert(image != (const Image *) NULL);
2222 assert(image->signature == MagickSignature);
2223 if (image->debug != MagickFalse)
2224 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2225 assert(exception != (ExceptionInfo *) NULL);
2226 assert(exception->signature == MagickSignature);
2227 transpose_image=CloneImage(image,image->rows,image->columns,MagickTrue,
2229 if (transpose_image == (Image *) NULL)
2230 return((Image *) NULL);
2236 image_view=AcquireVirtualCacheView(image,exception);
2237 transpose_view=AcquireAuthenticCacheView(transpose_image,exception);
2238 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2239 #pragma omp parallel for schedule(static,4) shared(progress,status) \
2240 magick_threads(image,transpose_image,image->rows,1)
2242 for (y=0; y < (ssize_t) image->rows; y++)
2244 register const Quantum
2253 if (status == MagickFalse)
2255 p=GetCacheViewVirtualPixels(image_view,0,(ssize_t) image->rows-y-1,
2256 image->columns,1,exception);
2257 q=QueueCacheViewAuthenticPixels(transpose_view,(ssize_t) (image->rows-y-1),
2258 0,1,transpose_image->rows,exception);
2259 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2264 for (x=0; x < (ssize_t) image->columns; x++)
2269 if (GetPixelMask(image,q) != 0)
2271 p+=GetPixelChannels(image);
2272 q+=GetPixelChannels(transpose_image);
2275 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2277 PixelChannel channel=GetPixelChannelChannel(image,i);
2278 PixelTrait traits=GetPixelChannelTraits(image,channel);
2279 PixelTrait transpose_traits=GetPixelChannelTraits(transpose_image,
2281 if ((traits == UndefinedPixelTrait) ||
2282 (transpose_traits == UndefinedPixelTrait))
2284 SetPixelChannel(transpose_image,channel,p[i],q);
2286 p+=GetPixelChannels(image);
2287 q+=GetPixelChannels(transpose_image);
2289 if (SyncCacheViewAuthenticPixels(transpose_view,exception) == MagickFalse)
2291 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2296 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2297 #pragma omp critical (MagickCore_TransposeImage)
2299 proceed=SetImageProgress(image,TransposeImageTag,progress++,
2301 if (proceed == MagickFalse)
2305 transpose_view=DestroyCacheView(transpose_view);
2306 image_view=DestroyCacheView(image_view);
2307 transpose_image->type=image->type;
2308 page=transpose_image->page;
2309 Swap(page.width,page.height);
2310 Swap(page.x,page.y);
2311 transpose_image->page=page;
2312 if (status == MagickFalse)
2313 transpose_image=DestroyImage(transpose_image);
2314 return(transpose_image);
2318 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2322 % T r a n s v e r s e I m a g e %
2326 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2328 % TransverseImage() creates a vertical mirror image by reflecting the pixels
2329 % around the central x-axis while rotating them by 270 degrees.
2331 % The format of the TransverseImage method is:
2333 % Image *TransverseImage(const Image *image,ExceptionInfo *exception)
2335 % A description of each parameter follows:
2337 % o image: the image.
2339 % o exception: return any errors or warnings in this structure.
2342 MagickExport Image *TransverseImage(const Image *image,ExceptionInfo *exception)
2344 #define TransverseImageTag "Transverse/Image"
2365 assert(image != (const Image *) NULL);
2366 assert(image->signature == MagickSignature);
2367 if (image->debug != MagickFalse)
2368 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2369 assert(exception != (ExceptionInfo *) NULL);
2370 assert(exception->signature == MagickSignature);
2371 transverse_image=CloneImage(image,image->rows,image->columns,MagickTrue,
2373 if (transverse_image == (Image *) NULL)
2374 return((Image *) NULL);
2380 image_view=AcquireVirtualCacheView(image,exception);
2381 transverse_view=AcquireAuthenticCacheView(transverse_image,exception);
2382 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2383 #pragma omp parallel for schedule(static,4) shared(progress,status) \
2384 magick_threads(image,transverse_image,image->rows,1)
2386 for (y=0; y < (ssize_t) image->rows; y++)
2391 register const Quantum
2400 if (status == MagickFalse)
2402 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2403 q=QueueCacheViewAuthenticPixels(transverse_view,(ssize_t) (image->rows-y-1),
2404 0,1,transverse_image->rows,exception);
2405 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2410 q+=GetPixelChannels(transverse_image)*image->columns;
2411 for (x=0; x < (ssize_t) image->columns; x++)
2416 q-=GetPixelChannels(transverse_image);
2417 if (GetPixelMask(image,p) != 0)
2419 p+=GetPixelChannels(image);
2422 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2424 PixelChannel channel=GetPixelChannelChannel(image,i);
2425 PixelTrait traits=GetPixelChannelTraits(image,channel);
2426 PixelTrait transverse_traits=GetPixelChannelTraits(transverse_image,
2428 if ((traits == UndefinedPixelTrait) ||
2429 (transverse_traits == UndefinedPixelTrait))
2431 SetPixelChannel(transverse_image,channel,p[i],q);
2433 p+=GetPixelChannels(image);
2435 sync=SyncCacheViewAuthenticPixels(transverse_view,exception);
2436 if (sync == MagickFalse)
2438 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2443 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2444 #pragma omp critical (MagickCore_TransverseImage)
2446 proceed=SetImageProgress(image,TransverseImageTag,progress++,
2448 if (proceed == MagickFalse)
2452 transverse_view=DestroyCacheView(transverse_view);
2453 image_view=DestroyCacheView(image_view);
2454 transverse_image->type=image->type;
2455 page=transverse_image->page;
2456 Swap(page.width,page.height);
2457 Swap(page.x,page.y);
2458 if (page.width != 0)
2459 page.x=(ssize_t) (page.width-transverse_image->columns-page.x);
2460 if (page.height != 0)
2461 page.y=(ssize_t) (page.height-transverse_image->rows-page.y);
2462 transverse_image->page=page;
2463 if (status == MagickFalse)
2464 transverse_image=DestroyImage(transverse_image);
2465 return(transverse_image);
2469 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2473 % T r i m I m a g e %
2477 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2479 % TrimImage() trims pixels from the image edges. It allocates the memory
2480 % necessary for the new Image structure and returns a pointer to the new
2483 % The format of the TrimImage method is:
2485 % Image *TrimImage(const Image *image,ExceptionInfo *exception)
2487 % A description of each parameter follows:
2489 % o image: the image.
2491 % o exception: return any errors or warnings in this structure.
2494 MagickExport Image *TrimImage(const Image *image,ExceptionInfo *exception)
2499 assert(image != (const Image *) NULL);
2500 assert(image->signature == MagickSignature);
2501 if (image->debug != MagickFalse)
2502 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2503 geometry=GetImageBoundingBox(image,exception);
2504 if ((geometry.width == 0) || (geometry.height == 0))
2509 crop_image=CloneImage(image,1,1,MagickTrue,exception);
2510 if (crop_image == (Image *) NULL)
2511 return((Image *) NULL);
2512 crop_image->background_color.alpha=(Quantum) TransparentAlpha;
2513 (void) SetImageBackgroundColor(crop_image,exception);
2514 crop_image->page=image->page;
2515 crop_image->page.x=(-1);
2516 crop_image->page.y=(-1);
2519 geometry.x+=image->page.x;
2520 geometry.y+=image->page.y;
2521 return(CropImage(image,&geometry,exception));