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-2017 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,4) 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,4) 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,images->columns,images->rows,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=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=(Quantum) 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,4) 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 if (GetPixelWriteMask(image,p) <= (QuantumRange/2))
703 SetPixelBackgoundColor(crop_image,q);
704 p+=GetPixelChannels(image);
705 q+=GetPixelChannels(crop_image);
708 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
710 PixelChannel channel = GetPixelChannelChannel(image,i);
711 PixelTrait traits = GetPixelChannelTraits(image,channel);
712 PixelTrait crop_traits=GetPixelChannelTraits(crop_image,channel);
713 if ((traits == UndefinedPixelTrait) ||
714 (crop_traits == UndefinedPixelTrait))
716 SetPixelChannel(crop_image,channel,p[i],q);
718 p+=GetPixelChannels(image);
719 q+=GetPixelChannels(crop_image);
721 if (SyncCacheViewAuthenticPixels(crop_view,exception) == MagickFalse)
723 if (image->progress_monitor != (MagickProgressMonitor) NULL)
728 #if defined(MAGICKCORE_OPENMP_SUPPORT)
729 #pragma omp critical (MagickCore_CropImage)
731 proceed=SetImageProgress(image,CropImageTag,progress++,image->rows);
732 if (proceed == MagickFalse)
736 crop_view=DestroyCacheView(crop_view);
737 image_view=DestroyCacheView(image_view);
738 crop_image->type=image->type;
739 if (status == MagickFalse)
740 crop_image=DestroyImage(crop_image);
745 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
749 % C r o p I m a g e T o T i l e s %
753 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
755 % CropImageToTiles() crops a single image, into a possible list of tiles.
756 % This may include a single sub-region of the image. This basically applies
757 % all the normal geometry flags for Crop.
759 % Image *CropImageToTiles(const Image *image,
760 % const RectangleInfo *crop_geometry, ExceptionInfo *exception)
762 % A description of each parameter follows:
764 % o image: the image The transformed image is returned as this parameter.
766 % o crop_geometry: A crop geometry string.
768 % o exception: return any errors or warnings in this structure.
772 static inline double MagickRound(double x)
775 Round the fraction to nearest integer.
777 if ((x-floor(x)) < (ceil(x)-x))
782 MagickExport Image *CropImageToTiles(const Image *image,
783 const char *crop_geometry,ExceptionInfo *exception)
795 assert(image != (Image *) NULL);
796 assert(image->signature == MagickCoreSignature);
797 if (image->debug != MagickFalse)
798 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
799 crop_image=NewImageList();
801 flags=ParseGravityGeometry(image,crop_geometry,&geometry,exception);
802 if ((flags & AreaValue) != 0)
816 Crop into NxM tiles (@ flag).
818 width=image->columns;
820 if (geometry.width == 0)
822 if (geometry.height == 0)
824 if ((flags & AspectValue) == 0)
826 width-=(geometry.x < 0 ? -1 : 1)*geometry.x;
827 height-=(geometry.y < 0 ? -1 : 1)*geometry.y;
831 width+=(geometry.x < 0 ? -1 : 1)*geometry.x;
832 height+=(geometry.y < 0 ? -1 : 1)*geometry.y;
834 delta.x=(double) width/geometry.width;
835 delta.y=(double) height/geometry.height;
840 for (offset.y=0; offset.y < (double) height; )
842 if ((flags & AspectValue) == 0)
844 crop.y=(ssize_t) MagickRound((double) (offset.y-
845 (geometry.y > 0 ? 0 : geometry.y)));
846 offset.y+=delta.y; /* increment now to find width */
847 crop.height=(size_t) MagickRound((double) (offset.y+
848 (geometry.y < 0 ? 0 : geometry.y)));
852 crop.y=(ssize_t) MagickRound((double) (offset.y-
853 (geometry.y > 0 ? geometry.y : 0)));
854 offset.y+=delta.y; /* increment now to find width */
855 crop.height=(size_t) MagickRound((double)
856 (offset.y+(geometry.y < -1 ? geometry.y : 0)));
859 crop.y+=image->page.y;
860 for (offset.x=0; offset.x < (double) width; )
862 if ((flags & AspectValue) == 0)
864 crop.x=(ssize_t) MagickRound((double) (offset.x-
865 (geometry.x > 0 ? 0 : geometry.x)));
866 offset.x+=delta.x; /* increment now to find height */
867 crop.width=(size_t) MagickRound((double) (offset.x+
868 (geometry.x < 0 ? 0 : geometry.x)));
872 crop.x=(ssize_t) MagickRound((double) (offset.x-
873 (geometry.x > 0 ? geometry.x : 0)));
874 offset.x+=delta.x; /* increment now to find height */
875 crop.width=(size_t) MagickRound((double) (offset.x+
876 (geometry.x < 0 ? geometry.x : 0)));
879 crop.x+=image->page.x;
880 next=CropImage(image,&crop,exception);
881 if (next != (Image *) NULL)
882 AppendImageToList(&crop_image,next);
885 ClearMagickException(exception);
888 if (((geometry.width == 0) && (geometry.height == 0)) ||
889 ((flags & XValue) != 0) || ((flags & YValue) != 0))
892 Crop a single region at +X+Y.
894 crop_image=CropImage(image,&geometry,exception);
895 if ((crop_image != (Image *) NULL) && ((flags & AspectValue) != 0))
897 crop_image->page.width=geometry.width;
898 crop_image->page.height=geometry.height;
899 crop_image->page.x-=geometry.x;
900 crop_image->page.y-=geometry.y;
904 if ((image->columns > geometry.width) || (image->rows > geometry.height))
918 Crop into tiles of fixed size WxH.
922 page.width=image->columns;
923 if (page.height == 0)
924 page.height=image->rows;
925 width=geometry.width;
928 height=geometry.height;
932 for (y=0; y < (ssize_t) page.height; y+=(ssize_t) height)
934 for (x=0; x < (ssize_t) page.width; x+=(ssize_t) width)
936 geometry.width=width;
937 geometry.height=height;
940 next=CropImage(image,&geometry,exception);
941 if (next == (Image *) NULL)
943 AppendImageToList(&crop_image,next);
945 if (next == (Image *) NULL)
950 return(CloneImage(image,0,0,MagickTrue,exception));
954 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
958 % E x c e r p t I m a g e %
962 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
964 % ExcerptImage() returns a excerpt of the image as defined by the geometry.
966 % The format of the ExcerptImage method is:
968 % Image *ExcerptImage(const Image *image,const RectangleInfo *geometry,
969 % ExceptionInfo *exception)
971 % A description of each parameter follows:
973 % o image: the image.
975 % o geometry: Define the region of the image to extend with members
976 % x, y, width, and height.
978 % o exception: return any errors or warnings in this structure.
981 MagickExport Image *ExcerptImage(const Image *image,
982 const RectangleInfo *geometry,ExceptionInfo *exception)
984 #define ExcerptImageTag "Excerpt/Image"
1003 Allocate excerpt image.
1005 assert(image != (const Image *) NULL);
1006 assert(image->signature == MagickCoreSignature);
1007 if (image->debug != MagickFalse)
1008 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1009 assert(geometry != (const RectangleInfo *) NULL);
1010 assert(exception != (ExceptionInfo *) NULL);
1011 assert(exception->signature == MagickCoreSignature);
1012 excerpt_image=CloneImage(image,geometry->width,geometry->height,MagickTrue,
1014 if (excerpt_image == (Image *) NULL)
1015 return((Image *) NULL);
1021 image_view=AcquireVirtualCacheView(image,exception);
1022 excerpt_view=AcquireAuthenticCacheView(excerpt_image,exception);
1023 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1024 #pragma omp parallel for schedule(static,4) shared(progress,status) \
1025 magick_number_threads(image,excerpt_image,excerpt_image->rows,1)
1027 for (y=0; y < (ssize_t) excerpt_image->rows; y++)
1029 register const Quantum
1038 if (status == MagickFalse)
1040 p=GetCacheViewVirtualPixels(image_view,geometry->x,geometry->y+y,
1041 geometry->width,1,exception);
1042 q=GetCacheViewAuthenticPixels(excerpt_view,0,y,excerpt_image->columns,1,
1044 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1049 for (x=0; x < (ssize_t) excerpt_image->columns; x++)
1054 if (GetPixelWriteMask(image,p) <= (QuantumRange/2))
1056 SetPixelBackgoundColor(excerpt_image,q);
1057 p+=GetPixelChannels(image);
1058 q+=GetPixelChannels(excerpt_image);
1061 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1063 PixelChannel channel = GetPixelChannelChannel(image,i);
1064 PixelTrait traits = GetPixelChannelTraits(image,channel);
1065 PixelTrait excerpt_traits=GetPixelChannelTraits(excerpt_image,channel);
1066 if ((traits == UndefinedPixelTrait) ||
1067 (excerpt_traits == UndefinedPixelTrait))
1069 SetPixelChannel(excerpt_image,channel,p[i],q);
1071 p+=GetPixelChannels(image);
1072 q+=GetPixelChannels(excerpt_image);
1074 if (SyncCacheViewAuthenticPixels(excerpt_view,exception) == MagickFalse)
1076 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1081 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1082 #pragma omp critical (MagickCore_ExcerptImage)
1084 proceed=SetImageProgress(image,ExcerptImageTag,progress++,image->rows);
1085 if (proceed == MagickFalse)
1089 excerpt_view=DestroyCacheView(excerpt_view);
1090 image_view=DestroyCacheView(image_view);
1091 excerpt_image->type=image->type;
1092 if (status == MagickFalse)
1093 excerpt_image=DestroyImage(excerpt_image);
1094 return(excerpt_image);
1098 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1102 % E x t e n t I m a g e %
1106 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1108 % ExtentImage() extends the image as defined by the geometry, gravity, and
1109 % image background color. Set the (x,y) offset of the geometry to move the
1110 % original image relative to the extended image.
1112 % The format of the ExtentImage method is:
1114 % Image *ExtentImage(const Image *image,const RectangleInfo *geometry,
1115 % ExceptionInfo *exception)
1117 % A description of each parameter follows:
1119 % o image: the image.
1121 % o geometry: Define the region of the image to extend with members
1122 % x, y, width, and height.
1124 % o exception: return any errors or warnings in this structure.
1127 MagickExport Image *ExtentImage(const Image *image,
1128 const RectangleInfo *geometry,ExceptionInfo *exception)
1134 Allocate extent image.
1136 assert(image != (const Image *) NULL);
1137 assert(image->signature == MagickCoreSignature);
1138 if (image->debug != MagickFalse)
1139 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1140 assert(geometry != (const RectangleInfo *) NULL);
1141 assert(exception != (ExceptionInfo *) NULL);
1142 assert(exception->signature == MagickCoreSignature);
1143 if ((image->columns == geometry->width) &&
1144 (image->rows == geometry->height) &&
1145 (geometry->x == 0) && (geometry->y == 0))
1146 return(CloneImage(image,0,0,MagickTrue,exception));
1147 extent_image=CloneImage(image,geometry->width,geometry->height,MagickTrue,
1149 if (extent_image == (Image *) NULL)
1150 return((Image *) NULL);
1151 (void) SetImageBackgroundColor(extent_image,exception);
1152 (void) CompositeImage(extent_image,image,image->compose,MagickTrue,
1153 -geometry->x,-geometry->y,exception);
1154 return(extent_image);
1158 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1162 % F l i p I m a g e %
1166 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1168 % FlipImage() creates a vertical mirror image by reflecting the pixels
1169 % around the central x-axis.
1171 % The format of the FlipImage method is:
1173 % Image *FlipImage(const Image *image,ExceptionInfo *exception)
1175 % A description of each parameter follows:
1177 % o image: the image.
1179 % o exception: return any errors or warnings in this structure.
1182 MagickExport Image *FlipImage(const Image *image,ExceptionInfo *exception)
1184 #define FlipImageTag "Flip/Image"
1205 assert(image != (const Image *) NULL);
1206 assert(image->signature == MagickCoreSignature);
1207 if (image->debug != MagickFalse)
1208 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1209 assert(exception != (ExceptionInfo *) NULL);
1210 assert(exception->signature == MagickCoreSignature);
1211 flip_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
1212 if (flip_image == (Image *) NULL)
1213 return((Image *) NULL);
1220 image_view=AcquireVirtualCacheView(image,exception);
1221 flip_view=AcquireAuthenticCacheView(flip_image,exception);
1222 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1223 #pragma omp parallel for schedule(static,4) shared(status) \
1224 magick_number_threads(image,flip_image,flip_image->rows,1)
1226 for (y=0; y < (ssize_t) flip_image->rows; y++)
1228 register const Quantum
1237 if (status == MagickFalse)
1239 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1240 q=QueueCacheViewAuthenticPixels(flip_view,0,(ssize_t) (flip_image->rows-y-
1241 1),flip_image->columns,1,exception);
1242 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1247 for (x=0; x < (ssize_t) flip_image->columns; x++)
1252 if (GetPixelWriteMask(image,p) <= (QuantumRange/2))
1254 SetPixelBackgoundColor(flip_image,q);
1255 p+=GetPixelChannels(image);
1256 q+=GetPixelChannels(flip_image);
1259 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1261 PixelChannel channel = GetPixelChannelChannel(image,i);
1262 PixelTrait traits = GetPixelChannelTraits(image,channel);
1263 PixelTrait flip_traits=GetPixelChannelTraits(flip_image,channel);
1264 if ((traits == UndefinedPixelTrait) ||
1265 (flip_traits == UndefinedPixelTrait))
1267 SetPixelChannel(flip_image,channel,p[i],q);
1269 p+=GetPixelChannels(image);
1270 q+=GetPixelChannels(flip_image);
1272 if (SyncCacheViewAuthenticPixels(flip_view,exception) == MagickFalse)
1274 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1279 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1280 #pragma omp critical (MagickCore_FlipImage)
1282 proceed=SetImageProgress(image,FlipImageTag,progress++,image->rows);
1283 if (proceed == MagickFalse)
1287 flip_view=DestroyCacheView(flip_view);
1288 image_view=DestroyCacheView(image_view);
1289 flip_image->type=image->type;
1290 if (page.height != 0)
1291 page.y=(ssize_t) (page.height-flip_image->rows-page.y);
1292 flip_image->page=page;
1293 if (status == MagickFalse)
1294 flip_image=DestroyImage(flip_image);
1299 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1303 % F l o p I m a g e %
1307 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1309 % FlopImage() creates a horizontal mirror image by reflecting the pixels
1310 % around the central y-axis.
1312 % The format of the FlopImage method is:
1314 % Image *FlopImage(const Image *image,ExceptionInfo *exception)
1316 % A description of each parameter follows:
1318 % o image: the image.
1320 % o exception: return any errors or warnings in this structure.
1323 MagickExport Image *FlopImage(const Image *image,ExceptionInfo *exception)
1325 #define FlopImageTag "Flop/Image"
1346 assert(image != (const Image *) NULL);
1347 assert(image->signature == MagickCoreSignature);
1348 if (image->debug != MagickFalse)
1349 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1350 assert(exception != (ExceptionInfo *) NULL);
1351 assert(exception->signature == MagickCoreSignature);
1352 flop_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
1353 if (flop_image == (Image *) NULL)
1354 return((Image *) NULL);
1361 image_view=AcquireVirtualCacheView(image,exception);
1362 flop_view=AcquireAuthenticCacheView(flop_image,exception);
1363 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1364 #pragma omp parallel for schedule(static,4) shared(status) \
1365 magick_number_threads(image,flop_image,flop_image->rows,1)
1367 for (y=0; y < (ssize_t) flop_image->rows; y++)
1369 register const Quantum
1378 if (status == MagickFalse)
1380 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1381 q=QueueCacheViewAuthenticPixels(flop_view,0,y,flop_image->columns,1,
1383 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1388 q+=GetPixelChannels(flop_image)*flop_image->columns;
1389 for (x=0; x < (ssize_t) flop_image->columns; x++)
1394 q-=GetPixelChannels(flop_image);
1395 if (GetPixelWriteMask(image,p) <= (QuantumRange/2))
1397 p+=GetPixelChannels(image);
1400 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1402 PixelChannel channel = GetPixelChannelChannel(image,i);
1403 PixelTrait traits = GetPixelChannelTraits(image,channel);
1404 PixelTrait flop_traits=GetPixelChannelTraits(flop_image,channel);
1405 if ((traits == UndefinedPixelTrait) ||
1406 (flop_traits == UndefinedPixelTrait))
1408 SetPixelChannel(flop_image,channel,p[i],q);
1410 p+=GetPixelChannels(image);
1412 if (SyncCacheViewAuthenticPixels(flop_view,exception) == MagickFalse)
1414 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1419 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1420 #pragma omp critical (MagickCore_FlopImage)
1422 proceed=SetImageProgress(image,FlopImageTag,progress++,image->rows);
1423 if (proceed == MagickFalse)
1427 flop_view=DestroyCacheView(flop_view);
1428 image_view=DestroyCacheView(image_view);
1429 flop_image->type=image->type;
1430 if (page.width != 0)
1431 page.x=(ssize_t) (page.width-flop_image->columns-page.x);
1432 flop_image->page=page;
1433 if (status == MagickFalse)
1434 flop_image=DestroyImage(flop_image);
1439 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1443 % R o l l I m a g e %
1447 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1449 % RollImage() offsets an image as defined by x_offset and y_offset.
1451 % The format of the RollImage method is:
1453 % Image *RollImage(const Image *image,const ssize_t x_offset,
1454 % const ssize_t y_offset,ExceptionInfo *exception)
1456 % A description of each parameter follows:
1458 % o image: the image.
1460 % o x_offset: the number of columns to roll in the horizontal direction.
1462 % o y_offset: the number of rows to roll in the vertical direction.
1464 % o exception: return any errors or warnings in this structure.
1468 static MagickBooleanType CopyImageRegion(Image *destination,const Image *source, const size_t columns,const size_t rows,const ssize_t sx,const ssize_t sy,
1469 const ssize_t dx,const ssize_t dy,ExceptionInfo *exception)
1484 source_view=AcquireVirtualCacheView(source,exception);
1485 destination_view=AcquireAuthenticCacheView(destination,exception);
1486 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1487 #pragma omp parallel for schedule(static,4) shared(status) \
1488 magick_number_threads(source,destination,rows,1)
1490 for (y=0; y < (ssize_t) rows; y++)
1495 register const Quantum
1507 if (status == MagickFalse)
1509 p=GetCacheViewVirtualPixels(source_view,sx,sy+y,columns,1,exception);
1510 q=GetCacheViewAuthenticPixels(destination_view,dx,dy+y,columns,1,exception);
1511 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1516 for (x=0; x < (ssize_t) columns; x++)
1521 if (GetPixelWriteMask(source,p) <= (QuantumRange/2))
1523 SetPixelBackgoundColor(destination,q);
1524 p+=GetPixelChannels(source);
1525 q+=GetPixelChannels(destination);
1528 for (i=0; i < (ssize_t) GetPixelChannels(source); i++)
1530 PixelChannel channel = GetPixelChannelChannel(source,i);
1531 PixelTrait source_traits=GetPixelChannelTraits(source,channel);
1532 PixelTrait destination_traits=GetPixelChannelTraits(destination,
1534 if ((source_traits == UndefinedPixelTrait) ||
1535 (destination_traits == UndefinedPixelTrait))
1537 SetPixelChannel(destination,channel,p[i],q);
1539 p+=GetPixelChannels(source);
1540 q+=GetPixelChannels(destination);
1542 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
1543 if (sync == MagickFalse)
1546 destination_view=DestroyCacheView(destination_view);
1547 source_view=DestroyCacheView(source_view);
1551 MagickExport Image *RollImage(const Image *image,const ssize_t x_offset,
1552 const ssize_t y_offset,ExceptionInfo *exception)
1554 #define RollImageTag "Roll/Image"
1566 Initialize roll image attributes.
1568 assert(image != (const Image *) NULL);
1569 assert(image->signature == MagickCoreSignature);
1570 if (image->debug != MagickFalse)
1571 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1572 assert(exception != (ExceptionInfo *) NULL);
1573 assert(exception->signature == MagickCoreSignature);
1574 roll_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
1575 if (roll_image == (Image *) NULL)
1576 return((Image *) NULL);
1579 while (offset.x < 0)
1580 offset.x+=(ssize_t) image->columns;
1581 while (offset.x >= (ssize_t) image->columns)
1582 offset.x-=(ssize_t) image->columns;
1583 while (offset.y < 0)
1584 offset.y+=(ssize_t) image->rows;
1585 while (offset.y >= (ssize_t) image->rows)
1586 offset.y-=(ssize_t) image->rows;
1590 status=CopyImageRegion(roll_image,image,(size_t) offset.x,
1591 (size_t) offset.y,(ssize_t) image->columns-offset.x,(ssize_t) image->rows-
1592 offset.y,0,0,exception);
1593 (void) SetImageProgress(image,RollImageTag,0,3);
1594 status&=CopyImageRegion(roll_image,image,image->columns-offset.x,
1595 (size_t) offset.y,0,(ssize_t) image->rows-offset.y,offset.x,0,
1597 (void) SetImageProgress(image,RollImageTag,1,3);
1598 status&=CopyImageRegion(roll_image,image,(size_t) offset.x,image->rows-
1599 offset.y,(ssize_t) image->columns-offset.x,0,0,offset.y,exception);
1600 (void) SetImageProgress(image,RollImageTag,2,3);
1601 status&=CopyImageRegion(roll_image,image,image->columns-offset.x,image->rows-
1602 offset.y,0,0,offset.x,offset.y,exception);
1603 (void) SetImageProgress(image,RollImageTag,3,3);
1604 roll_image->type=image->type;
1605 if (status == MagickFalse)
1606 roll_image=DestroyImage(roll_image);
1611 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1615 % S h a v e I m a g e %
1619 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1621 % ShaveImage() shaves pixels from the image edges. It allocates the memory
1622 % necessary for the new Image structure and returns a pointer to the new
1625 % The format of the ShaveImage method is:
1627 % Image *ShaveImage(const Image *image,const RectangleInfo *shave_info,
1628 % ExceptionInfo *exception)
1630 % A description of each parameter follows:
1632 % o shave_image: Method ShaveImage returns a pointer to the shaved
1633 % image. A null image is returned if there is a memory shortage or
1634 % if the image width or height is zero.
1636 % o image: the image.
1638 % o shave_info: Specifies a pointer to a RectangleInfo which defines the
1639 % region of the image to crop.
1641 % o exception: return any errors or warnings in this structure.
1644 MagickExport Image *ShaveImage(const Image *image,
1645 const RectangleInfo *shave_info,ExceptionInfo *exception)
1653 assert(image != (const Image *) NULL);
1654 assert(image->signature == MagickCoreSignature);
1655 if (image->debug != MagickFalse)
1656 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1657 if (((2*shave_info->width) >= image->columns) ||
1658 ((2*shave_info->height) >= image->rows))
1659 ThrowImageException(OptionWarning,"GeometryDoesNotContainImage");
1660 SetGeometry(image,&geometry);
1661 geometry.width-=2*shave_info->width;
1662 geometry.height-=2*shave_info->height;
1663 geometry.x=(ssize_t) shave_info->width+image->page.x;
1664 geometry.y=(ssize_t) shave_info->height+image->page.y;
1665 shave_image=CropImage(image,&geometry,exception);
1666 if (shave_image == (Image *) NULL)
1667 return((Image *) NULL);
1668 shave_image->page.width-=2*shave_info->width;
1669 shave_image->page.height-=2*shave_info->height;
1670 shave_image->page.x-=(ssize_t) shave_info->width;
1671 shave_image->page.y-=(ssize_t) shave_info->height;
1672 return(shave_image);
1676 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1680 % S p l i c e I m a g e %
1684 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1686 % SpliceImage() splices a solid color into the image as defined by the
1689 % The format of the SpliceImage method is:
1691 % Image *SpliceImage(const Image *image,const RectangleInfo *geometry,
1692 % ExceptionInfo *exception)
1694 % A description of each parameter follows:
1696 % o image: the image.
1698 % o geometry: Define the region of the image to splice with members
1699 % x, y, width, and height.
1701 % o exception: return any errors or warnings in this structure.
1704 MagickExport Image *SpliceImage(const Image *image,
1705 const RectangleInfo *geometry,ExceptionInfo *exception)
1707 #define SpliceImageTag "Splice/Image"
1730 Allocate splice image.
1732 assert(image != (const Image *) NULL);
1733 assert(image->signature == MagickCoreSignature);
1734 if (image->debug != MagickFalse)
1735 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1736 assert(geometry != (const RectangleInfo *) NULL);
1737 assert(exception != (ExceptionInfo *) NULL);
1738 assert(exception->signature == MagickCoreSignature);
1739 splice_geometry=(*geometry);
1740 splice_image=CloneImage(image,image->columns+splice_geometry.width,
1741 image->rows+splice_geometry.height,MagickTrue,exception);
1742 if (splice_image == (Image *) NULL)
1743 return((Image *) NULL);
1744 if (SetImageStorageClass(splice_image,DirectClass,exception) == MagickFalse)
1746 splice_image=DestroyImage(splice_image);
1747 return((Image *) NULL);
1749 if ((IsPixelInfoGray(&splice_image->background_color) == MagickFalse) &&
1750 (IsGrayColorspace(splice_image->colorspace) != MagickFalse))
1751 (void) SetImageColorspace(splice_image,sRGBColorspace,exception);
1752 if ((splice_image->background_color.alpha_trait != UndefinedPixelTrait) &&
1753 (splice_image->alpha_trait == UndefinedPixelTrait))
1754 (void) SetImageAlpha(splice_image,OpaqueAlpha,exception);
1755 (void) SetImageBackgroundColor(splice_image,exception);
1757 Respect image geometry.
1759 switch (image->gravity)
1762 case UndefinedGravity:
1763 case NorthWestGravity:
1767 splice_geometry.x+=(ssize_t) splice_geometry.width/2;
1770 case NorthEastGravity:
1772 splice_geometry.x+=(ssize_t) splice_geometry.width;
1777 splice_geometry.y+=(ssize_t) splice_geometry.width/2;
1782 splice_geometry.x+=(ssize_t) splice_geometry.width/2;
1783 splice_geometry.y+=(ssize_t) splice_geometry.height/2;
1788 splice_geometry.x+=(ssize_t) splice_geometry.width;
1789 splice_geometry.y+=(ssize_t) splice_geometry.height/2;
1792 case SouthWestGravity:
1794 splice_geometry.y+=(ssize_t) splice_geometry.height;
1799 splice_geometry.x+=(ssize_t) splice_geometry.width/2;
1800 splice_geometry.y+=(ssize_t) splice_geometry.height;
1803 case SouthEastGravity:
1805 splice_geometry.x+=(ssize_t) splice_geometry.width;
1806 splice_geometry.y+=(ssize_t) splice_geometry.height;
1815 columns=MagickMin(splice_geometry.x,(ssize_t) splice_image->columns);
1816 image_view=AcquireVirtualCacheView(image,exception);
1817 splice_view=AcquireAuthenticCacheView(splice_image,exception);
1818 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1819 #pragma omp parallel for schedule(static,4) shared(progress,status) \
1820 magick_number_threads(image,splice_image,splice_geometry.y,1)
1822 for (y=0; y < (ssize_t) splice_geometry.y; y++)
1824 register const Quantum
1833 if (status == MagickFalse)
1835 p=GetCacheViewVirtualPixels(image_view,0,y,splice_image->columns,1,
1837 q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1,
1839 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1844 for (x=0; x < columns; x++)
1849 if (GetPixelWriteMask(image,p) <= (QuantumRange/2))
1851 SetPixelBackgoundColor(splice_image,q);
1852 p+=GetPixelChannels(image);
1853 q+=GetPixelChannels(splice_image);
1856 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1858 PixelChannel channel = GetPixelChannelChannel(image,i);
1859 PixelTrait traits = GetPixelChannelTraits(image,channel);
1860 PixelTrait splice_traits=GetPixelChannelTraits(splice_image,channel);
1861 if ((traits == UndefinedPixelTrait) ||
1862 (splice_traits == UndefinedPixelTrait))
1864 SetPixelChannel(splice_image,channel,p[i],q);
1866 SetPixelRed(splice_image,GetPixelRed(image,p),q);
1867 SetPixelGreen(splice_image,GetPixelGreen(image,p),q);
1868 SetPixelBlue(splice_image,GetPixelBlue(image,p),q);
1869 SetPixelAlpha(splice_image,GetPixelAlpha(image,p),q);
1870 p+=GetPixelChannels(image);
1871 q+=GetPixelChannels(splice_image);
1873 for ( ; x < (ssize_t) (splice_geometry.x+splice_geometry.width); x++)
1874 q+=GetPixelChannels(splice_image);
1875 for ( ; x < (ssize_t) splice_image->columns; x++)
1880 if (GetPixelWriteMask(image,p) <= (QuantumRange/2))
1882 SetPixelBackgoundColor(splice_image,q);
1883 p+=GetPixelChannels(image);
1884 q+=GetPixelChannels(splice_image);
1887 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1889 PixelChannel channel = GetPixelChannelChannel(image,i);
1890 PixelTrait traits = GetPixelChannelTraits(image,channel);
1891 PixelTrait splice_traits=GetPixelChannelTraits(splice_image,channel);
1892 if ((traits == UndefinedPixelTrait) ||
1893 (splice_traits == UndefinedPixelTrait))
1895 SetPixelChannel(splice_image,channel,p[i],q);
1897 SetPixelRed(splice_image,GetPixelRed(image,p),q);
1898 SetPixelGreen(splice_image,GetPixelGreen(image,p),q);
1899 SetPixelBlue(splice_image,GetPixelBlue(image,p),q);
1900 SetPixelAlpha(splice_image,GetPixelAlpha(image,p),q);
1901 p+=GetPixelChannels(image);
1902 q+=GetPixelChannels(splice_image);
1904 if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse)
1906 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1911 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1912 #pragma omp critical (MagickCore_TransposeImage)
1914 proceed=SetImageProgress(image,SpliceImageTag,progress++,
1915 splice_image->rows);
1916 if (proceed == MagickFalse)
1920 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1921 #pragma omp parallel for schedule(static,4) shared(progress,status) \
1922 magick_number_threads(image,splice_image,splice_image->rows,2)
1924 for (y=(ssize_t) (splice_geometry.y+splice_geometry.height);
1925 y < (ssize_t) splice_image->rows; y++)
1927 register const Quantum
1936 if (status == MagickFalse)
1938 if ((y < 0) || (y >= (ssize_t)splice_image->rows))
1940 p=GetCacheViewVirtualPixels(image_view,0,y-(ssize_t) splice_geometry.height,
1941 splice_image->columns,1,exception);
1942 q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1,
1944 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1949 for (x=0; x < columns; x++)
1954 if (GetPixelWriteMask(image,q) <= (QuantumRange/2))
1956 SetPixelBackgoundColor(splice_image,q);
1957 p+=GetPixelChannels(image);
1958 q+=GetPixelChannels(splice_image);
1961 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1963 PixelChannel channel = GetPixelChannelChannel(image,i);
1964 PixelTrait traits = GetPixelChannelTraits(image,channel);
1965 PixelTrait splice_traits=GetPixelChannelTraits(splice_image,channel);
1966 if ((traits == UndefinedPixelTrait) ||
1967 (splice_traits == UndefinedPixelTrait))
1969 SetPixelChannel(splice_image,channel,p[i],q);
1971 SetPixelRed(splice_image,GetPixelRed(image,p),q);
1972 SetPixelGreen(splice_image,GetPixelGreen(image,p),q);
1973 SetPixelBlue(splice_image,GetPixelBlue(image,p),q);
1974 SetPixelAlpha(splice_image,GetPixelAlpha(image,p),q);
1975 p+=GetPixelChannels(image);
1976 q+=GetPixelChannels(splice_image);
1978 for ( ; x < (ssize_t) (splice_geometry.x+splice_geometry.width); x++)
1979 q+=GetPixelChannels(splice_image);
1980 for ( ; x < (ssize_t) splice_image->columns; x++)
1985 if (GetPixelWriteMask(image,q) <= (QuantumRange/2))
1987 SetPixelBackgoundColor(splice_image,q);
1988 p+=GetPixelChannels(image);
1989 q+=GetPixelChannels(splice_image);
1992 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1994 PixelChannel channel = GetPixelChannelChannel(image,i);
1995 PixelTrait traits = GetPixelChannelTraits(image,channel);
1996 PixelTrait splice_traits=GetPixelChannelTraits(splice_image,channel);
1997 if ((traits == UndefinedPixelTrait) ||
1998 (splice_traits == UndefinedPixelTrait))
2000 SetPixelChannel(splice_image,channel,p[i],q);
2002 SetPixelRed(splice_image,GetPixelRed(image,p),q);
2003 SetPixelGreen(splice_image,GetPixelGreen(image,p),q);
2004 SetPixelBlue(splice_image,GetPixelBlue(image,p),q);
2005 SetPixelAlpha(splice_image,GetPixelAlpha(image,p),q);
2006 p+=GetPixelChannels(image);
2007 q+=GetPixelChannels(splice_image);
2009 if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse)
2011 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2016 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2017 #pragma omp critical (MagickCore_TransposeImage)
2019 proceed=SetImageProgress(image,SpliceImageTag,progress++,
2020 splice_image->rows);
2021 if (proceed == MagickFalse)
2025 splice_view=DestroyCacheView(splice_view);
2026 image_view=DestroyCacheView(image_view);
2027 if (status == MagickFalse)
2028 splice_image=DestroyImage(splice_image);
2029 return(splice_image);
2033 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2037 % T r a n s f o r m I m a g e %
2041 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2043 % TransformImage() is a convenience method that behaves like ResizeImage() or
2044 % CropImage() but accepts scaling and/or cropping information as a region
2045 % geometry specification. If the operation fails, the original image handle
2048 % This should only be used for single images.
2050 % This function destroys what it assumes to be a single image list.
2051 % If the input image is part of a larger list, all other images in that list
2052 % will be simply 'lost', not destroyed.
2054 % Also if the crop generates a list of images only the first image is resized.
2055 % And finally if the crop succeeds and the resize failed, you will get a
2056 % cropped image, as well as a 'false' or 'failed' report.
2058 % This function and should probably be deprecated in favor of direct calls
2059 % to CropImageToTiles() or ResizeImage(), as appropriate.
2061 % The format of the TransformImage method is:
2063 % MagickBooleanType TransformImage(Image **image,const char *crop_geometry,
2064 % const char *image_geometry,ExceptionInfo *exception)
2066 % A description of each parameter follows:
2068 % o image: the image The transformed image is returned as this parameter.
2070 % o crop_geometry: A crop geometry string. This geometry defines a
2071 % subregion of the image to crop.
2073 % o image_geometry: An image geometry string. This geometry defines the
2074 % final size of the image.
2076 % o exception: return any errors or warnings in this structure.
2079 MagickPrivate MagickBooleanType TransformImage(Image **image,
2080 const char *crop_geometry,const char *image_geometry,ExceptionInfo *exception)
2089 assert(image != (Image **) NULL);
2090 assert((*image)->signature == MagickCoreSignature);
2091 if ((*image)->debug != MagickFalse)
2092 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
2093 transform_image=(*image);
2094 if (crop_geometry != (const char *) NULL)
2100 Crop image to a user specified size.
2102 crop_image=CropImageToTiles(*image,crop_geometry,exception);
2103 if (crop_image == (Image *) NULL)
2104 transform_image=CloneImage(*image,0,0,MagickTrue,exception);
2107 transform_image=DestroyImage(transform_image);
2108 transform_image=GetFirstImageInList(crop_image);
2110 *image=transform_image;
2112 if (image_geometry == (const char *) NULL)
2115 Scale image to a user specified size.
2117 (void) ParseRegionGeometry(transform_image,image_geometry,&geometry,
2119 if ((transform_image->columns == geometry.width) &&
2120 (transform_image->rows == geometry.height))
2122 resize_image=ResizeImage(transform_image,geometry.width,geometry.height,
2123 transform_image->filter,exception);
2124 if (resize_image == (Image *) NULL)
2125 return(MagickFalse);
2126 transform_image=DestroyImage(transform_image);
2127 transform_image=resize_image;
2128 *image=transform_image;
2133 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2137 % T r a n s p o s e I m a g e %
2141 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2143 % TransposeImage() creates a horizontal mirror image by reflecting the pixels
2144 % around the central y-axis while rotating them by 90 degrees.
2146 % The format of the TransposeImage method is:
2148 % Image *TransposeImage(const Image *image,ExceptionInfo *exception)
2150 % A description of each parameter follows:
2152 % o image: the image.
2154 % o exception: return any errors or warnings in this structure.
2157 MagickExport Image *TransposeImage(const Image *image,ExceptionInfo *exception)
2159 #define TransposeImageTag "Transpose/Image"
2180 assert(image != (const Image *) NULL);
2181 assert(image->signature == MagickCoreSignature);
2182 if (image->debug != MagickFalse)
2183 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2184 assert(exception != (ExceptionInfo *) NULL);
2185 assert(exception->signature == MagickCoreSignature);
2186 transpose_image=CloneImage(image,image->rows,image->columns,MagickTrue,
2188 if (transpose_image == (Image *) NULL)
2189 return((Image *) NULL);
2195 image_view=AcquireVirtualCacheView(image,exception);
2196 transpose_view=AcquireAuthenticCacheView(transpose_image,exception);
2197 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2198 #pragma omp parallel for schedule(static,4) shared(progress,status) \
2199 magick_number_threads(image,transpose_image,image->rows,1)
2201 for (y=0; y < (ssize_t) image->rows; y++)
2203 register const Quantum
2212 if (status == MagickFalse)
2214 p=GetCacheViewVirtualPixels(image_view,0,(ssize_t) image->rows-y-1,
2215 image->columns,1,exception);
2216 q=QueueCacheViewAuthenticPixels(transpose_view,(ssize_t) (image->rows-y-1),
2217 0,1,transpose_image->rows,exception);
2218 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2223 for (x=0; x < (ssize_t) image->columns; x++)
2228 if (GetPixelWriteMask(image,q) <= (QuantumRange/2))
2230 SetPixelBackgoundColor(transpose_image,q);
2231 p+=GetPixelChannels(image);
2232 q+=GetPixelChannels(transpose_image);
2235 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2237 PixelChannel channel = GetPixelChannelChannel(image,i);
2238 PixelTrait traits = GetPixelChannelTraits(image,channel);
2239 PixelTrait transpose_traits=GetPixelChannelTraits(transpose_image,
2241 if ((traits == UndefinedPixelTrait) ||
2242 (transpose_traits == UndefinedPixelTrait))
2244 SetPixelChannel(transpose_image,channel,p[i],q);
2246 p+=GetPixelChannels(image);
2247 q+=GetPixelChannels(transpose_image);
2249 if (SyncCacheViewAuthenticPixels(transpose_view,exception) == MagickFalse)
2251 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2256 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2257 #pragma omp critical (MagickCore_TransposeImage)
2259 proceed=SetImageProgress(image,TransposeImageTag,progress++,
2261 if (proceed == MagickFalse)
2265 transpose_view=DestroyCacheView(transpose_view);
2266 image_view=DestroyCacheView(image_view);
2267 transpose_image->type=image->type;
2268 page=transpose_image->page;
2269 Swap(page.width,page.height);
2270 Swap(page.x,page.y);
2271 transpose_image->page=page;
2272 if (status == MagickFalse)
2273 transpose_image=DestroyImage(transpose_image);
2274 return(transpose_image);
2278 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2282 % T r a n s v e r s e I m a g e %
2286 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2288 % TransverseImage() creates a vertical mirror image by reflecting the pixels
2289 % around the central x-axis while rotating them by 270 degrees.
2291 % The format of the TransverseImage method is:
2293 % Image *TransverseImage(const Image *image,ExceptionInfo *exception)
2295 % A description of each parameter follows:
2297 % o image: the image.
2299 % o exception: return any errors or warnings in this structure.
2302 MagickExport Image *TransverseImage(const Image *image,ExceptionInfo *exception)
2304 #define TransverseImageTag "Transverse/Image"
2325 assert(image != (const Image *) NULL);
2326 assert(image->signature == MagickCoreSignature);
2327 if (image->debug != MagickFalse)
2328 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2329 assert(exception != (ExceptionInfo *) NULL);
2330 assert(exception->signature == MagickCoreSignature);
2331 transverse_image=CloneImage(image,image->rows,image->columns,MagickTrue,
2333 if (transverse_image == (Image *) NULL)
2334 return((Image *) NULL);
2340 image_view=AcquireVirtualCacheView(image,exception);
2341 transverse_view=AcquireAuthenticCacheView(transverse_image,exception);
2342 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2343 #pragma omp parallel for schedule(static,4) shared(progress,status) \
2344 magick_number_threads(image,transverse_image,image->rows,1)
2346 for (y=0; y < (ssize_t) image->rows; y++)
2351 register const Quantum
2360 if (status == MagickFalse)
2362 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2363 q=QueueCacheViewAuthenticPixels(transverse_view,(ssize_t) (image->rows-y-1),
2364 0,1,transverse_image->rows,exception);
2365 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2370 q+=GetPixelChannels(transverse_image)*image->columns;
2371 for (x=0; x < (ssize_t) image->columns; x++)
2376 q-=GetPixelChannels(transverse_image);
2377 if (GetPixelWriteMask(image,p) <= (QuantumRange/2))
2379 p+=GetPixelChannels(image);
2382 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2384 PixelChannel channel = GetPixelChannelChannel(image,i);
2385 PixelTrait traits = GetPixelChannelTraits(image,channel);
2386 PixelTrait transverse_traits=GetPixelChannelTraits(transverse_image,
2388 if ((traits == UndefinedPixelTrait) ||
2389 (transverse_traits == UndefinedPixelTrait))
2391 SetPixelChannel(transverse_image,channel,p[i],q);
2393 p+=GetPixelChannels(image);
2395 sync=SyncCacheViewAuthenticPixels(transverse_view,exception);
2396 if (sync == MagickFalse)
2398 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2403 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2404 #pragma omp critical (MagickCore_TransverseImage)
2406 proceed=SetImageProgress(image,TransverseImageTag,progress++,
2408 if (proceed == MagickFalse)
2412 transverse_view=DestroyCacheView(transverse_view);
2413 image_view=DestroyCacheView(image_view);
2414 transverse_image->type=image->type;
2415 page=transverse_image->page;
2416 Swap(page.width,page.height);
2417 Swap(page.x,page.y);
2418 if (page.width != 0)
2419 page.x=(ssize_t) (page.width-transverse_image->columns-page.x);
2420 if (page.height != 0)
2421 page.y=(ssize_t) (page.height-transverse_image->rows-page.y);
2422 transverse_image->page=page;
2423 if (status == MagickFalse)
2424 transverse_image=DestroyImage(transverse_image);
2425 return(transverse_image);
2429 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2433 % T r i m I m a g e %
2437 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2439 % TrimImage() trims pixels from the image edges. It allocates the memory
2440 % necessary for the new Image structure and returns a pointer to the new
2443 % The format of the TrimImage method is:
2445 % Image *TrimImage(const Image *image,ExceptionInfo *exception)
2447 % A description of each parameter follows:
2449 % o image: the image.
2451 % o exception: return any errors or warnings in this structure.
2454 MagickExport Image *TrimImage(const Image *image,ExceptionInfo *exception)
2459 assert(image != (const Image *) NULL);
2460 assert(image->signature == MagickCoreSignature);
2461 if (image->debug != MagickFalse)
2462 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2463 geometry=GetImageBoundingBox(image,exception);
2464 if ((geometry.width == 0) || (geometry.height == 0))
2469 crop_image=CloneImage(image,1,1,MagickTrue,exception);
2470 if (crop_image == (Image *) NULL)
2471 return((Image *) NULL);
2472 crop_image->background_color.alpha=(Quantum) TransparentAlpha;
2473 crop_image->alpha_trait=BlendPixelTrait;
2474 (void) SetImageBackgroundColor(crop_image,exception);
2475 crop_image->page=image->page;
2476 crop_image->page.x=(-1);
2477 crop_image->page.y=(-1);
2480 geometry.x+=image->page.x;
2481 geometry.y+=image->page.y;
2482 return(CropImage(image,&geometry,exception));