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-2018 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 % https://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"
69 #include "MagickCore/transform-private.h"
72 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
76 % A u t o O r i e n t I m a g e %
80 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
82 % AutoOrientImage() adjusts an image so that its orientation is suitable for
83 % viewing (i.e. top-left orientation).
85 % The format of the AutoOrientImage method is:
87 % Image *AutoOrientImage(const Image *image,
88 % const OrientationType orientation,ExceptionInfo *exception)
90 % A description of each parameter follows:
94 % o orientation: Current image orientation.
96 % o exception: Return any errors or warnings in this structure.
99 MagickExport Image *AutoOrientImage(const Image *image,
100 const OrientationType orientation,ExceptionInfo *exception)
105 assert(image != (const Image *) NULL);
106 assert(image->signature == MagickCoreSignature);
107 assert(exception != (ExceptionInfo *) NULL);
108 assert(exception->signature == MagickCoreSignature);
109 orient_image=(Image *) NULL;
112 case UndefinedOrientation:
113 case TopLeftOrientation:
116 orient_image=CloneImage(image,0,0,MagickTrue,exception);
119 case TopRightOrientation:
121 orient_image=FlopImage(image,exception);
124 case BottomRightOrientation:
126 orient_image=RotateImage(image,180.0,exception);
129 case BottomLeftOrientation:
131 orient_image=FlipImage(image,exception);
134 case LeftTopOrientation:
136 orient_image=TransposeImage(image,exception);
139 case RightTopOrientation:
141 orient_image=RotateImage(image,90.0,exception);
144 case RightBottomOrientation:
146 orient_image=TransverseImage(image,exception);
149 case LeftBottomOrientation:
151 orient_image=RotateImage(image,270.0,exception);
155 if (orient_image != (Image *) NULL)
156 orient_image->orientation=TopLeftOrientation;
157 return(orient_image);
161 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
165 % C h o p I m a g e %
169 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
171 % ChopImage() removes a region of an image and collapses the image to occupy
172 % the removed portion.
174 % The format of the ChopImage method is:
176 % Image *ChopImage(const Image *image,const RectangleInfo *chop_info)
177 % ExceptionInfo *exception)
179 % A description of each parameter follows:
181 % o image: the image.
183 % o chop_info: Define the region of the image to chop.
185 % o exception: return any errors or warnings in this structure.
188 MagickExport Image *ChopImage(const Image *image,const RectangleInfo *chop_info,
189 ExceptionInfo *exception)
191 #define ChopImageTag "Chop/Image"
215 assert(image != (const Image *) NULL);
216 assert(image->signature == MagickCoreSignature);
217 if (image->debug != MagickFalse)
218 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
219 assert(exception != (ExceptionInfo *) NULL);
220 assert(exception->signature == MagickCoreSignature);
221 assert(chop_info != (RectangleInfo *) NULL);
222 if (((chop_info->x+(ssize_t) chop_info->width) < 0) ||
223 ((chop_info->y+(ssize_t) chop_info->height) < 0) ||
224 (chop_info->x > (ssize_t) image->columns) ||
225 (chop_info->y > (ssize_t) image->rows))
226 ThrowImageException(OptionWarning,"GeometryDoesNotContainImage");
228 if ((extent.x+(ssize_t) extent.width) > (ssize_t) image->columns)
229 extent.width=(size_t) ((ssize_t) image->columns-extent.x);
230 if ((extent.y+(ssize_t) extent.height) > (ssize_t) image->rows)
231 extent.height=(size_t) ((ssize_t) image->rows-extent.y);
234 extent.width-=(size_t) (-extent.x);
239 extent.height-=(size_t) (-extent.y);
242 chop_image=CloneImage(image,image->columns-extent.width,image->rows-
243 extent.height,MagickTrue,exception);
244 if (chop_image == (Image *) NULL)
245 return((Image *) NULL);
251 image_view=AcquireVirtualCacheView(image,exception);
252 chop_view=AcquireAuthenticCacheView(chop_image,exception);
253 #if defined(MAGICKCORE_OPENMP_SUPPORT)
254 #pragma omp parallel for schedule(static) shared(status) \
255 magick_number_threads(image,chop_image,extent.y,1)
257 for (y=0; y < (ssize_t) extent.y; y++)
259 register const Quantum
268 if (status == MagickFalse)
270 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
271 q=QueueCacheViewAuthenticPixels(chop_view,0,y,chop_image->columns,1,
273 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
278 for (x=0; x < (ssize_t) image->columns; x++)
280 if ((x < extent.x) || (x >= (ssize_t) (extent.x+extent.width)))
285 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
287 PixelChannel channel = GetPixelChannelChannel(image,i);
288 PixelTrait traits = GetPixelChannelTraits(image,channel);
289 PixelTrait chop_traits=GetPixelChannelTraits(chop_image,channel);
290 if ((traits == UndefinedPixelTrait) ||
291 (chop_traits == UndefinedPixelTrait))
293 SetPixelChannel(chop_image,channel,p[i],q);
295 q+=GetPixelChannels(chop_image);
297 p+=GetPixelChannels(image);
299 if (SyncCacheViewAuthenticPixels(chop_view,exception) == MagickFalse)
301 if (image->progress_monitor != (MagickProgressMonitor) NULL)
306 #if defined(MAGICKCORE_OPENMP_SUPPORT)
307 #pragma omp critical (MagickCore_ChopImage)
309 proceed=SetImageProgress(image,ChopImageTag,progress++,image->rows);
310 if (proceed == MagickFalse)
317 #if defined(MAGICKCORE_OPENMP_SUPPORT)
318 #pragma omp parallel for schedule(static) shared(progress,status) \
319 magick_number_threads(image,chop_image,image->rows-(extent.y+extent.height),1)
321 for (y=0; y < (ssize_t) (image->rows-(extent.y+extent.height)); y++)
323 register const Quantum
332 if (status == MagickFalse)
334 p=GetCacheViewVirtualPixels(image_view,0,extent.y+extent.height+y,
335 image->columns,1,exception);
336 q=QueueCacheViewAuthenticPixels(chop_view,0,extent.y+y,chop_image->columns,
338 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
343 for (x=0; x < (ssize_t) image->columns; x++)
345 if ((x < extent.x) || (x >= (ssize_t) (extent.x+extent.width)))
350 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
352 PixelChannel channel = GetPixelChannelChannel(image,i);
353 PixelTrait traits = GetPixelChannelTraits(image,channel);
354 PixelTrait chop_traits=GetPixelChannelTraits(chop_image,channel);
355 if ((traits == UndefinedPixelTrait) ||
356 (chop_traits == UndefinedPixelTrait))
358 SetPixelChannel(chop_image,channel,p[i],q);
360 q+=GetPixelChannels(chop_image);
362 p+=GetPixelChannels(image);
364 if (SyncCacheViewAuthenticPixels(chop_view,exception) == MagickFalse)
366 if (image->progress_monitor != (MagickProgressMonitor) NULL)
371 #if defined(MAGICKCORE_OPENMP_SUPPORT)
372 #pragma omp critical (MagickCore_ChopImage)
374 proceed=SetImageProgress(image,ChopImageTag,progress++,image->rows);
375 if (proceed == MagickFalse)
379 chop_view=DestroyCacheView(chop_view);
380 image_view=DestroyCacheView(image_view);
381 chop_image->type=image->type;
382 if (status == MagickFalse)
383 chop_image=DestroyImage(chop_image);
388 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
392 + C o n s o l i d a t e C M Y K I m a g e %
396 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
398 % ConsolidateCMYKImage() consolidates separate C, M, Y, and K planes into a
401 % The format of the ConsolidateCMYKImage method is:
403 % Image *ConsolidateCMYKImage(const Image *image,ExceptionInfo *exception)
405 % A description of each parameter follows:
407 % o image: the image sequence.
409 % o exception: return any errors or warnings in this structure.
412 MagickExport Image *ConsolidateCMYKImages(const Image *images,
413 ExceptionInfo *exception)
430 Consolidate separate C, M, Y, and K planes into a single image.
432 assert(images != (Image *) NULL);
433 assert(images->signature == MagickCoreSignature);
434 if (images->debug != MagickFalse)
435 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
436 assert(exception != (ExceptionInfo *) NULL);
437 assert(exception->signature == MagickCoreSignature);
438 cmyk_images=NewImageList();
439 for (j=0; j < (ssize_t) GetImageListLength(images); j+=4)
444 assert(images != (Image *) NULL);
445 cmyk_image=CloneImage(images,0,0,MagickTrue,
447 if (cmyk_image == (Image *) NULL)
449 if (SetImageStorageClass(cmyk_image,DirectClass,exception) == MagickFalse)
451 (void) SetImageColorspace(cmyk_image,CMYKColorspace,exception);
452 for (i=0; i < 4; i++)
454 image_view=AcquireVirtualCacheView(images,exception);
455 cmyk_view=AcquireAuthenticCacheView(cmyk_image,exception);
456 for (y=0; y < (ssize_t) images->rows; y++)
458 register const Quantum
467 p=GetCacheViewVirtualPixels(image_view,0,y,images->columns,1,exception);
468 q=QueueCacheViewAuthenticPixels(cmyk_view,0,y,cmyk_image->columns,1,
470 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
472 for (x=0; x < (ssize_t) images->columns; x++)
477 pixel=ClampToQuantum(QuantumRange-GetPixelIntensity(images,p));
480 case 0: SetPixelCyan(cmyk_image,pixel,q); break;
481 case 1: SetPixelMagenta(cmyk_image,pixel,q); break;
482 case 2: SetPixelYellow(cmyk_image,pixel,q); break;
483 case 3: SetPixelBlack(cmyk_image,pixel,q); break;
486 p+=GetPixelChannels(images);
487 q+=GetPixelChannels(cmyk_image);
489 if (SyncCacheViewAuthenticPixels(cmyk_view,exception) == MagickFalse)
492 cmyk_view=DestroyCacheView(cmyk_view);
493 image_view=DestroyCacheView(image_view);
494 images=GetNextImageInList(images);
495 if (images == (Image *) NULL)
498 AppendImageToList(&cmyk_images,cmyk_image);
504 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
508 % C r o p I m a g e %
512 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
514 % CropImage() extracts a region of the image starting at the offset defined
515 % by geometry. Region must be fully defined, and no special handling of
516 % geometry flags is performed.
518 % The format of the CropImage method is:
520 % Image *CropImage(const Image *image,const RectangleInfo *geometry,
521 % ExceptionInfo *exception)
523 % A description of each parameter follows:
525 % o image: the image.
527 % o geometry: Define the region of the image to crop with members
528 % x, y, width, and height.
530 % o exception: return any errors or warnings in this structure.
533 MagickExport Image *CropImage(const Image *image,const RectangleInfo *geometry,
534 ExceptionInfo *exception)
536 #define CropImageTag "Crop/Image"
564 assert(image != (const Image *) NULL);
565 assert(image->signature == MagickCoreSignature);
566 if (image->debug != MagickFalse)
567 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
568 assert(geometry != (const RectangleInfo *) NULL);
569 assert(exception != (ExceptionInfo *) NULL);
570 assert(exception->signature == MagickCoreSignature);
571 bounding_box=image->page;
572 if ((bounding_box.width == 0) || (bounding_box.height == 0))
574 bounding_box.width=image->columns;
575 bounding_box.height=image->rows;
579 page.width=bounding_box.width;
580 if (page.height == 0)
581 page.height=bounding_box.height;
582 if (((bounding_box.x-page.x) >= (ssize_t) page.width) ||
583 ((bounding_box.y-page.y) >= (ssize_t) page.height) ||
584 ((page.x-bounding_box.x) > (ssize_t) image->columns) ||
585 ((page.y-bounding_box.y) > (ssize_t) image->rows))
588 Crop is not within virtual canvas, return 1 pixel transparent image.
590 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
591 "GeometryDoesNotContainImage","`%s'",image->filename);
592 crop_image=CloneImage(image,1,1,MagickTrue,exception);
593 if (crop_image == (Image *) NULL)
594 return((Image *) NULL);
595 crop_image->background_color.alpha=(MagickRealType) TransparentAlpha;
596 crop_image->alpha_trait=BlendPixelTrait;
597 (void) SetImageBackgroundColor(crop_image,exception);
598 crop_image->page=bounding_box;
599 crop_image->page.x=(-1);
600 crop_image->page.y=(-1);
601 if (crop_image->dispose == BackgroundDispose)
602 crop_image->dispose=NoneDispose;
605 if ((page.x < 0) && (bounding_box.x >= 0))
607 page.width+=page.x-bounding_box.x;
612 page.width-=bounding_box.x-page.x;
613 page.x-=bounding_box.x;
617 if ((page.y < 0) && (bounding_box.y >= 0))
619 page.height+=page.y-bounding_box.y;
624 page.height-=bounding_box.y-page.y;
625 page.y-=bounding_box.y;
629 if ((page.x+(ssize_t) page.width) > (ssize_t) image->columns)
630 page.width=image->columns-page.x;
631 if ((geometry->width != 0) && (page.width > geometry->width))
632 page.width=geometry->width;
633 if ((page.y+(ssize_t) page.height) > (ssize_t) image->rows)
634 page.height=image->rows-page.y;
635 if ((geometry->height != 0) && (page.height > geometry->height))
636 page.height=geometry->height;
637 bounding_box.x+=page.x;
638 bounding_box.y+=page.y;
639 if ((page.width == 0) || (page.height == 0))
641 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
642 "GeometryDoesNotContainImage","`%s'",image->filename);
643 return((Image *) NULL);
646 Initialize crop image attributes.
648 crop_image=CloneImage(image,page.width,page.height,MagickTrue,exception);
649 if (crop_image == (Image *) NULL)
650 return((Image *) NULL);
651 crop_image->page.width=image->page.width;
652 crop_image->page.height=image->page.height;
653 offset.x=(ssize_t) (bounding_box.x+bounding_box.width);
654 offset.y=(ssize_t) (bounding_box.y+bounding_box.height);
655 if ((offset.x > (ssize_t) image->page.width) ||
656 (offset.y > (ssize_t) image->page.height))
658 crop_image->page.width=bounding_box.width;
659 crop_image->page.height=bounding_box.height;
661 crop_image->page.x=bounding_box.x;
662 crop_image->page.y=bounding_box.y;
668 image_view=AcquireVirtualCacheView(image,exception);
669 crop_view=AcquireAuthenticCacheView(crop_image,exception);
670 #if defined(MAGICKCORE_OPENMP_SUPPORT)
671 #pragma omp parallel for schedule(static) shared(status) \
672 magick_number_threads(image,crop_image,crop_image->rows,1)
674 for (y=0; y < (ssize_t) crop_image->rows; y++)
676 register const Quantum
685 if (status == MagickFalse)
687 p=GetCacheViewVirtualPixels(image_view,page.x,page.y+y,crop_image->columns,
689 q=QueueCacheViewAuthenticPixels(crop_view,0,y,crop_image->columns,1,
691 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
696 for (x=0; x < (ssize_t) crop_image->columns; x++)
701 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
703 PixelChannel channel = GetPixelChannelChannel(image,i);
704 PixelTrait traits = GetPixelChannelTraits(image,channel);
705 PixelTrait crop_traits=GetPixelChannelTraits(crop_image,channel);
706 if ((traits == UndefinedPixelTrait) ||
707 (crop_traits == UndefinedPixelTrait))
709 SetPixelChannel(crop_image,channel,p[i],q);
711 p+=GetPixelChannels(image);
712 q+=GetPixelChannels(crop_image);
714 if (SyncCacheViewAuthenticPixels(crop_view,exception) == MagickFalse)
716 if (image->progress_monitor != (MagickProgressMonitor) NULL)
721 #if defined(MAGICKCORE_OPENMP_SUPPORT)
722 #pragma omp critical (MagickCore_CropImage)
724 proceed=SetImageProgress(image,CropImageTag,progress++,image->rows);
725 if (proceed == MagickFalse)
729 crop_view=DestroyCacheView(crop_view);
730 image_view=DestroyCacheView(image_view);
731 crop_image->type=image->type;
732 if (status == MagickFalse)
733 crop_image=DestroyImage(crop_image);
738 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
742 % C r o p I m a g e T o T i l e s %
746 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
748 % CropImageToTiles() crops a single image, into a possible list of tiles.
749 % This may include a single sub-region of the image. This basically applies
750 % all the normal geometry flags for Crop.
752 % Image *CropImageToTiles(const Image *image,
753 % const RectangleInfo *crop_geometry, ExceptionInfo *exception)
755 % A description of each parameter follows:
757 % o image: the image The transformed image is returned as this parameter.
759 % o crop_geometry: A crop geometry string.
761 % o exception: return any errors or warnings in this structure.
765 static inline double MagickRound(double x)
768 Round the fraction to nearest integer.
770 if ((x-floor(x)) < (ceil(x)-x))
775 MagickExport Image *CropImageToTiles(const Image *image,
776 const char *crop_geometry,ExceptionInfo *exception)
788 assert(image != (Image *) NULL);
789 assert(image->signature == MagickCoreSignature);
790 if (image->debug != MagickFalse)
791 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
792 crop_image=NewImageList();
794 flags=ParseGravityGeometry(image,crop_geometry,&geometry,exception);
795 if ((flags & AreaValue) != 0)
809 Crop into NxM tiles (@ flag).
811 width=image->columns;
813 if (geometry.width == 0)
815 if (geometry.height == 0)
817 if ((flags & AspectValue) == 0)
819 width-=(geometry.x < 0 ? -1 : 1)*geometry.x;
820 height-=(geometry.y < 0 ? -1 : 1)*geometry.y;
824 width+=(geometry.x < 0 ? -1 : 1)*geometry.x;
825 height+=(geometry.y < 0 ? -1 : 1)*geometry.y;
827 delta.x=(double) width/geometry.width;
828 delta.y=(double) height/geometry.height;
833 for (offset.y=0; offset.y < (double) height; )
835 if ((flags & AspectValue) == 0)
837 crop.y=(ssize_t) MagickRound((double) (offset.y-
838 (geometry.y > 0 ? 0 : geometry.y)));
839 offset.y+=delta.y; /* increment now to find width */
840 crop.height=(size_t) MagickRound((double) (offset.y+
841 (geometry.y < 0 ? 0 : geometry.y)));
845 crop.y=(ssize_t) MagickRound((double) (offset.y-
846 (geometry.y > 0 ? geometry.y : 0)));
847 offset.y+=delta.y; /* increment now to find width */
848 crop.height=(size_t) MagickRound((double)
849 (offset.y+(geometry.y < -1 ? geometry.y : 0)));
852 crop.y+=image->page.y;
853 for (offset.x=0; offset.x < (double) width; )
855 if ((flags & AspectValue) == 0)
857 crop.x=(ssize_t) MagickRound((double) (offset.x-
858 (geometry.x > 0 ? 0 : geometry.x)));
859 offset.x+=delta.x; /* increment now to find height */
860 crop.width=(size_t) MagickRound((double) (offset.x+
861 (geometry.x < 0 ? 0 : geometry.x)));
865 crop.x=(ssize_t) MagickRound((double) (offset.x-
866 (geometry.x > 0 ? geometry.x : 0)));
867 offset.x+=delta.x; /* increment now to find height */
868 crop.width=(size_t) MagickRound((double) (offset.x+
869 (geometry.x < 0 ? geometry.x : 0)));
872 crop.x+=image->page.x;
873 next=CropImage(image,&crop,exception);
874 if (next != (Image *) NULL)
875 AppendImageToList(&crop_image,next);
878 ClearMagickException(exception);
881 if (((geometry.width == 0) && (geometry.height == 0)) ||
882 ((flags & XValue) != 0) || ((flags & YValue) != 0))
885 Crop a single region at +X+Y.
887 crop_image=CropImage(image,&geometry,exception);
888 if ((crop_image != (Image *) NULL) && ((flags & AspectValue) != 0))
890 crop_image->page.width=geometry.width;
891 crop_image->page.height=geometry.height;
892 crop_image->page.x-=geometry.x;
893 crop_image->page.y-=geometry.y;
897 if ((image->columns > geometry.width) || (image->rows > geometry.height))
911 Crop into tiles of fixed size WxH.
915 page.width=image->columns;
916 if (page.height == 0)
917 page.height=image->rows;
918 width=geometry.width;
921 height=geometry.height;
925 for (y=0; y < (ssize_t) page.height; y+=(ssize_t) height)
927 for (x=0; x < (ssize_t) page.width; x+=(ssize_t) width)
929 geometry.width=width;
930 geometry.height=height;
933 next=CropImage(image,&geometry,exception);
934 if (next == (Image *) NULL)
936 AppendImageToList(&crop_image,next);
938 if (next == (Image *) NULL)
943 return(CloneImage(image,0,0,MagickTrue,exception));
947 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
951 % E x c e r p t I m a g e %
955 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
957 % ExcerptImage() returns a excerpt of the image as defined by the geometry.
959 % The format of the ExcerptImage method is:
961 % Image *ExcerptImage(const Image *image,const RectangleInfo *geometry,
962 % ExceptionInfo *exception)
964 % A description of each parameter follows:
966 % o image: the image.
968 % o geometry: Define the region of the image to extend with members
969 % x, y, width, and height.
971 % o exception: return any errors or warnings in this structure.
974 MagickExport Image *ExcerptImage(const Image *image,
975 const RectangleInfo *geometry,ExceptionInfo *exception)
977 #define ExcerptImageTag "Excerpt/Image"
996 Allocate excerpt image.
998 assert(image != (const Image *) NULL);
999 assert(image->signature == MagickCoreSignature);
1000 if (image->debug != MagickFalse)
1001 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1002 assert(geometry != (const RectangleInfo *) NULL);
1003 assert(exception != (ExceptionInfo *) NULL);
1004 assert(exception->signature == MagickCoreSignature);
1005 excerpt_image=CloneImage(image,geometry->width,geometry->height,MagickTrue,
1007 if (excerpt_image == (Image *) NULL)
1008 return((Image *) NULL);
1014 image_view=AcquireVirtualCacheView(image,exception);
1015 excerpt_view=AcquireAuthenticCacheView(excerpt_image,exception);
1016 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1017 #pragma omp parallel for schedule(static) shared(progress,status) \
1018 magick_number_threads(image,excerpt_image,excerpt_image->rows,1)
1020 for (y=0; y < (ssize_t) excerpt_image->rows; y++)
1022 register const Quantum
1031 if (status == MagickFalse)
1033 p=GetCacheViewVirtualPixels(image_view,geometry->x,geometry->y+y,
1034 geometry->width,1,exception);
1035 q=GetCacheViewAuthenticPixels(excerpt_view,0,y,excerpt_image->columns,1,
1037 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1042 for (x=0; x < (ssize_t) excerpt_image->columns; x++)
1047 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1049 PixelChannel channel = GetPixelChannelChannel(image,i);
1050 PixelTrait traits = GetPixelChannelTraits(image,channel);
1051 PixelTrait excerpt_traits=GetPixelChannelTraits(excerpt_image,channel);
1052 if ((traits == UndefinedPixelTrait) ||
1053 (excerpt_traits == UndefinedPixelTrait))
1055 SetPixelChannel(excerpt_image,channel,p[i],q);
1057 p+=GetPixelChannels(image);
1058 q+=GetPixelChannels(excerpt_image);
1060 if (SyncCacheViewAuthenticPixels(excerpt_view,exception) == MagickFalse)
1062 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1067 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1068 #pragma omp critical (MagickCore_ExcerptImage)
1070 proceed=SetImageProgress(image,ExcerptImageTag,progress++,image->rows);
1071 if (proceed == MagickFalse)
1075 excerpt_view=DestroyCacheView(excerpt_view);
1076 image_view=DestroyCacheView(image_view);
1077 excerpt_image->type=image->type;
1078 if (status == MagickFalse)
1079 excerpt_image=DestroyImage(excerpt_image);
1080 return(excerpt_image);
1084 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1088 % E x t e n t I m a g e %
1092 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1094 % ExtentImage() extends the image as defined by the geometry, gravity, and
1095 % image background color. Set the (x,y) offset of the geometry to move the
1096 % original image relative to the extended image.
1098 % The format of the ExtentImage method is:
1100 % Image *ExtentImage(const Image *image,const RectangleInfo *geometry,
1101 % ExceptionInfo *exception)
1103 % A description of each parameter follows:
1105 % o image: the image.
1107 % o geometry: Define the region of the image to extend with members
1108 % x, y, width, and height.
1110 % o exception: return any errors or warnings in this structure.
1113 MagickExport Image *ExtentImage(const Image *image,
1114 const RectangleInfo *geometry,ExceptionInfo *exception)
1123 Allocate extent image.
1125 assert(image != (const Image *) NULL);
1126 assert(image->signature == MagickCoreSignature);
1127 if (image->debug != MagickFalse)
1128 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1129 assert(geometry != (const RectangleInfo *) NULL);
1130 assert(exception != (ExceptionInfo *) NULL);
1131 assert(exception->signature == MagickCoreSignature);
1132 extent_image=CloneImage(image,geometry->width,geometry->height,MagickTrue,
1134 if (extent_image == (Image *) NULL)
1135 return((Image *) NULL);
1136 status=SetImageBackgroundColor(extent_image,exception);
1137 if (status == MagickFalse)
1139 extent_image=DestroyImage(extent_image);
1140 return((Image *) NULL);
1142 status=CompositeImage(extent_image,image,image->compose,MagickTrue,
1143 -geometry->x,-geometry->y,exception);
1144 return(extent_image);
1148 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1152 % F l i p I m a g e %
1156 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1158 % FlipImage() creates a vertical mirror image by reflecting the pixels
1159 % around the central x-axis.
1161 % The format of the FlipImage method is:
1163 % Image *FlipImage(const Image *image,ExceptionInfo *exception)
1165 % A description of each parameter follows:
1167 % o image: the image.
1169 % o exception: return any errors or warnings in this structure.
1172 MagickExport Image *FlipImage(const Image *image,ExceptionInfo *exception)
1174 #define FlipImageTag "Flip/Image"
1195 assert(image != (const Image *) NULL);
1196 assert(image->signature == MagickCoreSignature);
1197 if (image->debug != MagickFalse)
1198 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1199 assert(exception != (ExceptionInfo *) NULL);
1200 assert(exception->signature == MagickCoreSignature);
1201 flip_image=CloneImage(image,0,0,MagickTrue,exception);
1202 if (flip_image == (Image *) NULL)
1203 return((Image *) NULL);
1210 image_view=AcquireVirtualCacheView(image,exception);
1211 flip_view=AcquireAuthenticCacheView(flip_image,exception);
1212 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1213 #pragma omp parallel for schedule(static) shared(status) \
1214 magick_number_threads(image,flip_image,flip_image->rows,1)
1216 for (y=0; y < (ssize_t) flip_image->rows; y++)
1218 register const Quantum
1227 if (status == MagickFalse)
1229 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1230 q=QueueCacheViewAuthenticPixels(flip_view,0,(ssize_t) (flip_image->rows-y-
1231 1),flip_image->columns,1,exception);
1232 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1237 for (x=0; x < (ssize_t) flip_image->columns; x++)
1242 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1244 PixelChannel channel = GetPixelChannelChannel(image,i);
1245 PixelTrait traits = GetPixelChannelTraits(image,channel);
1246 PixelTrait flip_traits=GetPixelChannelTraits(flip_image,channel);
1247 if ((traits == UndefinedPixelTrait) ||
1248 (flip_traits == UndefinedPixelTrait))
1250 SetPixelChannel(flip_image,channel,p[i],q);
1252 p+=GetPixelChannels(image);
1253 q+=GetPixelChannels(flip_image);
1255 if (SyncCacheViewAuthenticPixels(flip_view,exception) == MagickFalse)
1257 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1262 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1263 #pragma omp critical (MagickCore_FlipImage)
1265 proceed=SetImageProgress(image,FlipImageTag,progress++,image->rows);
1266 if (proceed == MagickFalse)
1270 flip_view=DestroyCacheView(flip_view);
1271 image_view=DestroyCacheView(image_view);
1272 flip_image->type=image->type;
1273 if (page.height != 0)
1274 page.y=(ssize_t) (page.height-flip_image->rows-page.y);
1275 flip_image->page=page;
1276 if (status == MagickFalse)
1277 flip_image=DestroyImage(flip_image);
1282 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1286 % F l o p I m a g e %
1290 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1292 % FlopImage() creates a horizontal mirror image by reflecting the pixels
1293 % around the central y-axis.
1295 % The format of the FlopImage method is:
1297 % Image *FlopImage(const Image *image,ExceptionInfo *exception)
1299 % A description of each parameter follows:
1301 % o image: the image.
1303 % o exception: return any errors or warnings in this structure.
1306 MagickExport Image *FlopImage(const Image *image,ExceptionInfo *exception)
1308 #define FlopImageTag "Flop/Image"
1329 assert(image != (const Image *) NULL);
1330 assert(image->signature == MagickCoreSignature);
1331 if (image->debug != MagickFalse)
1332 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1333 assert(exception != (ExceptionInfo *) NULL);
1334 assert(exception->signature == MagickCoreSignature);
1335 flop_image=CloneImage(image,0,0,MagickTrue,exception);
1336 if (flop_image == (Image *) NULL)
1337 return((Image *) NULL);
1344 image_view=AcquireVirtualCacheView(image,exception);
1345 flop_view=AcquireAuthenticCacheView(flop_image,exception);
1346 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1347 #pragma omp parallel for schedule(static) shared(status) \
1348 magick_number_threads(image,flop_image,flop_image->rows,1)
1350 for (y=0; y < (ssize_t) flop_image->rows; y++)
1352 register const Quantum
1361 if (status == MagickFalse)
1363 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1364 q=QueueCacheViewAuthenticPixels(flop_view,0,y,flop_image->columns,1,
1366 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1371 q+=GetPixelChannels(flop_image)*flop_image->columns;
1372 for (x=0; x < (ssize_t) flop_image->columns; x++)
1377 q-=GetPixelChannels(flop_image);
1378 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1380 PixelChannel channel = GetPixelChannelChannel(image,i);
1381 PixelTrait traits = GetPixelChannelTraits(image,channel);
1382 PixelTrait flop_traits=GetPixelChannelTraits(flop_image,channel);
1383 if ((traits == UndefinedPixelTrait) ||
1384 (flop_traits == UndefinedPixelTrait))
1386 SetPixelChannel(flop_image,channel,p[i],q);
1388 p+=GetPixelChannels(image);
1390 if (SyncCacheViewAuthenticPixels(flop_view,exception) == MagickFalse)
1392 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1397 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1398 #pragma omp critical (MagickCore_FlopImage)
1400 proceed=SetImageProgress(image,FlopImageTag,progress++,image->rows);
1401 if (proceed == MagickFalse)
1405 flop_view=DestroyCacheView(flop_view);
1406 image_view=DestroyCacheView(image_view);
1407 flop_image->type=image->type;
1408 if (page.width != 0)
1409 page.x=(ssize_t) (page.width-flop_image->columns-page.x);
1410 flop_image->page=page;
1411 if (status == MagickFalse)
1412 flop_image=DestroyImage(flop_image);
1417 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1421 % R o l l I m a g e %
1425 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1427 % RollImage() offsets an image as defined by x_offset and y_offset.
1429 % The format of the RollImage method is:
1431 % Image *RollImage(const Image *image,const ssize_t x_offset,
1432 % const ssize_t y_offset,ExceptionInfo *exception)
1434 % A description of each parameter follows:
1436 % o image: the image.
1438 % o x_offset: the number of columns to roll in the horizontal direction.
1440 % o y_offset: the number of rows to roll in the vertical direction.
1442 % o exception: return any errors or warnings in this structure.
1446 static MagickBooleanType CopyImageRegion(Image *destination,const Image *source, const size_t columns,const size_t rows,const ssize_t sx,const ssize_t sy,
1447 const ssize_t dx,const ssize_t dy,ExceptionInfo *exception)
1462 source_view=AcquireVirtualCacheView(source,exception);
1463 destination_view=AcquireAuthenticCacheView(destination,exception);
1464 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1465 #pragma omp parallel for schedule(static) shared(status) \
1466 magick_number_threads(source,destination,rows,1)
1468 for (y=0; y < (ssize_t) rows; y++)
1473 register const Quantum
1485 if (status == MagickFalse)
1487 p=GetCacheViewVirtualPixels(source_view,sx,sy+y,columns,1,exception);
1488 q=GetCacheViewAuthenticPixels(destination_view,dx,dy+y,columns,1,exception);
1489 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1494 for (x=0; x < (ssize_t) columns; x++)
1499 for (i=0; i < (ssize_t) GetPixelChannels(source); i++)
1501 PixelChannel channel = GetPixelChannelChannel(source,i);
1502 PixelTrait source_traits=GetPixelChannelTraits(source,channel);
1503 PixelTrait destination_traits=GetPixelChannelTraits(destination,
1505 if ((source_traits == UndefinedPixelTrait) ||
1506 (destination_traits == UndefinedPixelTrait))
1508 SetPixelChannel(destination,channel,p[i],q);
1510 p+=GetPixelChannels(source);
1511 q+=GetPixelChannels(destination);
1513 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
1514 if (sync == MagickFalse)
1517 destination_view=DestroyCacheView(destination_view);
1518 source_view=DestroyCacheView(source_view);
1522 MagickExport Image *RollImage(const Image *image,const ssize_t x_offset,
1523 const ssize_t y_offset,ExceptionInfo *exception)
1525 #define RollImageTag "Roll/Image"
1537 Initialize roll image attributes.
1539 assert(image != (const Image *) NULL);
1540 assert(image->signature == MagickCoreSignature);
1541 if (image->debug != MagickFalse)
1542 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1543 assert(exception != (ExceptionInfo *) NULL);
1544 assert(exception->signature == MagickCoreSignature);
1545 roll_image=CloneImage(image,0,0,MagickTrue,exception);
1546 if (roll_image == (Image *) NULL)
1547 return((Image *) NULL);
1550 while (offset.x < 0)
1551 offset.x+=(ssize_t) image->columns;
1552 while (offset.x >= (ssize_t) image->columns)
1553 offset.x-=(ssize_t) image->columns;
1554 while (offset.y < 0)
1555 offset.y+=(ssize_t) image->rows;
1556 while (offset.y >= (ssize_t) image->rows)
1557 offset.y-=(ssize_t) image->rows;
1561 status=CopyImageRegion(roll_image,image,(size_t) offset.x,
1562 (size_t) offset.y,(ssize_t) image->columns-offset.x,(ssize_t) image->rows-
1563 offset.y,0,0,exception);
1564 (void) SetImageProgress(image,RollImageTag,0,3);
1565 status&=CopyImageRegion(roll_image,image,image->columns-offset.x,
1566 (size_t) offset.y,0,(ssize_t) image->rows-offset.y,offset.x,0,
1568 (void) SetImageProgress(image,RollImageTag,1,3);
1569 status&=CopyImageRegion(roll_image,image,(size_t) offset.x,image->rows-
1570 offset.y,(ssize_t) image->columns-offset.x,0,0,offset.y,exception);
1571 (void) SetImageProgress(image,RollImageTag,2,3);
1572 status&=CopyImageRegion(roll_image,image,image->columns-offset.x,image->rows-
1573 offset.y,0,0,offset.x,offset.y,exception);
1574 (void) SetImageProgress(image,RollImageTag,3,3);
1575 roll_image->type=image->type;
1576 if (status == MagickFalse)
1577 roll_image=DestroyImage(roll_image);
1582 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1586 % S h a v e I m a g e %
1590 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1592 % ShaveImage() shaves pixels from the image edges. It allocates the memory
1593 % necessary for the new Image structure and returns a pointer to the new
1596 % The format of the ShaveImage method is:
1598 % Image *ShaveImage(const Image *image,const RectangleInfo *shave_info,
1599 % ExceptionInfo *exception)
1601 % A description of each parameter follows:
1603 % o shave_image: Method ShaveImage returns a pointer to the shaved
1604 % image. A null image is returned if there is a memory shortage or
1605 % if the image width or height is zero.
1607 % o image: the image.
1609 % o shave_info: Specifies a pointer to a RectangleInfo which defines the
1610 % region of the image to crop.
1612 % o exception: return any errors or warnings in this structure.
1615 MagickExport Image *ShaveImage(const Image *image,
1616 const RectangleInfo *shave_info,ExceptionInfo *exception)
1624 assert(image != (const Image *) NULL);
1625 assert(image->signature == MagickCoreSignature);
1626 if (image->debug != MagickFalse)
1627 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1628 if (((2*shave_info->width) >= image->columns) ||
1629 ((2*shave_info->height) >= image->rows))
1630 ThrowImageException(OptionWarning,"GeometryDoesNotContainImage");
1631 SetGeometry(image,&geometry);
1632 geometry.width-=2*shave_info->width;
1633 geometry.height-=2*shave_info->height;
1634 geometry.x=(ssize_t) shave_info->width+image->page.x;
1635 geometry.y=(ssize_t) shave_info->height+image->page.y;
1636 shave_image=CropImage(image,&geometry,exception);
1637 if (shave_image == (Image *) NULL)
1638 return((Image *) NULL);
1639 shave_image->page.width-=2*shave_info->width;
1640 shave_image->page.height-=2*shave_info->height;
1641 shave_image->page.x-=(ssize_t) shave_info->width;
1642 shave_image->page.y-=(ssize_t) shave_info->height;
1643 return(shave_image);
1647 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1651 % S p l i c e I m a g e %
1655 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1657 % SpliceImage() splices a solid color into the image as defined by the
1660 % The format of the SpliceImage method is:
1662 % Image *SpliceImage(const Image *image,const RectangleInfo *geometry,
1663 % ExceptionInfo *exception)
1665 % A description of each parameter follows:
1667 % o image: the image.
1669 % o geometry: Define the region of the image to splice with members
1670 % x, y, width, and height.
1672 % o exception: return any errors or warnings in this structure.
1675 MagickExport Image *SpliceImage(const Image *image,
1676 const RectangleInfo *geometry,ExceptionInfo *exception)
1678 #define SpliceImageTag "Splice/Image"
1701 Allocate splice image.
1703 assert(image != (const Image *) NULL);
1704 assert(image->signature == MagickCoreSignature);
1705 if (image->debug != MagickFalse)
1706 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1707 assert(geometry != (const RectangleInfo *) NULL);
1708 assert(exception != (ExceptionInfo *) NULL);
1709 assert(exception->signature == MagickCoreSignature);
1710 splice_geometry=(*geometry);
1711 splice_image=CloneImage(image,image->columns+splice_geometry.width,
1712 image->rows+splice_geometry.height,MagickTrue,exception);
1713 if (splice_image == (Image *) NULL)
1714 return((Image *) NULL);
1715 if (SetImageStorageClass(splice_image,DirectClass,exception) == MagickFalse)
1717 splice_image=DestroyImage(splice_image);
1718 return((Image *) NULL);
1720 if ((IsPixelInfoGray(&splice_image->background_color) == MagickFalse) &&
1721 (IsGrayColorspace(splice_image->colorspace) != MagickFalse))
1722 (void) SetImageColorspace(splice_image,sRGBColorspace,exception);
1723 if ((splice_image->background_color.alpha_trait != UndefinedPixelTrait) &&
1724 (splice_image->alpha_trait == UndefinedPixelTrait))
1725 (void) SetImageAlpha(splice_image,OpaqueAlpha,exception);
1726 (void) SetImageBackgroundColor(splice_image,exception);
1728 Respect image geometry.
1730 switch (image->gravity)
1733 case UndefinedGravity:
1734 case NorthWestGravity:
1738 splice_geometry.x+=(ssize_t) splice_geometry.width/2;
1741 case NorthEastGravity:
1743 splice_geometry.x+=(ssize_t) splice_geometry.width;
1748 splice_geometry.y+=(ssize_t) splice_geometry.width/2;
1753 splice_geometry.x+=(ssize_t) splice_geometry.width/2;
1754 splice_geometry.y+=(ssize_t) splice_geometry.height/2;
1759 splice_geometry.x+=(ssize_t) splice_geometry.width;
1760 splice_geometry.y+=(ssize_t) splice_geometry.height/2;
1763 case SouthWestGravity:
1765 splice_geometry.y+=(ssize_t) splice_geometry.height;
1770 splice_geometry.x+=(ssize_t) splice_geometry.width/2;
1771 splice_geometry.y+=(ssize_t) splice_geometry.height;
1774 case SouthEastGravity:
1776 splice_geometry.x+=(ssize_t) splice_geometry.width;
1777 splice_geometry.y+=(ssize_t) splice_geometry.height;
1786 columns=MagickMin(splice_geometry.x,(ssize_t) splice_image->columns);
1787 image_view=AcquireVirtualCacheView(image,exception);
1788 splice_view=AcquireAuthenticCacheView(splice_image,exception);
1789 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1790 #pragma omp parallel for schedule(static) shared(progress,status) \
1791 magick_number_threads(image,splice_image,splice_geometry.y,1)
1793 for (y=0; y < (ssize_t) splice_geometry.y; y++)
1795 register const Quantum
1804 if (status == MagickFalse)
1806 p=GetCacheViewVirtualPixels(image_view,0,y,splice_image->columns,1,
1808 q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1,
1810 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1815 for (x=0; x < columns; x++)
1820 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1822 PixelChannel channel = GetPixelChannelChannel(image,i);
1823 PixelTrait traits = GetPixelChannelTraits(image,channel);
1824 PixelTrait splice_traits=GetPixelChannelTraits(splice_image,channel);
1825 if ((traits == UndefinedPixelTrait) ||
1826 (splice_traits == UndefinedPixelTrait))
1828 SetPixelChannel(splice_image,channel,p[i],q);
1830 SetPixelRed(splice_image,GetPixelRed(image,p),q);
1831 SetPixelGreen(splice_image,GetPixelGreen(image,p),q);
1832 SetPixelBlue(splice_image,GetPixelBlue(image,p),q);
1833 SetPixelAlpha(splice_image,GetPixelAlpha(image,p),q);
1834 p+=GetPixelChannels(image);
1835 q+=GetPixelChannels(splice_image);
1837 for ( ; x < (ssize_t) (splice_geometry.x+splice_geometry.width); x++)
1838 q+=GetPixelChannels(splice_image);
1839 for ( ; x < (ssize_t) splice_image->columns; x++)
1844 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1846 PixelChannel channel = GetPixelChannelChannel(image,i);
1847 PixelTrait traits = GetPixelChannelTraits(image,channel);
1848 PixelTrait splice_traits=GetPixelChannelTraits(splice_image,channel);
1849 if ((traits == UndefinedPixelTrait) ||
1850 (splice_traits == UndefinedPixelTrait))
1852 SetPixelChannel(splice_image,channel,p[i],q);
1854 SetPixelRed(splice_image,GetPixelRed(image,p),q);
1855 SetPixelGreen(splice_image,GetPixelGreen(image,p),q);
1856 SetPixelBlue(splice_image,GetPixelBlue(image,p),q);
1857 SetPixelAlpha(splice_image,GetPixelAlpha(image,p),q);
1858 p+=GetPixelChannels(image);
1859 q+=GetPixelChannels(splice_image);
1861 if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse)
1863 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1868 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1869 #pragma omp critical (MagickCore_TransposeImage)
1871 proceed=SetImageProgress(image,SpliceImageTag,progress++,
1872 splice_image->rows);
1873 if (proceed == MagickFalse)
1877 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1878 #pragma omp parallel for schedule(static) shared(progress,status) \
1879 magick_number_threads(image,splice_image,splice_image->rows,2)
1881 for (y=(ssize_t) (splice_geometry.y+splice_geometry.height);
1882 y < (ssize_t) splice_image->rows; y++)
1884 register const Quantum
1893 if (status == MagickFalse)
1895 if ((y < 0) || (y >= (ssize_t)splice_image->rows))
1897 p=GetCacheViewVirtualPixels(image_view,0,y-(ssize_t) splice_geometry.height,
1898 splice_image->columns,1,exception);
1899 q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1,
1901 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1906 for (x=0; x < columns; x++)
1911 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1913 PixelChannel channel = GetPixelChannelChannel(image,i);
1914 PixelTrait traits = GetPixelChannelTraits(image,channel);
1915 PixelTrait splice_traits=GetPixelChannelTraits(splice_image,channel);
1916 if ((traits == UndefinedPixelTrait) ||
1917 (splice_traits == UndefinedPixelTrait))
1919 SetPixelChannel(splice_image,channel,p[i],q);
1921 SetPixelRed(splice_image,GetPixelRed(image,p),q);
1922 SetPixelGreen(splice_image,GetPixelGreen(image,p),q);
1923 SetPixelBlue(splice_image,GetPixelBlue(image,p),q);
1924 SetPixelAlpha(splice_image,GetPixelAlpha(image,p),q);
1925 p+=GetPixelChannels(image);
1926 q+=GetPixelChannels(splice_image);
1928 for ( ; x < (ssize_t) (splice_geometry.x+splice_geometry.width); x++)
1929 q+=GetPixelChannels(splice_image);
1930 for ( ; x < (ssize_t) splice_image->columns; x++)
1935 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1937 PixelChannel channel = GetPixelChannelChannel(image,i);
1938 PixelTrait traits = GetPixelChannelTraits(image,channel);
1939 PixelTrait splice_traits=GetPixelChannelTraits(splice_image,channel);
1940 if ((traits == UndefinedPixelTrait) ||
1941 (splice_traits == UndefinedPixelTrait))
1943 SetPixelChannel(splice_image,channel,p[i],q);
1945 SetPixelRed(splice_image,GetPixelRed(image,p),q);
1946 SetPixelGreen(splice_image,GetPixelGreen(image,p),q);
1947 SetPixelBlue(splice_image,GetPixelBlue(image,p),q);
1948 SetPixelAlpha(splice_image,GetPixelAlpha(image,p),q);
1949 p+=GetPixelChannels(image);
1950 q+=GetPixelChannels(splice_image);
1952 if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse)
1954 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1959 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1960 #pragma omp critical (MagickCore_TransposeImage)
1962 proceed=SetImageProgress(image,SpliceImageTag,progress++,
1963 splice_image->rows);
1964 if (proceed == MagickFalse)
1968 splice_view=DestroyCacheView(splice_view);
1969 image_view=DestroyCacheView(image_view);
1970 if (status == MagickFalse)
1971 splice_image=DestroyImage(splice_image);
1972 return(splice_image);
1976 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1980 % T r a n s f o r m I m a g e %
1984 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1986 % TransformImage() is a convenience method that behaves like ResizeImage() or
1987 % CropImage() but accepts scaling and/or cropping information as a region
1988 % geometry specification. If the operation fails, the original image handle
1991 % This should only be used for single images.
1993 % This function destroys what it assumes to be a single image list.
1994 % If the input image is part of a larger list, all other images in that list
1995 % will be simply 'lost', not destroyed.
1997 % Also if the crop generates a list of images only the first image is resized.
1998 % And finally if the crop succeeds and the resize failed, you will get a
1999 % cropped image, as well as a 'false' or 'failed' report.
2001 % This function and should probably be deprecated in favor of direct calls
2002 % to CropImageToTiles() or ResizeImage(), as appropriate.
2004 % The format of the TransformImage method is:
2006 % MagickBooleanType TransformImage(Image **image,const char *crop_geometry,
2007 % const char *image_geometry,ExceptionInfo *exception)
2009 % A description of each parameter follows:
2011 % o image: the image The transformed image is returned as this parameter.
2013 % o crop_geometry: A crop geometry string. This geometry defines a
2014 % subregion of the image to crop.
2016 % o image_geometry: An image geometry string. This geometry defines the
2017 % final size of the image.
2019 % o exception: return any errors or warnings in this structure.
2022 MagickPrivate MagickBooleanType TransformImage(Image **image,
2023 const char *crop_geometry,const char *image_geometry,ExceptionInfo *exception)
2032 assert(image != (Image **) NULL);
2033 assert((*image)->signature == MagickCoreSignature);
2034 if ((*image)->debug != MagickFalse)
2035 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
2036 transform_image=(*image);
2037 if (crop_geometry != (const char *) NULL)
2043 Crop image to a user specified size.
2045 crop_image=CropImageToTiles(*image,crop_geometry,exception);
2046 if (crop_image == (Image *) NULL)
2047 transform_image=CloneImage(*image,0,0,MagickTrue,exception);
2050 transform_image=DestroyImage(transform_image);
2051 transform_image=GetFirstImageInList(crop_image);
2053 *image=transform_image;
2055 if (image_geometry == (const char *) NULL)
2058 Scale image to a user specified size.
2060 (void) ParseRegionGeometry(transform_image,image_geometry,&geometry,
2062 if ((transform_image->columns == geometry.width) &&
2063 (transform_image->rows == geometry.height))
2065 resize_image=ResizeImage(transform_image,geometry.width,geometry.height,
2066 transform_image->filter,exception);
2067 if (resize_image == (Image *) NULL)
2068 return(MagickFalse);
2069 transform_image=DestroyImage(transform_image);
2070 transform_image=resize_image;
2071 *image=transform_image;
2076 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2080 % T r a n s p o s e I m a g e %
2084 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2086 % TransposeImage() creates a horizontal mirror image by reflecting the pixels
2087 % around the central y-axis while rotating them by 90 degrees.
2089 % The format of the TransposeImage method is:
2091 % Image *TransposeImage(const Image *image,ExceptionInfo *exception)
2093 % A description of each parameter follows:
2095 % o image: the image.
2097 % o exception: return any errors or warnings in this structure.
2100 MagickExport Image *TransposeImage(const Image *image,ExceptionInfo *exception)
2102 #define TransposeImageTag "Transpose/Image"
2123 assert(image != (const Image *) NULL);
2124 assert(image->signature == MagickCoreSignature);
2125 if (image->debug != MagickFalse)
2126 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2127 assert(exception != (ExceptionInfo *) NULL);
2128 assert(exception->signature == MagickCoreSignature);
2129 transpose_image=CloneImage(image,image->rows,image->columns,MagickTrue,
2131 if (transpose_image == (Image *) NULL)
2132 return((Image *) NULL);
2138 image_view=AcquireVirtualCacheView(image,exception);
2139 transpose_view=AcquireAuthenticCacheView(transpose_image,exception);
2140 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2141 #pragma omp parallel for schedule(static) shared(progress,status) \
2142 magick_number_threads(image,transpose_image,image->rows,1)
2144 for (y=0; y < (ssize_t) image->rows; y++)
2146 register const Quantum
2155 if (status == MagickFalse)
2157 p=GetCacheViewVirtualPixels(image_view,0,(ssize_t) image->rows-y-1,
2158 image->columns,1,exception);
2159 q=QueueCacheViewAuthenticPixels(transpose_view,(ssize_t) (image->rows-y-1),
2160 0,1,transpose_image->rows,exception);
2161 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2166 for (x=0; x < (ssize_t) image->columns; x++)
2171 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2173 PixelChannel channel = GetPixelChannelChannel(image,i);
2174 PixelTrait traits = GetPixelChannelTraits(image,channel);
2175 PixelTrait transpose_traits=GetPixelChannelTraits(transpose_image,
2177 if ((traits == UndefinedPixelTrait) ||
2178 (transpose_traits == UndefinedPixelTrait))
2180 SetPixelChannel(transpose_image,channel,p[i],q);
2182 p+=GetPixelChannels(image);
2183 q+=GetPixelChannels(transpose_image);
2185 if (SyncCacheViewAuthenticPixels(transpose_view,exception) == MagickFalse)
2187 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2192 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2193 #pragma omp critical (MagickCore_TransposeImage)
2195 proceed=SetImageProgress(image,TransposeImageTag,progress++,
2197 if (proceed == MagickFalse)
2201 transpose_view=DestroyCacheView(transpose_view);
2202 image_view=DestroyCacheView(image_view);
2203 transpose_image->type=image->type;
2204 page=transpose_image->page;
2205 Swap(page.width,page.height);
2206 Swap(page.x,page.y);
2207 transpose_image->page=page;
2208 if (status == MagickFalse)
2209 transpose_image=DestroyImage(transpose_image);
2210 return(transpose_image);
2214 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2218 % T r a n s v e r s e I m a g e %
2222 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2224 % TransverseImage() creates a vertical mirror image by reflecting the pixels
2225 % around the central x-axis while rotating them by 270 degrees.
2227 % The format of the TransverseImage method is:
2229 % Image *TransverseImage(const Image *image,ExceptionInfo *exception)
2231 % A description of each parameter follows:
2233 % o image: the image.
2235 % o exception: return any errors or warnings in this structure.
2238 MagickExport Image *TransverseImage(const Image *image,ExceptionInfo *exception)
2240 #define TransverseImageTag "Transverse/Image"
2261 assert(image != (const Image *) NULL);
2262 assert(image->signature == MagickCoreSignature);
2263 if (image->debug != MagickFalse)
2264 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2265 assert(exception != (ExceptionInfo *) NULL);
2266 assert(exception->signature == MagickCoreSignature);
2267 transverse_image=CloneImage(image,image->rows,image->columns,MagickTrue,
2269 if (transverse_image == (Image *) NULL)
2270 return((Image *) NULL);
2276 image_view=AcquireVirtualCacheView(image,exception);
2277 transverse_view=AcquireAuthenticCacheView(transverse_image,exception);
2278 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2279 #pragma omp parallel for schedule(static) shared(progress,status) \
2280 magick_number_threads(image,transverse_image,image->rows,1)
2282 for (y=0; y < (ssize_t) image->rows; y++)
2287 register const Quantum
2296 if (status == MagickFalse)
2298 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2299 q=QueueCacheViewAuthenticPixels(transverse_view,(ssize_t) (image->rows-y-1),
2300 0,1,transverse_image->rows,exception);
2301 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2306 q+=GetPixelChannels(transverse_image)*image->columns;
2307 for (x=0; x < (ssize_t) image->columns; x++)
2312 q-=GetPixelChannels(transverse_image);
2313 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2315 PixelChannel channel = GetPixelChannelChannel(image,i);
2316 PixelTrait traits = GetPixelChannelTraits(image,channel);
2317 PixelTrait transverse_traits=GetPixelChannelTraits(transverse_image,
2319 if ((traits == UndefinedPixelTrait) ||
2320 (transverse_traits == UndefinedPixelTrait))
2322 SetPixelChannel(transverse_image,channel,p[i],q);
2324 p+=GetPixelChannels(image);
2326 sync=SyncCacheViewAuthenticPixels(transverse_view,exception);
2327 if (sync == MagickFalse)
2329 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2334 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2335 #pragma omp critical (MagickCore_TransverseImage)
2337 proceed=SetImageProgress(image,TransverseImageTag,progress++,
2339 if (proceed == MagickFalse)
2343 transverse_view=DestroyCacheView(transverse_view);
2344 image_view=DestroyCacheView(image_view);
2345 transverse_image->type=image->type;
2346 page=transverse_image->page;
2347 Swap(page.width,page.height);
2348 Swap(page.x,page.y);
2349 if (page.width != 0)
2350 page.x=(ssize_t) (page.width-transverse_image->columns-page.x);
2351 if (page.height != 0)
2352 page.y=(ssize_t) (page.height-transverse_image->rows-page.y);
2353 transverse_image->page=page;
2354 if (status == MagickFalse)
2355 transverse_image=DestroyImage(transverse_image);
2356 return(transverse_image);
2360 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2364 % T r i m I m a g e %
2368 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2370 % TrimImage() trims pixels from the image edges. It allocates the memory
2371 % necessary for the new Image structure and returns a pointer to the new
2374 % The format of the TrimImage method is:
2376 % Image *TrimImage(const Image *image,ExceptionInfo *exception)
2378 % A description of each parameter follows:
2380 % o image: the image.
2382 % o exception: return any errors or warnings in this structure.
2385 MagickExport Image *TrimImage(const Image *image,ExceptionInfo *exception)
2390 assert(image != (const Image *) NULL);
2391 assert(image->signature == MagickCoreSignature);
2392 if (image->debug != MagickFalse)
2393 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2394 geometry=GetImageBoundingBox(image,exception);
2395 if ((geometry.width == 0) || (geometry.height == 0))
2400 crop_image=CloneImage(image,1,1,MagickTrue,exception);
2401 if (crop_image == (Image *) NULL)
2402 return((Image *) NULL);
2403 crop_image->background_color.alpha=(MagickRealType) TransparentAlpha;
2404 crop_image->alpha_trait=BlendPixelTrait;
2405 (void) SetImageBackgroundColor(crop_image,exception);
2406 crop_image->page=image->page;
2407 crop_image->page.x=(-1);
2408 crop_image->page.y=(-1);
2411 geometry.x+=image->page.x;
2412 geometry.y+=image->page.y;
2413 return(CropImage(image,&geometry,exception));