2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % TTTTT RRRR AAA N N SSSSS FFFFF OOO RRRR M M %
7 % T R R A A NN N SS F O O R R MM MM %
8 % T RRRR AAAAA N N N SSS FFF O O RRRR M M M %
9 % T R R A A N NN SS F O O R R M M %
10 % T R R A A N N SSSSS F OOO R R M M %
13 % MagickCore Image Transform Methods %
20 % Copyright 1999-2014 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
42 #include "MagickCore/studio.h"
43 #include "MagickCore/attribute.h"
44 #include "MagickCore/cache.h"
45 #include "MagickCore/cache-view.h"
46 #include "MagickCore/color.h"
47 #include "MagickCore/color-private.h"
48 #include "MagickCore/colorspace-private.h"
49 #include "MagickCore/composite.h"
50 #include "MagickCore/distort.h"
51 #include "MagickCore/draw.h"
52 #include "MagickCore/effect.h"
53 #include "MagickCore/exception.h"
54 #include "MagickCore/exception-private.h"
55 #include "MagickCore/geometry.h"
56 #include "MagickCore/image.h"
57 #include "MagickCore/memory_.h"
58 #include "MagickCore/layer.h"
59 #include "MagickCore/list.h"
60 #include "MagickCore/monitor.h"
61 #include "MagickCore/monitor-private.h"
62 #include "MagickCore/pixel-accessor.h"
63 #include "MagickCore/resource_.h"
64 #include "MagickCore/resize.h"
65 #include "MagickCore/statistic.h"
66 #include "MagickCore/string_.h"
67 #include "MagickCore/thread-private.h"
68 #include "MagickCore/transform.h"
71 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
75 % A u t o O r i e n t I m a g e %
79 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
81 % AutoOrientImage() adjusts an image so that its orientation is suitable for
82 % viewing (i.e. top-left orientation).
84 % The format of the AutoOrientImage method is:
86 % Image *AutoOrientImage(const Image *image,
87 % const OrientationType orientation,ExceptionInfo *exception)
89 % A description of each parameter follows:
93 % o orientation: Current image orientation.
95 % o exception: Return any errors or warnings in this structure.
98 MagickExport Image *AutoOrientImage(const Image *image,
99 const OrientationType orientation,ExceptionInfo *exception)
104 assert(image != (const Image *) NULL);
105 assert(image->signature == MagickSignature);
106 assert(exception != (ExceptionInfo *) NULL);
107 assert(exception->signature == MagickSignature);
108 orient_image=(Image *) NULL;
111 case UndefinedOrientation:
112 case TopLeftOrientation:
115 orient_image=CloneImage(image,0,0,MagickTrue,exception);
118 case TopRightOrientation:
120 orient_image=FlopImage(image,exception);
123 case BottomRightOrientation:
125 orient_image=RotateImage(image,180.0,exception);
128 case BottomLeftOrientation:
130 orient_image=FlipImage(image,exception);
133 case LeftTopOrientation:
135 orient_image=TransposeImage(image,exception);
138 case RightTopOrientation:
140 orient_image=RotateImage(image,90.0,exception);
143 case RightBottomOrientation:
145 orient_image=TransverseImage(image,exception);
148 case LeftBottomOrientation:
150 orient_image=RotateImage(image,270.0,exception);
154 if (orient_image != (Image *) NULL)
155 orient_image->orientation=TopLeftOrientation;
156 return(orient_image);
160 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
164 % C h o p I m a g e %
168 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
170 % ChopImage() removes a region of an image and collapses the image to occupy
171 % the removed portion.
173 % The format of the ChopImage method is:
175 % Image *ChopImage(const Image *image,const RectangleInfo *chop_info)
176 % ExceptionInfo *exception)
178 % A description of each parameter follows:
180 % o image: the image.
182 % o chop_info: Define the region of the image to chop.
184 % o exception: return any errors or warnings in this structure.
187 MagickExport Image *ChopImage(const Image *image,const RectangleInfo *chop_info,
188 ExceptionInfo *exception)
190 #define ChopImageTag "Chop/Image"
214 assert(image != (const Image *) NULL);
215 assert(image->signature == MagickSignature);
216 if (image->debug != MagickFalse)
217 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
218 assert(exception != (ExceptionInfo *) NULL);
219 assert(exception->signature == MagickSignature);
220 assert(chop_info != (RectangleInfo *) NULL);
221 if (((chop_info->x+(ssize_t) chop_info->width) < 0) ||
222 ((chop_info->y+(ssize_t) chop_info->height) < 0) ||
223 (chop_info->x > (ssize_t) image->columns) ||
224 (chop_info->y > (ssize_t) image->rows))
225 ThrowImageException(OptionWarning,"GeometryDoesNotContainImage");
227 if ((extent.x+(ssize_t) extent.width) > (ssize_t) image->columns)
228 extent.width=(size_t) ((ssize_t) image->columns-extent.x);
229 if ((extent.y+(ssize_t) extent.height) > (ssize_t) image->rows)
230 extent.height=(size_t) ((ssize_t) image->rows-extent.y);
233 extent.width-=(size_t) (-extent.x);
238 extent.height-=(size_t) (-extent.y);
241 chop_image=CloneImage(image,image->columns-extent.width,image->rows-
242 extent.height,MagickTrue,exception);
243 if (chop_image == (Image *) NULL)
244 return((Image *) NULL);
250 image_view=AcquireVirtualCacheView(image,exception);
251 chop_view=AcquireAuthenticCacheView(chop_image,exception);
252 #if defined(MAGICKCORE_OPENMP_SUPPORT)
253 #pragma omp parallel for schedule(static,4) shared(status) \
254 magick_threads(image,chop_image,1,1)
256 for (y=0; y < (ssize_t) extent.y; y++)
258 register const Quantum
267 if (status == MagickFalse)
269 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
270 q=QueueCacheViewAuthenticPixels(chop_view,0,y,chop_image->columns,1,
272 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
277 for (x=0; x < (ssize_t) image->columns; x++)
279 if ((x < extent.x) || (x >= (ssize_t) (extent.x+extent.width)))
284 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
286 PixelChannel channel=GetPixelChannelChannel(image,i);
287 PixelTrait traits=GetPixelChannelTraits(image,channel);
288 PixelTrait chop_traits=GetPixelChannelTraits(chop_image,channel);
289 if ((traits == UndefinedPixelTrait) ||
290 (chop_traits == UndefinedPixelTrait))
292 SetPixelChannel(chop_image,channel,p[i],q);
294 q+=GetPixelChannels(chop_image);
296 p+=GetPixelChannels(image);
298 if (SyncCacheViewAuthenticPixels(chop_view,exception) == MagickFalse)
300 if (image->progress_monitor != (MagickProgressMonitor) NULL)
305 #if defined(MAGICKCORE_OPENMP_SUPPORT)
306 #pragma omp critical (MagickCore_ChopImage)
308 proceed=SetImageProgress(image,ChopImageTag,progress++,image->rows);
309 if (proceed == MagickFalse)
316 #if defined(MAGICKCORE_OPENMP_SUPPORT)
317 #pragma omp parallel for schedule(static,4) shared(progress,status) \
318 magick_threads(image,chop_image,1,1)
320 for (y=0; y < (ssize_t) (image->rows-(extent.y+extent.height)); y++)
322 register const Quantum
331 if (status == MagickFalse)
333 p=GetCacheViewVirtualPixels(image_view,0,extent.y+extent.height+y,
334 image->columns,1,exception);
335 q=QueueCacheViewAuthenticPixels(chop_view,0,extent.y+y,chop_image->columns,
337 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
342 for (x=0; x < (ssize_t) image->columns; x++)
344 if ((x < extent.x) || (x >= (ssize_t) (extent.x+extent.width)))
349 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
351 PixelChannel channel=GetPixelChannelChannel(image,i);
352 PixelTrait traits=GetPixelChannelTraits(image,channel);
353 PixelTrait chop_traits=GetPixelChannelTraits(chop_image,channel);
354 if ((traits == UndefinedPixelTrait) ||
355 (chop_traits == UndefinedPixelTrait))
357 SetPixelChannel(chop_image,channel,p[i],q);
359 q+=GetPixelChannels(chop_image);
361 p+=GetPixelChannels(image);
363 if (SyncCacheViewAuthenticPixels(chop_view,exception) == MagickFalse)
365 if (image->progress_monitor != (MagickProgressMonitor) NULL)
370 #if defined(MAGICKCORE_OPENMP_SUPPORT)
371 #pragma omp critical (MagickCore_ChopImage)
373 proceed=SetImageProgress(image,ChopImageTag,progress++,image->rows);
374 if (proceed == MagickFalse)
378 chop_view=DestroyCacheView(chop_view);
379 image_view=DestroyCacheView(image_view);
380 chop_image->type=image->type;
381 if (status == MagickFalse)
382 chop_image=DestroyImage(chop_image);
387 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
391 + C o n s o l i d a t e C M Y K I m a g e %
395 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
397 % ConsolidateCMYKImage() consolidates separate C, M, Y, and K planes into a
400 % The format of the ConsolidateCMYKImage method is:
402 % Image *ConsolidateCMYKImage(const Image *image,ExceptionInfo *exception)
404 % A description of each parameter follows:
406 % o image: the image sequence.
408 % o exception: return any errors or warnings in this structure.
411 MagickExport Image *ConsolidateCMYKImages(const Image *images,
412 ExceptionInfo *exception)
429 Consolidate separate C, M, Y, and K planes into a single image.
431 assert(images != (Image *) NULL);
432 assert(images->signature == MagickSignature);
433 if (images->debug != MagickFalse)
434 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
435 assert(exception != (ExceptionInfo *) NULL);
436 assert(exception->signature == MagickSignature);
437 cmyk_images=NewImageList();
438 for (j=0; j < (ssize_t) GetImageListLength(images); j+=4)
443 assert(images != (Image *) NULL);
444 cmyk_image=CloneImage(images,images->columns,images->rows,MagickTrue,
446 if (cmyk_image == (Image *) NULL)
448 if (SetImageStorageClass(cmyk_image,DirectClass,exception) == MagickFalse)
450 (void) SetImageColorspace(cmyk_image,CMYKColorspace,exception);
451 for (i=0; i < 4; i++)
453 image_view=AcquireVirtualCacheView(images,exception);
454 cmyk_view=AcquireAuthenticCacheView(cmyk_image,exception);
455 for (y=0; y < (ssize_t) images->rows; y++)
457 register const Quantum
466 p=GetCacheViewVirtualPixels(image_view,0,y,images->columns,1,exception);
467 q=QueueCacheViewAuthenticPixels(cmyk_view,0,y,cmyk_image->columns,1,
469 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
471 for (x=0; x < (ssize_t) images->columns; x++)
476 pixel=QuantumRange-GetPixelIntensity(images,p);
479 case 0: SetPixelCyan(cmyk_image,pixel,q); break;
480 case 1: SetPixelMagenta(cmyk_image,pixel,q); break;
481 case 2: SetPixelYellow(cmyk_image,pixel,q); break;
482 case 3: SetPixelBlack(cmyk_image,pixel,q); break;
485 p+=GetPixelChannels(images);
486 q+=GetPixelChannels(cmyk_image);
488 if (SyncCacheViewAuthenticPixels(cmyk_view,exception) == MagickFalse)
491 cmyk_view=DestroyCacheView(cmyk_view);
492 image_view=DestroyCacheView(image_view);
493 images=GetNextImageInList(images);
494 if (images == (Image *) NULL)
497 AppendImageToList(&cmyk_images,cmyk_image);
503 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
507 % C r o p I m a g e %
511 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
513 % CropImage() extracts a region of the image starting at the offset defined
514 % by geometry. Region must be fully defined, and no special handling of
515 % geometry flags is performed.
517 % The format of the CropImage method is:
519 % Image *CropImage(const Image *image,const RectangleInfo *geometry,
520 % ExceptionInfo *exception)
522 % A description of each parameter follows:
524 % o image: the image.
526 % o geometry: Define the region of the image to crop with members
527 % x, y, width, and height.
529 % o exception: return any errors or warnings in this structure.
532 MagickExport Image *CropImage(const Image *image,const RectangleInfo *geometry,
533 ExceptionInfo *exception)
535 #define CropImageTag "Crop/Image"
563 assert(image != (const Image *) NULL);
564 assert(image->signature == MagickSignature);
565 if (image->debug != MagickFalse)
566 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
567 assert(geometry != (const RectangleInfo *) NULL);
568 assert(exception != (ExceptionInfo *) NULL);
569 assert(exception->signature == MagickSignature);
570 bounding_box=image->page;
571 if ((bounding_box.width == 0) || (bounding_box.height == 0))
573 bounding_box.width=image->columns;
574 bounding_box.height=image->rows;
578 page.width=bounding_box.width;
579 if (page.height == 0)
580 page.height=bounding_box.height;
581 if (((bounding_box.x-page.x) >= (ssize_t) page.width) ||
582 ((bounding_box.y-page.y) >= (ssize_t) page.height) ||
583 ((page.x-bounding_box.x) > (ssize_t) image->columns) ||
584 ((page.y-bounding_box.y) > (ssize_t) image->rows))
587 Crop is not within virtual canvas, return 1 pixel transparent image.
589 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
590 "GeometryDoesNotContainImage","`%s'",image->filename);
591 crop_image=CloneImage(image,1,1,MagickTrue,exception);
592 if (crop_image == (Image *) NULL)
593 return((Image *) NULL);
594 crop_image->background_color.alpha=(Quantum) TransparentAlpha;
595 crop_image->alpha_trait=BlendPixelTrait;
596 (void) SetImageBackgroundColor(crop_image,exception);
597 crop_image->page=bounding_box;
598 crop_image->page.x=(-1);
599 crop_image->page.y=(-1);
600 if (crop_image->dispose == BackgroundDispose)
601 crop_image->dispose=NoneDispose;
604 if ((page.x < 0) && (bounding_box.x >= 0))
606 page.width+=page.x-bounding_box.x;
611 page.width-=bounding_box.x-page.x;
612 page.x-=bounding_box.x;
616 if ((page.y < 0) && (bounding_box.y >= 0))
618 page.height+=page.y-bounding_box.y;
623 page.height-=bounding_box.y-page.y;
624 page.y-=bounding_box.y;
628 if ((page.x+(ssize_t) page.width) > (ssize_t) image->columns)
629 page.width=image->columns-page.x;
630 if ((geometry->width != 0) && (page.width > geometry->width))
631 page.width=geometry->width;
632 if ((page.y+(ssize_t) page.height) > (ssize_t) image->rows)
633 page.height=image->rows-page.y;
634 if ((geometry->height != 0) && (page.height > geometry->height))
635 page.height=geometry->height;
636 bounding_box.x+=page.x;
637 bounding_box.y+=page.y;
638 if ((page.width == 0) || (page.height == 0))
640 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
641 "GeometryDoesNotContainImage","`%s'",image->filename);
642 return((Image *) NULL);
645 Initialize crop image attributes.
647 crop_image=CloneImage(image,page.width,page.height,MagickTrue,exception);
648 if (crop_image == (Image *) NULL)
649 return((Image *) NULL);
650 crop_image->page.width=image->page.width;
651 crop_image->page.height=image->page.height;
652 offset.x=(ssize_t) (bounding_box.x+bounding_box.width);
653 offset.y=(ssize_t) (bounding_box.y+bounding_box.height);
654 if ((offset.x > (ssize_t) image->page.width) ||
655 (offset.y > (ssize_t) image->page.height))
657 crop_image->page.width=bounding_box.width;
658 crop_image->page.height=bounding_box.height;
660 crop_image->page.x=bounding_box.x;
661 crop_image->page.y=bounding_box.y;
667 image_view=AcquireVirtualCacheView(image,exception);
668 crop_view=AcquireAuthenticCacheView(crop_image,exception);
669 #if defined(MAGICKCORE_OPENMP_SUPPORT)
670 #pragma omp parallel for schedule(static,4) shared(status) \
671 magick_threads(image,crop_image,1,1)
673 for (y=0; y < (ssize_t) crop_image->rows; y++)
675 register const Quantum
684 if (status == MagickFalse)
686 p=GetCacheViewVirtualPixels(image_view,page.x,page.y+y,crop_image->columns,
688 q=QueueCacheViewAuthenticPixels(crop_view,0,y,crop_image->columns,1,
690 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
695 for (x=0; x < (ssize_t) crop_image->columns; x++)
700 if (GetPixelReadMask(image,p) == 0)
702 SetPixelBackgoundColor(crop_image,q);
703 p+=GetPixelChannels(image);
704 q+=GetPixelChannels(crop_image);
707 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
709 PixelChannel channel=GetPixelChannelChannel(image,i);
710 PixelTrait traits=GetPixelChannelTraits(image,channel);
711 PixelTrait crop_traits=GetPixelChannelTraits(crop_image,channel);
712 if ((traits == UndefinedPixelTrait) ||
713 (crop_traits == UndefinedPixelTrait))
715 SetPixelChannel(crop_image,channel,p[i],q);
717 p+=GetPixelChannels(image);
718 q+=GetPixelChannels(crop_image);
720 if (SyncCacheViewAuthenticPixels(crop_view,exception) == MagickFalse)
722 if (image->progress_monitor != (MagickProgressMonitor) NULL)
727 #if defined(MAGICKCORE_OPENMP_SUPPORT)
728 #pragma omp critical (MagickCore_CropImage)
730 proceed=SetImageProgress(image,CropImageTag,progress++,image->rows);
731 if (proceed == MagickFalse)
735 crop_view=DestroyCacheView(crop_view);
736 image_view=DestroyCacheView(image_view);
737 crop_image->type=image->type;
738 if (status == MagickFalse)
739 crop_image=DestroyImage(crop_image);
744 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
748 % C r o p I m a g e T o T i l e s %
752 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
754 % CropImageToTiles() crops a single image, into a possible list of tiles.
755 % This may include a single sub-region of the image. This basically applies
756 % all the normal geometry flags for Crop.
758 % Image *CropImageToTiles(const Image *image,
759 % const RectangleInfo *crop_geometry, ExceptionInfo *exception)
761 % A description of each parameter follows:
763 % o image: the image The transformed image is returned as this parameter.
765 % o crop_geometry: A crop geometry string.
767 % o exception: return any errors or warnings in this structure.
771 static inline double MagickRound(double x)
774 Round the fraction to nearest integer.
776 if ((x-floor(x)) < (ceil(x)-x))
781 MagickExport Image *CropImageToTiles(const Image *image,
782 const char *crop_geometry,ExceptionInfo *exception)
794 assert(image != (Image *) NULL);
795 assert(image->signature == MagickSignature);
796 if (image->debug != MagickFalse)
797 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
798 crop_image=NewImageList();
800 flags=ParseGravityGeometry(image,crop_geometry,&geometry,exception);
801 if ((flags & AreaValue) != 0)
815 Crop into NxM tiles (@ flag).
817 width=image->columns;
819 if (geometry.width == 0)
821 if (geometry.height == 0)
823 if ((flags & AspectValue) == 0)
825 width-=(geometry.x < 0 ? -1 : 1)*geometry.x;
826 height-=(geometry.y < 0 ? -1 : 1)*geometry.y;
830 width+=(geometry.x < 0 ? -1 : 1)*geometry.x;
831 height+=(geometry.y < 0 ? -1 : 1)*geometry.y;
833 delta.x=(double) width/geometry.width;
834 delta.y=(double) height/geometry.height;
839 for (offset.y=0; offset.y < (double) height; )
841 if ((flags & AspectValue) == 0)
843 crop.y=(ssize_t) MagickRound((double) (offset.y-
844 (geometry.y > 0 ? 0 : geometry.y)));
845 offset.y+=delta.y; /* increment now to find width */
846 crop.height=(size_t) MagickRound((double) (offset.y+
847 (geometry.y < 0 ? 0 : geometry.y)));
851 crop.y=(ssize_t) MagickRound((double) (offset.y-
852 (geometry.y > 0 ? geometry.y : 0)));
853 offset.y+=delta.y; /* increment now to find width */
854 crop.height=(size_t) MagickRound((double)
855 (offset.y+(geometry.y < -1 ? geometry.y : 0)));
858 crop.y+=image->page.y;
859 for (offset.x=0; offset.x < (double) width; )
861 if ((flags & AspectValue) == 0)
863 crop.x=(ssize_t) MagickRound((double) (offset.x-
864 (geometry.x > 0 ? 0 : geometry.x)));
865 offset.x+=delta.x; /* increment now to find height */
866 crop.width=(size_t) MagickRound((double) (offset.x+
867 (geometry.x < 0 ? 0 : geometry.x)));
871 crop.x=(ssize_t) MagickRound((double) (offset.x-
872 (geometry.x > 0 ? geometry.x : 0)));
873 offset.x+=delta.x; /* increment now to find height */
874 crop.width=(size_t) MagickRound((double) (offset.x+
875 (geometry.x < 0 ? geometry.x : 0)));
878 crop.x+=image->page.x;
879 next=CropImage(image,&crop,exception);
880 if (next == (Image *) NULL)
882 AppendImageToList(&crop_image,next);
884 if (next == (Image *) NULL)
887 ClearMagickException(exception);
890 if (((geometry.width == 0) && (geometry.height == 0)) ||
891 ((flags & XValue) != 0) || ((flags & YValue) != 0))
894 Crop a single region at +X+Y.
896 crop_image=CropImage(image,&geometry,exception);
897 if ((crop_image != (Image *) NULL) && ((flags & AspectValue) != 0))
899 crop_image->page.width=geometry.width;
900 crop_image->page.height=geometry.height;
901 crop_image->page.x-=geometry.x;
902 crop_image->page.y-=geometry.y;
906 if ((image->columns > geometry.width) || (image->rows > geometry.height))
920 Crop into tiles of fixed size WxH.
924 page.width=image->columns;
925 if (page.height == 0)
926 page.height=image->rows;
927 width=geometry.width;
930 height=geometry.height;
934 for (y=0; y < (ssize_t) page.height; y+=(ssize_t) height)
936 for (x=0; x < (ssize_t) page.width; x+=(ssize_t) width)
938 geometry.width=width;
939 geometry.height=height;
942 next=CropImage(image,&geometry,exception);
943 if (next == (Image *) NULL)
945 AppendImageToList(&crop_image,next);
947 if (next == (Image *) NULL)
952 return(CloneImage(image,0,0,MagickTrue,exception));
956 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
960 % E x c e r p t I m a g e %
964 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
966 % ExcerptImage() returns a excerpt of the image as defined by the geometry.
968 % The format of the ExcerptImage method is:
970 % Image *ExcerptImage(const Image *image,const RectangleInfo *geometry,
971 % ExceptionInfo *exception)
973 % A description of each parameter follows:
975 % o image: the image.
977 % o geometry: Define the region of the image to extend with members
978 % x, y, width, and height.
980 % o exception: return any errors or warnings in this structure.
983 MagickExport Image *ExcerptImage(const Image *image,
984 const RectangleInfo *geometry,ExceptionInfo *exception)
986 #define ExcerptImageTag "Excerpt/Image"
1005 Allocate excerpt image.
1007 assert(image != (const Image *) NULL);
1008 assert(image->signature == MagickSignature);
1009 if (image->debug != MagickFalse)
1010 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1011 assert(geometry != (const RectangleInfo *) NULL);
1012 assert(exception != (ExceptionInfo *) NULL);
1013 assert(exception->signature == MagickSignature);
1014 excerpt_image=CloneImage(image,geometry->width,geometry->height,MagickTrue,
1016 if (excerpt_image == (Image *) NULL)
1017 return((Image *) NULL);
1023 image_view=AcquireVirtualCacheView(image,exception);
1024 excerpt_view=AcquireAuthenticCacheView(excerpt_image,exception);
1025 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1026 #pragma omp parallel for schedule(static,4) shared(progress,status) \
1027 magick_threads(image,excerpt_image,excerpt_image->rows,1)
1029 for (y=0; y < (ssize_t) excerpt_image->rows; y++)
1031 register const Quantum
1040 if (status == MagickFalse)
1042 p=GetCacheViewVirtualPixels(image_view,geometry->x,geometry->y+y,
1043 geometry->width,1,exception);
1044 q=GetCacheViewAuthenticPixels(excerpt_view,0,y,excerpt_image->columns,1,
1046 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1051 for (x=0; x < (ssize_t) excerpt_image->columns; x++)
1056 if (GetPixelReadMask(image,p) == 0)
1058 SetPixelBackgoundColor(excerpt_image,q);
1059 p+=GetPixelChannels(image);
1060 q+=GetPixelChannels(excerpt_image);
1063 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1065 PixelChannel channel=GetPixelChannelChannel(image,i);
1066 PixelTrait traits=GetPixelChannelTraits(image,channel);
1067 PixelTrait excerpt_traits=GetPixelChannelTraits(excerpt_image,channel);
1068 if ((traits == UndefinedPixelTrait) ||
1069 (excerpt_traits == UndefinedPixelTrait))
1071 SetPixelChannel(excerpt_image,channel,p[i],q);
1073 p+=GetPixelChannels(image);
1074 q+=GetPixelChannels(excerpt_image);
1076 if (SyncCacheViewAuthenticPixels(excerpt_view,exception) == MagickFalse)
1078 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1083 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1084 #pragma omp critical (MagickCore_ExcerptImage)
1086 proceed=SetImageProgress(image,ExcerptImageTag,progress++,image->rows);
1087 if (proceed == MagickFalse)
1091 excerpt_view=DestroyCacheView(excerpt_view);
1092 image_view=DestroyCacheView(image_view);
1093 excerpt_image->type=image->type;
1094 if (status == MagickFalse)
1095 excerpt_image=DestroyImage(excerpt_image);
1096 return(excerpt_image);
1100 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1104 % E x t e n t I m a g e %
1108 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1110 % ExtentImage() extends the image as defined by the geometry, gravity, and
1111 % image background color. Set the (x,y) offset of the geometry to move the
1112 % original image relative to the extended image.
1114 % The format of the ExtentImage method is:
1116 % Image *ExtentImage(const Image *image,const RectangleInfo *geometry,
1117 % ExceptionInfo *exception)
1119 % A description of each parameter follows:
1121 % o image: the image.
1123 % o geometry: Define the region of the image to extend with members
1124 % x, y, width, and height.
1126 % o exception: return any errors or warnings in this structure.
1129 MagickExport Image *ExtentImage(const Image *image,
1130 const RectangleInfo *geometry,ExceptionInfo *exception)
1136 Allocate extent image.
1138 assert(image != (const Image *) NULL);
1139 assert(image->signature == MagickSignature);
1140 if (image->debug != MagickFalse)
1141 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1142 assert(geometry != (const RectangleInfo *) NULL);
1143 assert(exception != (ExceptionInfo *) NULL);
1144 assert(exception->signature == MagickSignature);
1145 if ((image->columns == geometry->width) &&
1146 (image->rows == geometry->height) &&
1147 (geometry->x == 0) && (geometry->y == 0))
1148 return(CloneImage(image,0,0,MagickTrue,exception));
1149 extent_image=CloneImage(image,geometry->width,geometry->height,MagickTrue,
1151 if (extent_image == (Image *) NULL)
1152 return((Image *) NULL);
1153 (void) SetImageBackgroundColor(extent_image,exception);
1154 (void) CompositeImage(extent_image,image,image->compose,MagickTrue,
1155 -geometry->x,-geometry->y,exception);
1156 return(extent_image);
1160 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1164 % F l i p I m a g e %
1168 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1170 % FlipImage() creates a vertical mirror image by reflecting the pixels
1171 % around the central x-axis.
1173 % The format of the FlipImage method is:
1175 % Image *FlipImage(const Image *image,ExceptionInfo *exception)
1177 % A description of each parameter follows:
1179 % o image: the image.
1181 % o exception: return any errors or warnings in this structure.
1184 MagickExport Image *FlipImage(const Image *image,ExceptionInfo *exception)
1186 #define FlipImageTag "Flip/Image"
1207 assert(image != (const Image *) NULL);
1208 assert(image->signature == MagickSignature);
1209 if (image->debug != MagickFalse)
1210 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1211 assert(exception != (ExceptionInfo *) NULL);
1212 assert(exception->signature == MagickSignature);
1213 flip_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
1214 if (flip_image == (Image *) NULL)
1215 return((Image *) NULL);
1222 image_view=AcquireVirtualCacheView(image,exception);
1223 flip_view=AcquireAuthenticCacheView(flip_image,exception);
1224 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1225 #pragma omp parallel for schedule(static,4) shared(status) \
1226 magick_threads(image,flip_image,1,1)
1228 for (y=0; y < (ssize_t) flip_image->rows; y++)
1230 register const Quantum
1239 if (status == MagickFalse)
1241 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1242 q=QueueCacheViewAuthenticPixels(flip_view,0,(ssize_t) (flip_image->rows-y-
1243 1),flip_image->columns,1,exception);
1244 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1249 for (x=0; x < (ssize_t) flip_image->columns; x++)
1254 if (GetPixelReadMask(image,p) == 0)
1256 SetPixelBackgoundColor(flip_image,q);
1257 p+=GetPixelChannels(image);
1258 q+=GetPixelChannels(flip_image);
1261 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1263 PixelChannel channel=GetPixelChannelChannel(image,i);
1264 PixelTrait traits=GetPixelChannelTraits(image,channel);
1265 PixelTrait flip_traits=GetPixelChannelTraits(flip_image,channel);
1266 if ((traits == UndefinedPixelTrait) ||
1267 (flip_traits == UndefinedPixelTrait))
1269 SetPixelChannel(flip_image,channel,p[i],q);
1271 p+=GetPixelChannels(image);
1272 q+=GetPixelChannels(flip_image);
1274 if (SyncCacheViewAuthenticPixels(flip_view,exception) == MagickFalse)
1276 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1281 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1282 #pragma omp critical (MagickCore_FlipImage)
1284 proceed=SetImageProgress(image,FlipImageTag,progress++,image->rows);
1285 if (proceed == MagickFalse)
1289 flip_view=DestroyCacheView(flip_view);
1290 image_view=DestroyCacheView(image_view);
1291 flip_image->type=image->type;
1292 if (page.height != 0)
1293 page.y=(ssize_t) (page.height-flip_image->rows-page.y);
1294 flip_image->page=page;
1295 if (status == MagickFalse)
1296 flip_image=DestroyImage(flip_image);
1301 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1305 % F l o p I m a g e %
1309 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1311 % FlopImage() creates a horizontal mirror image by reflecting the pixels
1312 % around the central y-axis.
1314 % The format of the FlopImage method is:
1316 % Image *FlopImage(const Image *image,ExceptionInfo *exception)
1318 % A description of each parameter follows:
1320 % o image: the image.
1322 % o exception: return any errors or warnings in this structure.
1325 MagickExport Image *FlopImage(const Image *image,ExceptionInfo *exception)
1327 #define FlopImageTag "Flop/Image"
1348 assert(image != (const Image *) NULL);
1349 assert(image->signature == MagickSignature);
1350 if (image->debug != MagickFalse)
1351 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1352 assert(exception != (ExceptionInfo *) NULL);
1353 assert(exception->signature == MagickSignature);
1354 flop_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
1355 if (flop_image == (Image *) NULL)
1356 return((Image *) NULL);
1363 image_view=AcquireVirtualCacheView(image,exception);
1364 flop_view=AcquireAuthenticCacheView(flop_image,exception);
1365 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1366 #pragma omp parallel for schedule(static,4) shared(status) \
1367 magick_threads(image,flop_image,1,1)
1369 for (y=0; y < (ssize_t) flop_image->rows; y++)
1371 register const Quantum
1380 if (status == MagickFalse)
1382 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1383 q=QueueCacheViewAuthenticPixels(flop_view,0,y,flop_image->columns,1,
1385 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1390 q+=GetPixelChannels(flop_image)*flop_image->columns;
1391 for (x=0; x < (ssize_t) flop_image->columns; x++)
1396 q-=GetPixelChannels(flop_image);
1397 if (GetPixelReadMask(image,p) == 0)
1399 p+=GetPixelChannels(image);
1402 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1404 PixelChannel channel=GetPixelChannelChannel(image,i);
1405 PixelTrait traits=GetPixelChannelTraits(image,channel);
1406 PixelTrait flop_traits=GetPixelChannelTraits(flop_image,channel);
1407 if ((traits == UndefinedPixelTrait) ||
1408 (flop_traits == UndefinedPixelTrait))
1410 SetPixelChannel(flop_image,channel,p[i],q);
1412 p+=GetPixelChannels(image);
1414 if (SyncCacheViewAuthenticPixels(flop_view,exception) == MagickFalse)
1416 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1421 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1422 #pragma omp critical (MagickCore_FlopImage)
1424 proceed=SetImageProgress(image,FlopImageTag,progress++,image->rows);
1425 if (proceed == MagickFalse)
1429 flop_view=DestroyCacheView(flop_view);
1430 image_view=DestroyCacheView(image_view);
1431 flop_image->type=image->type;
1432 if (page.width != 0)
1433 page.x=(ssize_t) (page.width-flop_image->columns-page.x);
1434 flop_image->page=page;
1435 if (status == MagickFalse)
1436 flop_image=DestroyImage(flop_image);
1441 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1445 % R o l l I m a g e %
1449 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1451 % RollImage() offsets an image as defined by x_offset and y_offset.
1453 % The format of the RollImage method is:
1455 % Image *RollImage(const Image *image,const ssize_t x_offset,
1456 % const ssize_t y_offset,ExceptionInfo *exception)
1458 % A description of each parameter follows:
1460 % o image: the image.
1462 % o x_offset: the number of columns to roll in the horizontal direction.
1464 % o y_offset: the number of rows to roll in the vertical direction.
1466 % o exception: return any errors or warnings in this structure.
1470 static inline MagickBooleanType CopyImageRegion(Image *destination,
1471 const Image *source,const size_t columns,const size_t rows,
1472 const ssize_t sx,const ssize_t sy,const ssize_t dx,const ssize_t dy,
1473 ExceptionInfo *exception)
1488 source_view=AcquireVirtualCacheView(source,exception);
1489 destination_view=AcquireAuthenticCacheView(destination,exception);
1490 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1491 #pragma omp parallel for schedule(static,4) shared(status) \
1492 magick_threads(source,destination,rows,1)
1494 for (y=0; y < (ssize_t) rows; y++)
1499 register const Quantum
1511 if (status == MagickFalse)
1513 p=GetCacheViewVirtualPixels(source_view,sx,sy+y,columns,1,exception);
1514 q=GetCacheViewAuthenticPixels(destination_view,dx,dy+y,columns,1,exception);
1515 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1520 for (x=0; x < (ssize_t) columns; x++)
1525 if (GetPixelReadMask(source,p) == 0)
1527 SetPixelBackgoundColor(destination,q);
1528 p+=GetPixelChannels(source);
1529 q+=GetPixelChannels(destination);
1532 for (i=0; i < (ssize_t) GetPixelChannels(source); i++)
1534 PixelChannel channel=GetPixelChannelChannel(source,i);
1535 PixelTrait source_traits=GetPixelChannelTraits(source,channel);
1536 PixelTrait destination_traits=GetPixelChannelTraits(destination,
1538 if ((source_traits == UndefinedPixelTrait) ||
1539 (destination_traits == UndefinedPixelTrait))
1541 SetPixelChannel(destination,channel,p[i],q);
1543 p+=GetPixelChannels(source);
1544 q+=GetPixelChannels(destination);
1546 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
1547 if (sync == MagickFalse)
1550 destination_view=DestroyCacheView(destination_view);
1551 source_view=DestroyCacheView(source_view);
1555 MagickExport Image *RollImage(const Image *image,const ssize_t x_offset,
1556 const ssize_t y_offset,ExceptionInfo *exception)
1558 #define RollImageTag "Roll/Image"
1570 Initialize roll image attributes.
1572 assert(image != (const Image *) NULL);
1573 assert(image->signature == MagickSignature);
1574 if (image->debug != MagickFalse)
1575 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1576 assert(exception != (ExceptionInfo *) NULL);
1577 assert(exception->signature == MagickSignature);
1578 roll_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
1579 if (roll_image == (Image *) NULL)
1580 return((Image *) NULL);
1583 while (offset.x < 0)
1584 offset.x+=(ssize_t) image->columns;
1585 while (offset.x >= (ssize_t) image->columns)
1586 offset.x-=(ssize_t) image->columns;
1587 while (offset.y < 0)
1588 offset.y+=(ssize_t) image->rows;
1589 while (offset.y >= (ssize_t) image->rows)
1590 offset.y-=(ssize_t) image->rows;
1594 status=CopyImageRegion(roll_image,image,(size_t) offset.x,
1595 (size_t) offset.y,(ssize_t) image->columns-offset.x,(ssize_t) image->rows-
1596 offset.y,0,0,exception);
1597 (void) SetImageProgress(image,RollImageTag,0,3);
1598 status&=CopyImageRegion(roll_image,image,image->columns-offset.x,
1599 (size_t) offset.y,0,(ssize_t) image->rows-offset.y,offset.x,0,
1601 (void) SetImageProgress(image,RollImageTag,1,3);
1602 status&=CopyImageRegion(roll_image,image,(size_t) offset.x,image->rows-
1603 offset.y,(ssize_t) image->columns-offset.x,0,0,offset.y,exception);
1604 (void) SetImageProgress(image,RollImageTag,2,3);
1605 status&=CopyImageRegion(roll_image,image,image->columns-offset.x,image->rows-
1606 offset.y,0,0,offset.x,offset.y,exception);
1607 (void) SetImageProgress(image,RollImageTag,3,3);
1608 roll_image->type=image->type;
1609 if (status == MagickFalse)
1610 roll_image=DestroyImage(roll_image);
1615 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1619 % S h a v e I m a g e %
1623 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1625 % ShaveImage() shaves pixels from the image edges. It allocates the memory
1626 % necessary for the new Image structure and returns a pointer to the new
1629 % The format of the ShaveImage method is:
1631 % Image *ShaveImage(const Image *image,const RectangleInfo *shave_info,
1632 % ExceptionInfo *exception)
1634 % A description of each parameter follows:
1636 % o shave_image: Method ShaveImage returns a pointer to the shaved
1637 % image. A null image is returned if there is a memory shortage or
1638 % if the image width or height is zero.
1640 % o image: the image.
1642 % o shave_info: Specifies a pointer to a RectangleInfo which defines the
1643 % region of the image to crop.
1645 % o exception: return any errors or warnings in this structure.
1648 MagickExport Image *ShaveImage(const Image *image,
1649 const RectangleInfo *shave_info,ExceptionInfo *exception)
1657 assert(image != (const Image *) NULL);
1658 assert(image->signature == MagickSignature);
1659 if (image->debug != MagickFalse)
1660 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1661 if (((2*shave_info->width) >= image->columns) ||
1662 ((2*shave_info->height) >= image->rows))
1663 ThrowImageException(OptionWarning,"GeometryDoesNotContainImage");
1664 SetGeometry(image,&geometry);
1665 geometry.width-=2*shave_info->width;
1666 geometry.height-=2*shave_info->height;
1667 geometry.x=(ssize_t) shave_info->width+image->page.x;
1668 geometry.y=(ssize_t) shave_info->height+image->page.y;
1669 shave_image=CropImage(image,&geometry,exception);
1670 if (shave_image == (Image *) NULL)
1671 return((Image *) NULL);
1672 shave_image->page.width-=2*shave_info->width;
1673 shave_image->page.height-=2*shave_info->height;
1674 shave_image->page.x-=(ssize_t) shave_info->width;
1675 shave_image->page.y-=(ssize_t) shave_info->height;
1676 return(shave_image);
1680 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1684 % S p l i c e I m a g e %
1688 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1690 % SpliceImage() splices a solid color into the image as defined by the
1693 % The format of the SpliceImage method is:
1695 % Image *SpliceImage(const Image *image,const RectangleInfo *geometry,
1696 % ExceptionInfo *exception)
1698 % A description of each parameter follows:
1700 % o image: the image.
1702 % o geometry: Define the region of the image to splice with members
1703 % x, y, width, and height.
1705 % o exception: return any errors or warnings in this structure.
1708 MagickExport Image *SpliceImage(const Image *image,
1709 const RectangleInfo *geometry,ExceptionInfo *exception)
1711 #define SpliceImageTag "Splice/Image"
1733 Allocate splice image.
1735 assert(image != (const Image *) NULL);
1736 assert(image->signature == MagickSignature);
1737 if (image->debug != MagickFalse)
1738 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1739 assert(geometry != (const RectangleInfo *) NULL);
1740 assert(exception != (ExceptionInfo *) NULL);
1741 assert(exception->signature == MagickSignature);
1742 splice_geometry=(*geometry);
1743 splice_image=CloneImage(image,image->columns+splice_geometry.width,
1744 image->rows+splice_geometry.height,MagickTrue,exception);
1745 if (splice_image == (Image *) NULL)
1746 return((Image *) NULL);
1747 if (SetImageStorageClass(splice_image,DirectClass,exception) == MagickFalse)
1749 splice_image=DestroyImage(splice_image);
1750 return((Image *) NULL);
1752 if ((IsPixelInfoGray(&splice_image->background_color) == MagickFalse) &&
1753 (IsGrayColorspace(splice_image->colorspace) != MagickFalse))
1754 (void) SetImageColorspace(splice_image,sRGBColorspace,exception);
1755 if ((splice_image->background_color.alpha_trait == BlendPixelTrait) &&
1756 (splice_image->alpha_trait != BlendPixelTrait))
1757 (void) SetImageAlpha(splice_image,OpaqueAlpha,exception);
1758 (void) SetImageBackgroundColor(splice_image,exception);
1760 Respect image geometry.
1762 switch (image->gravity)
1765 case UndefinedGravity:
1766 case NorthWestGravity:
1770 splice_geometry.x+=(ssize_t) splice_geometry.width/2;
1773 case NorthEastGravity:
1775 splice_geometry.x+=(ssize_t) splice_geometry.width;
1780 splice_geometry.y+=(ssize_t) splice_geometry.width/2;
1785 splice_geometry.x+=(ssize_t) splice_geometry.width/2;
1786 splice_geometry.y+=(ssize_t) splice_geometry.height/2;
1791 splice_geometry.x+=(ssize_t) splice_geometry.width;
1792 splice_geometry.y+=(ssize_t) splice_geometry.height/2;
1795 case SouthWestGravity:
1797 splice_geometry.y+=(ssize_t) splice_geometry.height;
1802 splice_geometry.x+=(ssize_t) splice_geometry.width/2;
1803 splice_geometry.y+=(ssize_t) splice_geometry.height;
1806 case SouthEastGravity:
1808 splice_geometry.x+=(ssize_t) splice_geometry.width;
1809 splice_geometry.y+=(ssize_t) splice_geometry.height;
1818 image_view=AcquireVirtualCacheView(image,exception);
1819 splice_view=AcquireAuthenticCacheView(splice_image,exception);
1820 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1821 #pragma omp parallel for schedule(static,4) shared(progress,status) \
1822 magick_threads(image,splice_image,1,1)
1824 for (y=0; y < (ssize_t) splice_geometry.y; y++)
1826 register const Quantum
1835 if (status == MagickFalse)
1837 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1838 q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1,
1840 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1845 for (x=0; x < splice_geometry.x; x++)
1850 if (GetPixelReadMask(image,p) == 0)
1852 SetPixelBackgoundColor(splice_image,q);
1853 p+=GetPixelChannels(image);
1854 q+=GetPixelChannels(splice_image);
1857 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1859 PixelChannel channel=GetPixelChannelChannel(image,i);
1860 PixelTrait traits=GetPixelChannelTraits(image,channel);
1861 PixelTrait splice_traits=GetPixelChannelTraits(splice_image,channel);
1862 if ((traits == UndefinedPixelTrait) ||
1863 (splice_traits == UndefinedPixelTrait))
1865 SetPixelChannel(splice_image,channel,p[i],q);
1867 SetPixelRed(splice_image,GetPixelRed(image,p),q);
1868 SetPixelGreen(splice_image,GetPixelGreen(image,p),q);
1869 SetPixelBlue(splice_image,GetPixelBlue(image,p),q);
1870 SetPixelAlpha(splice_image,GetPixelAlpha(image,p),q);
1871 p+=GetPixelChannels(image);
1872 q+=GetPixelChannels(splice_image);
1874 for ( ; x < (ssize_t) (splice_geometry.x+splice_geometry.width); x++)
1875 q+=GetPixelChannels(splice_image);
1876 for ( ; x < (ssize_t) splice_image->columns; x++)
1881 if (GetPixelReadMask(image,p) == 0)
1883 SetPixelBackgoundColor(splice_image,q);
1884 p+=GetPixelChannels(image);
1885 q+=GetPixelChannels(splice_image);
1888 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1890 PixelChannel channel=GetPixelChannelChannel(image,i);
1891 PixelTrait traits=GetPixelChannelTraits(image,channel);
1892 PixelTrait splice_traits=GetPixelChannelTraits(splice_image,channel);
1893 if ((traits == UndefinedPixelTrait) ||
1894 (splice_traits == UndefinedPixelTrait))
1896 SetPixelChannel(splice_image,channel,p[i],q);
1898 SetPixelRed(splice_image,GetPixelRed(image,p),q);
1899 SetPixelGreen(splice_image,GetPixelGreen(image,p),q);
1900 SetPixelBlue(splice_image,GetPixelBlue(image,p),q);
1901 SetPixelAlpha(splice_image,GetPixelAlpha(image,p),q);
1902 p+=GetPixelChannels(image);
1903 q+=GetPixelChannels(splice_image);
1905 if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse)
1907 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1912 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1913 #pragma omp critical (MagickCore_TransposeImage)
1915 proceed=SetImageProgress(image,SpliceImageTag,progress++,
1916 splice_image->rows);
1917 if (proceed == MagickFalse)
1921 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1922 #pragma omp parallel for schedule(static,4) shared(progress,status) \
1923 magick_threads(image,splice_image,1,1)
1925 for (y=(ssize_t) (splice_geometry.y+splice_geometry.height);
1926 y < (ssize_t) splice_image->rows; y++)
1928 register const Quantum
1937 if (status == MagickFalse)
1939 p=GetCacheViewVirtualPixels(image_view,0,y-(ssize_t) splice_geometry.height,
1940 image->columns,1,exception);
1941 if ((y < 0) || (y >= (ssize_t) splice_image->rows))
1943 q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1,
1945 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1950 for (x=0; x < splice_geometry.x; x++)
1955 if (GetPixelReadMask(image,q) == 0)
1957 SetPixelBackgoundColor(splice_image,q);
1958 p+=GetPixelChannels(image);
1959 q+=GetPixelChannels(splice_image);
1962 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1964 PixelChannel channel=GetPixelChannelChannel(image,i);
1965 PixelTrait traits=GetPixelChannelTraits(image,channel);
1966 PixelTrait splice_traits=GetPixelChannelTraits(splice_image,channel);
1967 if ((traits == UndefinedPixelTrait) ||
1968 (splice_traits == UndefinedPixelTrait))
1970 SetPixelChannel(splice_image,channel,p[i],q);
1972 SetPixelRed(splice_image,GetPixelRed(image,p),q);
1973 SetPixelGreen(splice_image,GetPixelGreen(image,p),q);
1974 SetPixelBlue(splice_image,GetPixelBlue(image,p),q);
1975 SetPixelAlpha(splice_image,GetPixelAlpha(image,p),q);
1976 p+=GetPixelChannels(image);
1977 q+=GetPixelChannels(splice_image);
1979 for ( ; x < (ssize_t) (splice_geometry.x+splice_geometry.width); x++)
1980 q+=GetPixelChannels(splice_image);
1981 for ( ; x < (ssize_t) splice_image->columns; x++)
1986 if (GetPixelReadMask(image,q) == 0)
1988 SetPixelBackgoundColor(splice_image,q);
1989 p+=GetPixelChannels(image);
1990 q+=GetPixelChannels(splice_image);
1993 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1995 PixelChannel channel=GetPixelChannelChannel(image,i);
1996 PixelTrait traits=GetPixelChannelTraits(image,channel);
1997 PixelTrait splice_traits=GetPixelChannelTraits(splice_image,channel);
1998 if ((traits == UndefinedPixelTrait) ||
1999 (splice_traits == UndefinedPixelTrait))
2001 SetPixelChannel(splice_image,channel,p[i],q);
2003 SetPixelRed(splice_image,GetPixelRed(image,p),q);
2004 SetPixelGreen(splice_image,GetPixelGreen(image,p),q);
2005 SetPixelBlue(splice_image,GetPixelBlue(image,p),q);
2006 SetPixelAlpha(splice_image,GetPixelAlpha(image,p),q);
2007 p+=GetPixelChannels(image);
2008 q+=GetPixelChannels(splice_image);
2010 if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse)
2012 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2017 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2018 #pragma omp critical (MagickCore_TransposeImage)
2020 proceed=SetImageProgress(image,SpliceImageTag,progress++,
2021 splice_image->rows);
2022 if (proceed == MagickFalse)
2026 splice_view=DestroyCacheView(splice_view);
2027 image_view=DestroyCacheView(image_view);
2028 if (status == MagickFalse)
2029 splice_image=DestroyImage(splice_image);
2030 return(splice_image);
2034 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2038 % T r a n s f o r m I m a g e %
2042 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2044 % TransformImage() is a convenience method that behaves like ResizeImage() or
2045 % CropImage() but accepts scaling and/or cropping information as a region
2046 % geometry specification. If the operation fails, the original image handle
2049 % This should only be used for single images.
2051 % This function destroys what it assumes to be a single image list.
2052 % If the input image is part of a larger list, all other images in that list
2053 % will be simply 'lost', not destroyed.
2055 % Also if the crop generates a list of images only the first image is resized.
2056 % And finally if the crop succeeds and the resize failed, you will get a
2057 % cropped image, as well as a 'false' or 'failed' report.
2059 % This function and should probably be deprecated in favor of direct calls
2060 % to CropImageToTiles() or ResizeImage(), as appropriate.
2062 % The format of the TransformImage method is:
2064 % MagickBooleanType TransformImage(Image **image,const char *crop_geometry,
2065 % const char *image_geometry,ExceptionInfo *exception)
2067 % A description of each parameter follows:
2069 % o image: the image The transformed image is returned as this parameter.
2071 % o crop_geometry: A crop geometry string. This geometry defines a
2072 % subregion of the image to crop.
2074 % o image_geometry: An image geometry string. This geometry defines the
2075 % final size of the image.
2077 % o exception: return any errors or warnings in this structure.
2080 MagickExport MagickBooleanType TransformImage(Image **image,
2081 const char *crop_geometry,const char *image_geometry,ExceptionInfo *exception)
2093 assert(image != (Image **) NULL);
2094 assert((*image)->signature == MagickSignature);
2095 if ((*image)->debug != MagickFalse)
2096 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
2097 transform_image=(*image);
2098 if (crop_geometry != (const char *) NULL)
2104 Crop image to a user specified size.
2106 crop_image=CropImageToTiles(*image,crop_geometry,exception);
2107 if (crop_image == (Image *) NULL)
2108 transform_image=CloneImage(*image,0,0,MagickTrue,exception);
2111 transform_image=DestroyImage(transform_image);
2112 transform_image=GetFirstImageInList(crop_image);
2114 *image=transform_image;
2116 if (image_geometry == (const char *) NULL)
2120 Scale image to a user specified size.
2122 flags=ParseRegionGeometry(transform_image,image_geometry,&geometry,exception);
2124 if ((transform_image->columns == geometry.width) &&
2125 (transform_image->rows == geometry.height))
2127 resize_image=ResizeImage(transform_image,geometry.width,geometry.height,
2128 transform_image->filter,exception);
2129 if (resize_image == (Image *) NULL)
2130 return(MagickFalse);
2131 transform_image=DestroyImage(transform_image);
2132 transform_image=resize_image;
2133 *image=transform_image;
2138 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2142 % T r a n s f o r m I m a g e s %
2146 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2148 % TransformImages() calls TransformImage() on each image of a sequence.
2150 % The format of the TransformImage method is:
2152 % MagickBooleanType TransformImages(Image **image,
2153 % const char *crop_geometry,const char *image_geometry,
2154 % ExceptionInfo *exception)
2156 % A description of each parameter follows:
2158 % o image: the image The transformed image is returned as this parameter.
2160 % o crop_geometry: A crop geometry string. This geometry defines a
2161 % subregion of the image to crop.
2163 % o image_geometry: An image geometry string. This geometry defines the
2164 % final size of the image.
2166 % o exception: return any errors or warnings in this structure.
2169 MagickExport MagickBooleanType TransformImages(Image **images,
2170 const char *crop_geometry,const char *image_geometry,ExceptionInfo *exception)
2183 assert(images != (Image **) NULL);
2184 assert((*images)->signature == MagickSignature);
2185 if ((*images)->debug != MagickFalse)
2186 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2187 (*images)->filename);
2188 image_list=ImageListToArray(*images,exception);
2189 if (image_list == (Image **) NULL)
2190 return(MagickFalse);
2192 transform_images=NewImageList();
2193 for (i=0; image_list[i] != (Image *) NULL; i++)
2195 image=image_list[i];
2196 status&=TransformImage(&image,crop_geometry,image_geometry,exception);
2197 AppendImageToList(&transform_images,image);
2199 *images=transform_images;
2200 image_list=(Image **) RelinquishMagickMemory(image_list);
2201 return(status != 0 ? MagickTrue : MagickFalse);
2205 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2209 % T r a n s p o s e I m a g e %
2213 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2215 % TransposeImage() creates a horizontal mirror image by reflecting the pixels
2216 % around the central y-axis while rotating them by 90 degrees.
2218 % The format of the TransposeImage method is:
2220 % Image *TransposeImage(const Image *image,ExceptionInfo *exception)
2222 % A description of each parameter follows:
2224 % o image: the image.
2226 % o exception: return any errors or warnings in this structure.
2229 MagickExport Image *TransposeImage(const Image *image,ExceptionInfo *exception)
2231 #define TransposeImageTag "Transpose/Image"
2252 assert(image != (const Image *) NULL);
2253 assert(image->signature == MagickSignature);
2254 if (image->debug != MagickFalse)
2255 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2256 assert(exception != (ExceptionInfo *) NULL);
2257 assert(exception->signature == MagickSignature);
2258 transpose_image=CloneImage(image,image->rows,image->columns,MagickTrue,
2260 if (transpose_image == (Image *) NULL)
2261 return((Image *) NULL);
2267 image_view=AcquireVirtualCacheView(image,exception);
2268 transpose_view=AcquireAuthenticCacheView(transpose_image,exception);
2269 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2270 #pragma omp parallel for schedule(static,4) shared(progress,status) \
2271 magick_threads(image,transpose_image,image->rows,1)
2273 for (y=0; y < (ssize_t) image->rows; y++)
2275 register const Quantum
2284 if (status == MagickFalse)
2286 p=GetCacheViewVirtualPixels(image_view,0,(ssize_t) image->rows-y-1,
2287 image->columns,1,exception);
2288 q=QueueCacheViewAuthenticPixels(transpose_view,(ssize_t) (image->rows-y-1),
2289 0,1,transpose_image->rows,exception);
2290 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2295 for (x=0; x < (ssize_t) image->columns; x++)
2300 if (GetPixelReadMask(image,q) == 0)
2302 SetPixelBackgoundColor(transpose_image,q);
2303 p+=GetPixelChannels(image);
2304 q+=GetPixelChannels(transpose_image);
2307 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2309 PixelChannel channel=GetPixelChannelChannel(image,i);
2310 PixelTrait traits=GetPixelChannelTraits(image,channel);
2311 PixelTrait transpose_traits=GetPixelChannelTraits(transpose_image,
2313 if ((traits == UndefinedPixelTrait) ||
2314 (transpose_traits == UndefinedPixelTrait))
2316 SetPixelChannel(transpose_image,channel,p[i],q);
2318 p+=GetPixelChannels(image);
2319 q+=GetPixelChannels(transpose_image);
2321 if (SyncCacheViewAuthenticPixels(transpose_view,exception) == MagickFalse)
2323 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2328 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2329 #pragma omp critical (MagickCore_TransposeImage)
2331 proceed=SetImageProgress(image,TransposeImageTag,progress++,
2333 if (proceed == MagickFalse)
2337 transpose_view=DestroyCacheView(transpose_view);
2338 image_view=DestroyCacheView(image_view);
2339 transpose_image->type=image->type;
2340 page=transpose_image->page;
2341 Swap(page.width,page.height);
2342 Swap(page.x,page.y);
2343 transpose_image->page=page;
2344 if (status == MagickFalse)
2345 transpose_image=DestroyImage(transpose_image);
2346 return(transpose_image);
2350 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2354 % T r a n s v e r s e I m a g e %
2358 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2360 % TransverseImage() creates a vertical mirror image by reflecting the pixels
2361 % around the central x-axis while rotating them by 270 degrees.
2363 % The format of the TransverseImage method is:
2365 % Image *TransverseImage(const Image *image,ExceptionInfo *exception)
2367 % A description of each parameter follows:
2369 % o image: the image.
2371 % o exception: return any errors or warnings in this structure.
2374 MagickExport Image *TransverseImage(const Image *image,ExceptionInfo *exception)
2376 #define TransverseImageTag "Transverse/Image"
2397 assert(image != (const Image *) NULL);
2398 assert(image->signature == MagickSignature);
2399 if (image->debug != MagickFalse)
2400 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2401 assert(exception != (ExceptionInfo *) NULL);
2402 assert(exception->signature == MagickSignature);
2403 transverse_image=CloneImage(image,image->rows,image->columns,MagickTrue,
2405 if (transverse_image == (Image *) NULL)
2406 return((Image *) NULL);
2412 image_view=AcquireVirtualCacheView(image,exception);
2413 transverse_view=AcquireAuthenticCacheView(transverse_image,exception);
2414 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2415 #pragma omp parallel for schedule(static,4) shared(progress,status) \
2416 magick_threads(image,transverse_image,image->rows,1)
2418 for (y=0; y < (ssize_t) image->rows; y++)
2423 register const Quantum
2432 if (status == MagickFalse)
2434 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2435 q=QueueCacheViewAuthenticPixels(transverse_view,(ssize_t) (image->rows-y-1),
2436 0,1,transverse_image->rows,exception);
2437 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2442 q+=GetPixelChannels(transverse_image)*image->columns;
2443 for (x=0; x < (ssize_t) image->columns; x++)
2448 q-=GetPixelChannels(transverse_image);
2449 if (GetPixelReadMask(image,p) == 0)
2451 p+=GetPixelChannels(image);
2454 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2456 PixelChannel channel=GetPixelChannelChannel(image,i);
2457 PixelTrait traits=GetPixelChannelTraits(image,channel);
2458 PixelTrait transverse_traits=GetPixelChannelTraits(transverse_image,
2460 if ((traits == UndefinedPixelTrait) ||
2461 (transverse_traits == UndefinedPixelTrait))
2463 SetPixelChannel(transverse_image,channel,p[i],q);
2465 p+=GetPixelChannels(image);
2467 sync=SyncCacheViewAuthenticPixels(transverse_view,exception);
2468 if (sync == MagickFalse)
2470 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2475 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2476 #pragma omp critical (MagickCore_TransverseImage)
2478 proceed=SetImageProgress(image,TransverseImageTag,progress++,
2480 if (proceed == MagickFalse)
2484 transverse_view=DestroyCacheView(transverse_view);
2485 image_view=DestroyCacheView(image_view);
2486 transverse_image->type=image->type;
2487 page=transverse_image->page;
2488 Swap(page.width,page.height);
2489 Swap(page.x,page.y);
2490 if (page.width != 0)
2491 page.x=(ssize_t) (page.width-transverse_image->columns-page.x);
2492 if (page.height != 0)
2493 page.y=(ssize_t) (page.height-transverse_image->rows-page.y);
2494 transverse_image->page=page;
2495 if (status == MagickFalse)
2496 transverse_image=DestroyImage(transverse_image);
2497 return(transverse_image);
2501 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2505 % T r i m I m a g e %
2509 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2511 % TrimImage() trims pixels from the image edges. It allocates the memory
2512 % necessary for the new Image structure and returns a pointer to the new
2515 % The format of the TrimImage method is:
2517 % Image *TrimImage(const Image *image,ExceptionInfo *exception)
2519 % A description of each parameter follows:
2521 % o image: the image.
2523 % o exception: return any errors or warnings in this structure.
2526 MagickExport Image *TrimImage(const Image *image,ExceptionInfo *exception)
2531 assert(image != (const Image *) NULL);
2532 assert(image->signature == MagickSignature);
2533 if (image->debug != MagickFalse)
2534 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2535 geometry=GetImageBoundingBox(image,exception);
2536 if ((geometry.width == 0) || (geometry.height == 0))
2541 crop_image=CloneImage(image,1,1,MagickTrue,exception);
2542 if (crop_image == (Image *) NULL)
2543 return((Image *) NULL);
2544 crop_image->background_color.alpha=(Quantum) TransparentAlpha;
2545 crop_image->alpha_trait=BlendPixelTrait;
2546 (void) SetImageBackgroundColor(crop_image,exception);
2547 crop_image->page=image->page;
2548 crop_image->page.x=(-1);
2549 crop_image->page.y=(-1);
2552 geometry.x+=image->page.x;
2553 geometry.y+=image->page.y;
2554 return(CropImage(image,&geometry,exception));