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-2010 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 "magick/studio.h"
43 #include "magick/attribute.h"
44 #include "magick/cache.h"
45 #include "magick/cache-view.h"
46 #include "magick/color.h"
47 #include "magick/color-private.h"
48 #include "magick/colorspace-private.h"
49 #include "magick/composite.h"
50 #include "magick/draw.h"
51 #include "magick/effect.h"
52 #include "magick/exception.h"
53 #include "magick/exception-private.h"
54 #include "magick/geometry.h"
55 #include "magick/image.h"
56 #include "magick/memory_.h"
57 #include "magick/layer.h"
58 #include "magick/list.h"
59 #include "magick/monitor.h"
60 #include "magick/monitor-private.h"
61 #include "magick/pixel-private.h"
62 #include "magick/resource_.h"
63 #include "magick/resize.h"
64 #include "magick/statistic.h"
65 #include "magick/string_.h"
66 #include "magick/transform.h"
69 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
77 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
79 % ChopImage() removes a region of an image and collapses the image to occupy
80 % the removed portion.
82 % The format of the ChopImage method is:
84 % Image *ChopImage(const Image *image,const RectangleInfo *chop_info)
85 % ExceptionInfo *exception)
87 % A description of each parameter follows:
91 % o chop_info: Define the region of the image to chop.
93 % o exception: return any errors or warnings in this structure.
96 MagickExport Image *ChopImage(const Image *image,const RectangleInfo *chop_info,
97 ExceptionInfo *exception)
99 #define ChopImageTag "Chop/Image"
125 assert(image != (const Image *) NULL);
126 assert(image->signature == MagickSignature);
127 if (image->debug != MagickFalse)
128 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
129 assert(exception != (ExceptionInfo *) NULL);
130 assert(exception->signature == MagickSignature);
131 assert(chop_info != (RectangleInfo *) NULL);
132 if (((chop_info->x+(long) chop_info->width) < 0) ||
133 ((chop_info->y+(long) chop_info->height) < 0) ||
134 (chop_info->x > (long) image->columns) ||
135 (chop_info->y > (long) image->rows))
136 ThrowImageException(OptionWarning,"GeometryDoesNotContainImage");
138 if ((extent.x+(long) extent.width) > (long) image->columns)
139 extent.width=(unsigned long) ((long) image->columns-extent.x);
140 if ((extent.y+(long) extent.height) > (long) image->rows)
141 extent.height=(unsigned long) ((long) image->rows-extent.y);
144 extent.width-=(unsigned long) (-extent.x);
149 extent.height-=(unsigned long) (-extent.y);
152 chop_image=CloneImage(image,image->columns-extent.width,image->rows-
153 extent.height,MagickTrue,exception);
154 if (chop_image == (Image *) NULL)
155 return((Image *) NULL);
162 image_view=AcquireCacheView(image);
163 chop_view=AcquireCacheView(chop_image);
164 for (y=0; y < (long) extent.y; y++)
166 register const PixelPacket
170 *restrict chop_indexes,
179 if (status == MagickFalse)
181 p=GetCacheViewVirtualPixels(image_view,0,i++,image->columns,1,exception);
182 q=QueueCacheViewAuthenticPixels(chop_view,0,j++,chop_image->columns,1,
184 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
189 indexes=GetCacheViewAuthenticIndexQueue(image_view);
190 chop_indexes=GetCacheViewAuthenticIndexQueue(chop_view);
191 for (x=0; x < (long) image->columns; x++)
193 if ((x < extent.x) || (x >= (long) (extent.x+extent.width)))
196 if (indexes != (IndexPacket *) NULL)
198 if (chop_indexes != (IndexPacket *) NULL)
199 *chop_indexes++=indexes[x];
205 if (SyncCacheViewAuthenticPixels(chop_view,exception) == MagickFalse)
207 proceed=SetImageProgress(image,ChopImageTag,y,chop_image->rows);
208 if (proceed == MagickFalse)
215 for (y=0; y < (long) (image->rows-(extent.y+extent.height)); y++)
217 register const PixelPacket
221 *restrict chop_indexes,
230 if (status == MagickFalse)
232 p=GetCacheViewVirtualPixels(image_view,0,i++,image->columns,1,exception);
233 q=QueueCacheViewAuthenticPixels(chop_view,0,j++,chop_image->columns,1,
235 if ((p == (PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
240 indexes=GetCacheViewAuthenticIndexQueue(image_view);
241 chop_indexes=GetCacheViewAuthenticIndexQueue(chop_view);
242 for (x=0; x < (long) image->columns; x++)
244 if ((x < extent.x) || (x >= (long) (extent.x+extent.width)))
247 if (indexes != (IndexPacket *) NULL)
249 if (chop_indexes != (IndexPacket *) NULL)
250 *chop_indexes++=indexes[x];
256 if (SyncCacheViewAuthenticPixels(chop_view,exception) == MagickFalse)
258 proceed=SetImageProgress(image,ChopImageTag,y,chop_image->rows);
259 if (proceed == MagickFalse)
262 chop_view=DestroyCacheView(chop_view);
263 image_view=DestroyCacheView(image_view);
264 chop_image->type=image->type;
269 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
273 + C o n s o l i d a t e C M Y K I m a g e %
277 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
279 % ConsolidateCMYKImage() consolidates separate C, M, Y, and K planes into a
282 % The format of the ConsolidateCMYKImage method is:
284 % Image *ConsolidateCMYKImage(const Image *image,ExceptionInfo *exception)
286 % A description of each parameter follows:
288 % o image: the image sequence.
290 % o exception: return any errors or warnings in this structure.
293 MagickExport Image *ConsolidateCMYKImages(const Image *images,
294 ExceptionInfo *exception)
307 Consolidate separate C, M, Y, and K planes into a single image.
309 assert(images != (Image *) NULL);
310 assert(images->signature == MagickSignature);
311 if (images->debug != MagickFalse)
312 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
313 assert(exception != (ExceptionInfo *) NULL);
314 assert(exception->signature == MagickSignature);
315 cmyk_images=NewImageList();
316 for (i=0; i < (long) GetImageListLength(images); i+=4)
318 cmyk_image=CloneImage(images,images->columns,images->rows,MagickTrue,
320 if (cmyk_image == (Image *) NULL)
322 if (SetImageStorageClass(cmyk_image,DirectClass) == MagickFalse)
324 (void) SetImageColorspace(cmyk_image,CMYKColorspace);
325 for (y=0; y < (long) images->rows; y++)
327 register const PixelPacket
336 p=GetVirtualPixels(images,0,y,images->columns,1,exception);
337 q=QueueAuthenticPixels(cmyk_image,0,y,cmyk_image->columns,1,exception);
338 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
340 for (x=0; x < (long) images->columns; x++)
342 q->red=(Quantum) (QuantumRange-PixelIntensityToQuantum(p));
346 if (SyncAuthenticPixels(cmyk_image,exception) == MagickFalse)
349 images=GetNextImageInList(images);
350 if (images == (Image *) NULL)
352 for (y=0; y < (long) images->rows; y++)
354 register const PixelPacket
363 p=GetVirtualPixels(images,0,y,images->columns,1,exception);
364 q=GetAuthenticPixels(cmyk_image,0,y,cmyk_image->columns,1,exception);
365 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
367 for (x=0; x < (long) images->columns; x++)
369 q->green=(Quantum) (QuantumRange-PixelIntensityToQuantum(p));
373 if (SyncAuthenticPixels(cmyk_image,exception) == MagickFalse)
376 images=GetNextImageInList(images);
377 if (images == (Image *) NULL)
379 for (y=0; y < (long) images->rows; y++)
381 register const PixelPacket
390 p=GetVirtualPixels(images,0,y,images->columns,1,exception);
391 q=GetAuthenticPixels(cmyk_image,0,y,cmyk_image->columns,1,exception);
392 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
394 for (x=0; x < (long) images->columns; x++)
396 q->blue=(Quantum) (QuantumRange-PixelIntensityToQuantum(p));
400 if (SyncAuthenticPixels(cmyk_image,exception) == MagickFalse)
403 images=GetNextImageInList(images);
404 if (images == (Image *) NULL)
406 for (y=0; y < (long) images->rows; y++)
408 register const PixelPacket
420 p=GetVirtualPixels(images,0,y,images->columns,1,exception);
421 q=GetAuthenticPixels(cmyk_image,0,y,cmyk_image->columns,1,exception);
422 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
424 indexes=GetAuthenticIndexQueue(cmyk_image);
425 for (x=0; x < (long) images->columns; x++)
427 indexes[x]=(IndexPacket) (QuantumRange-PixelIntensityToQuantum(p));
430 if (SyncAuthenticPixels(cmyk_image,exception) == MagickFalse)
433 AppendImageToList(&cmyk_images,cmyk_image);
434 images=GetNextImageInList(images);
435 if (images == (Image *) NULL)
442 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
446 % C r o p I m a g e %
450 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
452 % CropImage() extracts a region of the image starting at the offset defined
455 % The format of the CropImage method is:
457 % Image *CropImage(const Image *image,const RectangleInfo *geometry,
458 % ExceptionInfo *exception)
460 % A description of each parameter follows:
462 % o image: the image.
464 % o geometry: Define the region of the image to crop with members
465 % x, y, width, and height.
467 % o exception: return any errors or warnings in this structure.
470 MagickExport Image *CropImage(const Image *image,const RectangleInfo *geometry,
471 ExceptionInfo *exception)
473 #define CropImageTag "Crop/Image"
496 assert(image != (const Image *) NULL);
497 assert(image->signature == MagickSignature);
498 if (image->debug != MagickFalse)
499 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
500 assert(geometry != (const RectangleInfo *) NULL);
501 assert(exception != (ExceptionInfo *) NULL);
502 assert(exception->signature == MagickSignature);
503 bounding_box=image->page;
504 if ((bounding_box.width == 0) || (bounding_box.height == 0))
506 bounding_box.width=image->columns;
507 bounding_box.height=image->rows;
511 page.width=bounding_box.width;
512 if (page.height == 0)
513 page.height=bounding_box.height;
514 if (((bounding_box.x-page.x) >= (long) page.width) ||
515 ((bounding_box.y-page.y) >= (long) page.height) ||
516 ((page.x-bounding_box.x) > (long) image->columns) ||
517 ((page.y-bounding_box.y) > (long) image->rows))
520 Crop is not within virtual canvas, return 1 pixel transparent image.
522 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
523 "GeometryDoesNotContainImage","`%s'",image->filename);
524 crop_image=CloneImage(image,1,1,MagickTrue,exception);
525 if (crop_image == (Image *) NULL)
526 return((Image *) NULL);
527 crop_image->background_color.opacity=(Quantum) TransparentOpacity;
528 (void) SetImageBackgroundColor(crop_image);
529 crop_image->page=bounding_box;
530 crop_image->page.x=(-1);
531 crop_image->page.y=(-1);
532 if (crop_image->dispose == BackgroundDispose)
533 crop_image->dispose=NoneDispose;
536 if ((page.x < 0) && (bounding_box.x >= 0))
538 page.width+=page.x-bounding_box.x;
543 page.width-=bounding_box.x-page.x;
544 page.x-=bounding_box.x;
548 if ((page.y < 0) && (bounding_box.y >= 0))
550 page.height+=page.y-bounding_box.y;
555 page.height-=bounding_box.y-page.y;
556 page.y-=bounding_box.y;
560 if ((unsigned long) (page.x+page.width) > image->columns)
561 page.width=image->columns-page.x;
562 if ((geometry->width != 0) && (page.width > geometry->width))
563 page.width=geometry->width;
564 if ((unsigned long) (page.y+page.height) > image->rows)
565 page.height=image->rows-page.y;
566 if ((geometry->height != 0) && (page.height > geometry->height))
567 page.height=geometry->height;
568 bounding_box.x+=page.x;
569 bounding_box.y+=page.y;
570 if ((page.width == 0) || (page.height == 0))
572 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
573 "GeometryDoesNotContainImage","`%s'",image->filename);
574 return((Image *) NULL);
577 Initialize crop image attributes.
579 crop_image=CloneImage(image,page.width,page.height,MagickTrue,exception);
580 if (crop_image == (Image *) NULL)
581 return((Image *) NULL);
582 crop_image->page.width=image->page.width;
583 crop_image->page.height=image->page.height;
584 if (((long) (bounding_box.x+bounding_box.width) > (long) image->page.width) ||
585 ((long) (bounding_box.y+bounding_box.height) > (long) image->page.height))
587 crop_image->page.width=bounding_box.width;
588 crop_image->page.height=bounding_box.height;
590 crop_image->page.x=bounding_box.x;
591 crop_image->page.y=bounding_box.y;
597 image_view=AcquireCacheView(image);
598 crop_view=AcquireCacheView(crop_image);
599 #if defined(MAGICKCORE_OPENMP_SUPPORT) && (_OPENMP > 202001)
600 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
602 for (y=0; y < (long) crop_image->rows; y++)
604 register const IndexPacket
607 register const PixelPacket
611 *restrict crop_indexes;
616 if (status == MagickFalse)
618 p=GetCacheViewVirtualPixels(image_view,page.x,page.y+y,crop_image->columns,
620 q=QueueCacheViewAuthenticPixels(crop_view,0,y,crop_image->columns,1,
622 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
627 indexes=GetCacheViewVirtualIndexQueue(image_view);
628 crop_indexes=GetCacheViewAuthenticIndexQueue(crop_view);
629 (void) CopyMagickMemory(q,p,(size_t) crop_image->columns*sizeof(*q));
630 if ((indexes != (IndexPacket *) NULL) &&
631 (crop_indexes != (IndexPacket *) NULL))
632 (void) CopyMagickMemory(crop_indexes,indexes,(size_t) crop_image->columns*
633 sizeof(*crop_indexes));
634 if (SyncCacheViewAuthenticPixels(crop_view,exception) == MagickFalse)
636 if (image->progress_monitor != (MagickProgressMonitor) NULL)
641 #if defined(MAGICKCORE_OPENMP_SUPPORT) && (_OPENMP > 202001)
642 #pragma omp critical (MagickCore_CropImage)
644 proceed=SetImageProgress(image,CropImageTag,progress++,image->rows);
645 if (proceed == MagickFalse)
649 crop_view=DestroyCacheView(crop_view);
650 image_view=DestroyCacheView(image_view);
651 crop_image->type=image->type;
652 if (status == MagickFalse)
653 crop_image=DestroyImage(crop_image);
658 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
662 % E x c e r p t I m a g e %
666 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
668 % ExcerptImage() returns a excerpt of the image as defined by the geometry.
670 % The format of the ExcerptImage method is:
672 % Image *ExcerptImage(const Image *image,const RectangleInfo *geometry,
673 % ExceptionInfo *exception)
675 % A description of each parameter follows:
677 % o image: the image.
679 % o geometry: Define the region of the image to extend with members
680 % x, y, width, and height.
682 % o exception: return any errors or warnings in this structure.
685 MagickExport Image *ExcerptImage(const Image *image,
686 const RectangleInfo *geometry,ExceptionInfo *exception)
688 #define ExcerptImageTag "Excerpt/Image"
705 Allocate excerpt image.
707 assert(image != (const Image *) NULL);
708 assert(image->signature == MagickSignature);
709 if (image->debug != MagickFalse)
710 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
711 assert(geometry != (const RectangleInfo *) NULL);
712 assert(exception != (ExceptionInfo *) NULL);
713 assert(exception->signature == MagickSignature);
714 excerpt_image=CloneImage(image,geometry->width,geometry->height,MagickTrue,
716 if (excerpt_image == (Image *) NULL)
717 return((Image *) NULL);
723 image_view=AcquireCacheView(image);
724 excerpt_view=AcquireCacheView(excerpt_image);
725 #if defined(MAGICKCORE_OPENMP_SUPPORT)
726 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
728 for (y=0; y < (long) excerpt_image->rows; y++)
730 register const PixelPacket
734 *restrict excerpt_indexes,
740 if (status == MagickFalse)
742 p=GetCacheViewVirtualPixels(image_view,geometry->x,geometry->y+y,
743 geometry->width,1,exception);
744 q=GetCacheViewAuthenticPixels(excerpt_view,0,y,excerpt_image->columns,1,
746 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
751 (void) CopyMagickMemory(q,p,(size_t) excerpt_image->columns*sizeof(*q));
752 indexes=GetCacheViewAuthenticIndexQueue(image_view);
753 if (indexes != (IndexPacket *) NULL)
755 excerpt_indexes=GetCacheViewAuthenticIndexQueue(excerpt_view);
756 if (excerpt_indexes != (IndexPacket *) NULL)
757 (void) CopyMagickMemory(excerpt_indexes,indexes,(size_t)
758 excerpt_image->columns*sizeof(*excerpt_indexes));
760 if (SyncCacheViewAuthenticPixels(excerpt_view,exception) == MagickFalse)
762 if (image->progress_monitor != (MagickProgressMonitor) NULL)
767 #if defined(MAGICKCORE_OPENMP_SUPPORT)
768 #pragma omp critical (MagickCore_ExcerptImage)
770 proceed=SetImageProgress(image,ExcerptImageTag,progress++,image->rows);
771 if (proceed == MagickFalse)
775 excerpt_view=DestroyCacheView(excerpt_view);
776 image_view=DestroyCacheView(image_view);
777 excerpt_image->type=image->type;
778 if (status == MagickFalse)
779 excerpt_image=DestroyImage(excerpt_image);
780 return(excerpt_image);
784 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
788 % E x t e n t I m a g e %
792 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
794 % ExtentImage() extends the image as defined by the geometry, gravity, and
795 % image background color. Set the (x,y) offset of the geometry to move the
796 % original image relative to the extended image.
798 % The format of the ExtentImage method is:
800 % Image *ExtentImage(const Image *image,const RectangleInfo *geometry,
801 % ExceptionInfo *exception)
803 % A description of each parameter follows:
805 % o image: the image.
807 % o geometry: Define the region of the image to extend with members
808 % x, y, width, and height.
810 % o exception: return any errors or warnings in this structure.
813 MagickExport Image *ExtentImage(const Image *image,
814 const RectangleInfo *geometry,ExceptionInfo *exception)
820 Allocate extent image.
822 assert(image != (const Image *) NULL);
823 assert(image->signature == MagickSignature);
824 if (image->debug != MagickFalse)
825 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
826 assert(geometry != (const RectangleInfo *) NULL);
827 assert(exception != (ExceptionInfo *) NULL);
828 assert(exception->signature == MagickSignature);
829 extent_image=CloneImage(image,geometry->width,geometry->height,MagickTrue,
831 if (extent_image == (Image *) NULL)
832 return((Image *) NULL);
833 if (SetImageStorageClass(extent_image,DirectClass) == MagickFalse)
835 InheritException(exception,&extent_image->exception);
836 extent_image=DestroyImage(extent_image);
837 return((Image *) NULL);
839 if (extent_image->background_color.opacity != OpaqueOpacity)
840 extent_image->matte=MagickTrue;
841 (void) SetImageBackgroundColor(extent_image);
842 (void) CompositeImage(extent_image,image->compose,image,geometry->x,
844 return(extent_image);
848 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
852 % F l i p I m a g e %
856 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
858 % FlipImage() creates a vertical mirror image by reflecting the pixels
859 % around the central x-axis.
861 % The format of the FlipImage method is:
863 % Image *FlipImage(const Image *image,ExceptionInfo *exception)
865 % A description of each parameter follows:
867 % o image: the image.
869 % o exception: return any errors or warnings in this structure.
872 MagickExport Image *FlipImage(const Image *image,ExceptionInfo *exception)
874 #define FlipImageTag "Flip/Image"
890 assert(image != (const Image *) NULL);
891 assert(image->signature == MagickSignature);
892 if (image->debug != MagickFalse)
893 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
894 assert(exception != (ExceptionInfo *) NULL);
895 assert(exception->signature == MagickSignature);
896 flip_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
897 if (flip_image == (Image *) NULL)
898 return((Image *) NULL);
904 image_view=AcquireCacheView(image);
905 flip_view=AcquireCacheView(flip_image);
906 #if defined(MAGICKCORE_OPENMP_SUPPORT) && (_OPENMP > 202001)
907 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
909 for (y=0; y < (long) flip_image->rows; y++)
911 register const IndexPacket
914 register const PixelPacket
918 *restrict flip_indexes;
923 if (status == MagickFalse)
925 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
926 q=QueueCacheViewAuthenticPixels(flip_view,0,(long) (flip_image->rows-y-1),
927 flip_image->columns,1,exception);
928 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
933 (void) CopyMagickMemory(q,p,(size_t) image->columns*sizeof(*q));
934 indexes=GetCacheViewVirtualIndexQueue(image_view);
935 if (indexes != (const IndexPacket *) NULL)
937 flip_indexes=GetCacheViewAuthenticIndexQueue(flip_view);
938 if (flip_indexes != (IndexPacket *) NULL)
939 (void) CopyMagickMemory(flip_indexes,indexes,(size_t) image->columns*
940 sizeof(*flip_indexes));
942 if (SyncCacheViewAuthenticPixels(flip_view,exception) == MagickFalse)
944 if (image->progress_monitor != (MagickProgressMonitor) NULL)
949 #if defined(MAGICKCORE_OPENMP_SUPPORT) && (_OPENMP > 202001)
950 #pragma omp critical (MagickCore_FlipImage)
952 proceed=SetImageProgress(image,FlipImageTag,progress++,image->rows);
953 if (proceed == MagickFalse)
957 flip_view=DestroyCacheView(flip_view);
958 image_view=DestroyCacheView(image_view);
959 flip_image->type=image->type;
960 if (status == MagickFalse)
961 flip_image=DestroyImage(flip_image);
966 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
970 % F l o p I m a g e %
974 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
976 % FlopImage() creates a horizontal mirror image by reflecting the pixels
977 % around the central y-axis.
979 % The format of the FlopImage method is:
981 % Image *FlopImage(const Image *image,ExceptionInfo *exception)
983 % A description of each parameter follows:
985 % o image: the image.
987 % o exception: return any errors or warnings in this structure.
990 MagickExport Image *FlopImage(const Image *image,ExceptionInfo *exception)
992 #define FlopImageTag "Flop/Image"
1008 assert(image != (const Image *) NULL);
1009 assert(image->signature == MagickSignature);
1010 if (image->debug != MagickFalse)
1011 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1012 assert(exception != (ExceptionInfo *) NULL);
1013 assert(exception->signature == MagickSignature);
1014 flop_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
1015 if (flop_image == (Image *) NULL)
1016 return((Image *) NULL);
1022 image_view=AcquireCacheView(image);
1023 flop_view=AcquireCacheView(flop_image);
1024 #if defined(MAGICKCORE_OPENMP_SUPPORT) && (_OPENMP > 202001)
1025 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
1027 for (y=0; y < (long) flop_image->rows; y++)
1029 register const IndexPacket
1032 register const PixelPacket
1035 register IndexPacket
1036 *restrict flop_indexes;
1041 register PixelPacket
1044 if (status == MagickFalse)
1046 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1047 q=QueueCacheViewAuthenticPixels(flop_view,0,y,flop_image->columns,1,
1049 if ((p == (PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
1054 q+=flop_image->columns;
1055 indexes=GetCacheViewVirtualIndexQueue(image_view);
1056 flop_indexes=GetCacheViewAuthenticIndexQueue(flop_view);
1057 for (x=0; x < (long) flop_image->columns; x++)
1060 if ((indexes != (const IndexPacket *) NULL) &&
1061 (flop_indexes != (IndexPacket *) NULL))
1062 flop_indexes[flop_image->columns-x-1]=indexes[x];
1064 if (SyncCacheViewAuthenticPixels(flop_view,exception) == MagickFalse)
1066 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1071 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1072 #pragma omp critical (MagickCore_FlopImage)
1074 proceed=SetImageProgress(image,FlopImageTag,progress++,image->rows);
1075 if (proceed == MagickFalse)
1079 flop_view=DestroyCacheView(flop_view);
1080 image_view=DestroyCacheView(image_view);
1081 flop_image->type=image->type;
1082 if (status == MagickFalse)
1083 flop_image=DestroyImage(flop_image);
1088 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1092 % R o l l I m a g e %
1096 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1098 % RollImage() offsets an image as defined by x_offset and y_offset.
1100 % The format of the RollImage method is:
1102 % Image *RollImage(const Image *image,const long x_offset,
1103 % const long y_offset,ExceptionInfo *exception)
1105 % A description of each parameter follows:
1107 % o image: the image.
1109 % o x_offset: the number of columns to roll in the horizontal direction.
1111 % o y_offset: the number of rows to roll in the vertical direction.
1113 % o exception: return any errors or warnings in this structure.
1117 static inline MagickBooleanType CopyImageRegion(Image *destination,
1118 const Image *source,const unsigned long columns,const unsigned long rows,
1119 const long sx,const long sy,const long dx,const long dy,
1120 ExceptionInfo *exception)
1133 source_view=AcquireCacheView(source);
1134 destination_view=AcquireCacheView(destination);
1135 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1136 #pragma omp parallel for schedule(dynamic,4) shared(status)
1138 for (y=0; y < (long) rows; y++)
1143 register const IndexPacket
1146 register const PixelPacket
1149 register IndexPacket
1150 *restrict destination_indexes;
1152 register PixelPacket
1158 if (status == MagickFalse)
1160 p=GetCacheViewVirtualPixels(source_view,sx,sy+y,columns,1,exception);
1161 q=GetCacheViewAuthenticPixels(destination_view,dx,dy+y,columns,1,exception);
1162 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
1167 indexes=GetCacheViewVirtualIndexQueue(source_view);
1168 (void) CopyMagickMemory(q,p,(size_t) columns*sizeof(*p));
1169 if (indexes != (IndexPacket *) NULL)
1171 destination_indexes=GetCacheViewAuthenticIndexQueue(destination_view);
1172 if (destination_indexes != (IndexPacket *) NULL)
1173 (void) CopyMagickMemory(destination_indexes,indexes,(size_t)
1174 columns*sizeof(*indexes));
1176 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
1177 if (sync == MagickFalse)
1180 destination_view=DestroyCacheView(destination_view);
1181 source_view=DestroyCacheView(source_view);
1185 MagickExport Image *RollImage(const Image *image,const long x_offset,
1186 const long y_offset,ExceptionInfo *exception)
1188 #define RollImageTag "Roll/Image"
1200 Initialize roll image attributes.
1202 assert(image != (const Image *) NULL);
1203 assert(image->signature == MagickSignature);
1204 if (image->debug != MagickFalse)
1205 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1206 assert(exception != (ExceptionInfo *) NULL);
1207 assert(exception->signature == MagickSignature);
1208 roll_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
1209 if (roll_image == (Image *) NULL)
1210 return((Image *) NULL);
1213 while (offset.x < 0)
1214 offset.x+=image->columns;
1215 while (offset.x >= (long) image->columns)
1216 offset.x-=image->columns;
1217 while (offset.y < 0)
1218 offset.y+=image->rows;
1219 while (offset.y >= (long) image->rows)
1220 offset.y-=image->rows;
1224 status=CopyImageRegion(roll_image,image,(unsigned long) offset.x,
1225 (unsigned long) offset.y,(long) image->columns-offset.x,(long) image->rows-
1226 offset.y,0,0,exception);
1227 (void) SetImageProgress(image,RollImageTag,0,3);
1228 status|=CopyImageRegion(roll_image,image,image->columns-offset.x,
1229 (unsigned long) offset.y,0,(long) image->rows-offset.y,offset.x,0,
1231 (void) SetImageProgress(image,RollImageTag,1,3);
1232 status|=CopyImageRegion(roll_image,image,(unsigned long) offset.x,image->rows-
1233 offset.y,(long) image->columns-offset.x,0,0,offset.y,exception);
1234 (void) SetImageProgress(image,RollImageTag,2,3);
1235 status|=CopyImageRegion(roll_image,image,image->columns-offset.x,image->rows-
1236 offset.y,0,0,offset.x,offset.y,exception);
1237 (void) SetImageProgress(image,RollImageTag,3,3);
1238 roll_image->type=image->type;
1239 if (status == MagickFalse)
1240 roll_image=DestroyImage(roll_image);
1245 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1249 % S h a v e I m a g e %
1253 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1255 % ShaveImage() shaves pixels from the image edges. It allocates the memory
1256 % necessary for the new Image structure and returns a pointer to the new
1259 % The format of the ShaveImage method is:
1261 % Image *ShaveImage(const Image *image,const RectangleInfo *shave_info,
1262 % ExceptionInfo *exception)
1264 % A description of each parameter follows:
1266 % o shave_image: Method ShaveImage returns a pointer to the shaved
1267 % image. A null image is returned if there is a memory shortage or
1268 % if the image width or height is zero.
1270 % o image: the image.
1272 % o shave_info: Specifies a pointer to a RectangleInfo which defines the
1273 % region of the image to crop.
1275 % o exception: return any errors or warnings in this structure.
1278 MagickExport Image *ShaveImage(const Image *image,
1279 const RectangleInfo *shave_info,ExceptionInfo *exception)
1287 assert(image != (const Image *) NULL);
1288 assert(image->signature == MagickSignature);
1289 if (image->debug != MagickFalse)
1290 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1291 if (((2*shave_info->width) >= image->columns) ||
1292 ((2*shave_info->height) >= image->rows))
1293 ThrowImageException(OptionWarning,"GeometryDoesNotContainImage");
1294 SetGeometry(image,&geometry);
1295 geometry.width-=2*shave_info->width;
1296 geometry.height-=2*shave_info->height;
1297 geometry.x=(long) shave_info->width+image->page.x;
1298 geometry.y=(long) shave_info->height+image->page.y;
1299 shave_image=CropImage(image,&geometry,exception);
1300 if (shave_image == (Image *) NULL)
1301 return((Image *) NULL);
1302 shave_image->page.width-=2*shave_info->width;
1303 shave_image->page.height-=2*shave_info->height;
1304 shave_image->page.x-=shave_info->width;
1305 shave_image->page.y-=shave_info->height;
1306 return(shave_image);
1310 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1314 % S p l i c e I m a g e %
1318 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1320 % SpliceImage() splices a solid color into the image as defined by the
1323 % The format of the SpliceImage method is:
1325 % Image *SpliceImage(const Image *image,const RectangleInfo *geometry,
1326 % ExceptionInfo *exception)
1328 % A description of each parameter follows:
1330 % o image: the image.
1332 % o geometry: Define the region of the image to splice with members
1333 % x, y, width, and height.
1335 % o exception: return any errors or warnings in this structure.
1338 MagickExport Image *SpliceImage(const Image *image,
1339 const RectangleInfo *geometry,ExceptionInfo *exception)
1341 #define SpliceImageTag "Splice/Image"
1365 Allocate splice image.
1367 assert(image != (const Image *) NULL);
1368 assert(image->signature == MagickSignature);
1369 if (image->debug != MagickFalse)
1370 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1371 assert(geometry != (const RectangleInfo *) NULL);
1372 assert(exception != (ExceptionInfo *) NULL);
1373 assert(exception->signature == MagickSignature);
1374 splice_geometry=(*geometry);
1375 splice_image=CloneImage(image,image->columns+splice_geometry.width,
1376 image->rows+splice_geometry.height,MagickTrue,exception);
1377 if (splice_image == (Image *) NULL)
1378 return((Image *) NULL);
1379 if (SetImageStorageClass(splice_image,DirectClass) == MagickFalse)
1381 InheritException(exception,&splice_image->exception);
1382 splice_image=DestroyImage(splice_image);
1383 return((Image *) NULL);
1385 (void) SetImageBackgroundColor(splice_image);
1387 Respect image geometry.
1389 switch (image->gravity)
1392 case UndefinedGravity:
1393 case NorthWestGravity:
1397 splice_geometry.x+=splice_geometry.width/2;
1400 case NorthEastGravity:
1402 splice_geometry.x+=splice_geometry.width;
1407 splice_geometry.y+=splice_geometry.width/2;
1413 splice_geometry.x+=splice_geometry.width/2;
1414 splice_geometry.y+=splice_geometry.height/2;
1419 splice_geometry.x+=splice_geometry.width;
1420 splice_geometry.y+=splice_geometry.height/2;
1423 case SouthWestGravity:
1425 splice_geometry.y+=splice_geometry.height;
1430 splice_geometry.x+=splice_geometry.width/2;
1431 splice_geometry.y+=splice_geometry.height;
1434 case SouthEastGravity:
1436 splice_geometry.x+=splice_geometry.width;
1437 splice_geometry.y+=splice_geometry.height;
1447 image_view=AcquireCacheView(image);
1448 splice_view=AcquireCacheView(splice_image);
1449 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1450 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
1452 for (y=0; y < (long) splice_geometry.y; y++)
1454 register const PixelPacket
1457 register IndexPacket
1459 *restrict splice_indexes;
1464 register PixelPacket
1467 if (status == MagickFalse)
1469 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1470 q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1,
1472 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
1477 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1478 splice_indexes=GetCacheViewAuthenticIndexQueue(splice_view);
1479 for (x=0; x < splice_geometry.x; x++)
1481 SetRedPixelComponent(q,GetRedPixelComponent(p));
1482 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
1483 SetBluePixelComponent(q,GetBluePixelComponent(p));
1484 SetOpacityPixelComponent(q,OpaqueOpacity);
1485 if (image->matte != MagickFalse)
1486 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
1487 if (image->colorspace == CMYKColorspace)
1488 splice_indexes[x]=(*indexes++);
1492 for ( ; x < (long) (splice_geometry.x+splice_geometry.width); x++)
1494 for ( ; x < (long) splice_image->columns; x++)
1496 SetRedPixelComponent(q,GetRedPixelComponent(p));
1497 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
1498 SetBluePixelComponent(q,GetBluePixelComponent(p));
1499 SetOpacityPixelComponent(q,OpaqueOpacity);
1500 if (image->matte != MagickFalse)
1501 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
1502 if (image->colorspace == CMYKColorspace)
1503 splice_indexes[x]=(*indexes++);
1507 if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse)
1509 proceed=SetImageProgress(image,SpliceImageTag,y,splice_image->rows);
1510 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1515 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1516 #pragma omp critical (MagickCore_TransposeImage)
1518 proceed=SetImageProgress(image,SpliceImageTag,progress++,
1519 splice_image->rows);
1520 if (proceed == MagickFalse)
1524 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1525 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
1527 for (y=(long) (splice_geometry.y+splice_geometry.height);
1528 y < (long) splice_image->rows; y++)
1530 register const PixelPacket
1533 register IndexPacket
1535 *restrict splice_indexes;
1540 register PixelPacket
1543 if (status == MagickFalse)
1545 p=GetCacheViewVirtualPixels(image_view,0,y-splice_geometry.height,
1546 image->columns,1,exception);
1547 q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1,
1549 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
1554 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1555 splice_indexes=GetCacheViewAuthenticIndexQueue(splice_view);
1556 for (x=0; x < splice_geometry.x; x++)
1558 SetRedPixelComponent(q,GetRedPixelComponent(p));
1559 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
1560 SetBluePixelComponent(q,GetBluePixelComponent(p));
1561 SetOpacityPixelComponent(q,OpaqueOpacity);
1562 if (image->matte != MagickFalse)
1563 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
1564 if (image->colorspace == CMYKColorspace)
1565 splice_indexes[x]=(*indexes++);
1569 for ( ; x < (long) (splice_geometry.x+splice_geometry.width); x++)
1571 for ( ; x < (long) splice_image->columns; x++)
1573 SetRedPixelComponent(q,GetRedPixelComponent(p));
1574 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
1575 SetBluePixelComponent(q,GetBluePixelComponent(p));
1576 SetOpacityPixelComponent(q,OpaqueOpacity);
1577 if (image->matte != MagickFalse)
1578 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
1579 if (image->colorspace == CMYKColorspace)
1580 splice_indexes[x]=(*indexes++);
1584 if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse)
1586 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1591 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1592 #pragma omp critical (MagickCore_TransposeImage)
1594 proceed=SetImageProgress(image,SpliceImageTag,progress++,
1595 splice_image->rows);
1596 if (proceed == MagickFalse)
1600 splice_view=DestroyCacheView(splice_view);
1601 image_view=DestroyCacheView(image_view);
1602 if (status == MagickFalse)
1603 splice_image=DestroyImage(splice_image);
1604 return(splice_image);
1608 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1612 % T r a n s f o r m I m a g e %
1616 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1618 % TransformImage() is a convenience method that behaves like ResizeImage() or
1619 % CropImage() but accepts scaling and/or cropping information as a region
1620 % geometry specification. If the operation fails, the original image handle
1623 % The format of the TransformImage method is:
1625 % MagickBooleanType TransformImage(Image **image,const char *crop_geometry,
1626 % const char *image_geometry)
1628 % A description of each parameter follows:
1630 % o image: the image The transformed image is returned as this parameter.
1632 % o crop_geometry: A crop geometry string. This geometry defines a
1633 % subregion of the image to crop.
1635 % o image_geometry: An image geometry string. This geometry defines the
1636 % final size of the image.
1639 static inline long MagickRound(MagickRealType x)
1642 Round the fraction to nearest integer.
1645 return((long) (x+0.5));
1646 return((long) (x-0.5));
1649 MagickExport MagickBooleanType TransformImage(Image **image,
1650 const char *crop_geometry,const char *image_geometry)
1671 assert(image != (Image **) NULL);
1672 assert((*image)->signature == MagickSignature);
1673 if ((*image)->debug != MagickFalse)
1674 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
1675 transform_image=(*image);
1676 if (crop_geometry != (const char *) NULL)
1685 Crop image to a user specified size.
1687 crop_image=NewImageList();
1688 flags=ParseGravityGeometry(transform_image,crop_geometry,&geometry,
1689 &(*image)->exception);
1690 if ((flags & AreaValue) != 0)
1700 Crop into NxM tiles (@ flag) - AT.
1702 if (geometry.width == 0)
1704 if (geometry.height == 0)
1706 width=transform_image->columns;
1707 height=transform_image->rows;
1708 if ((flags & AspectValue) == 0)
1710 width-=(geometry.x < 0 ? -1 : 1)*geometry.x;
1711 height-=(geometry.y < 0 ? -1 : 1)*geometry.y;
1715 width+=(geometry.x < 0 ? -1 : 1)*geometry.x;
1716 height+=(geometry.y < 0 ? -1 : 1)*geometry.y;
1718 delta.x=(double) width/geometry.width;
1719 delta.y=(double) height/geometry.height;
1720 next=NewImageList();
1721 for (offset.y=0; offset.y < (double) height; )
1723 if ((flags & AspectValue) == 0)
1725 crop.y=(long) MagickRound((MagickRealType) (offset.y-
1726 (geometry.y > 0 ? 0 : geometry.y)));
1728 crop.height=(unsigned long) MagickRound((MagickRealType)
1729 (offset.y+(geometry.y < 0 ? 0 : geometry.y)));
1733 crop.y=(long) MagickRound((MagickRealType) (offset.y-
1734 (geometry.y > 0 ? geometry.y : 0)));
1736 crop.height=(unsigned long) MagickRound((MagickRealType)
1737 (offset.y+(geometry.y < 0 ? geometry.y : 0)));
1739 crop.height-=crop.y;
1740 crop.y += transform_image->page.y;
1741 for (offset.x=0; offset.x < (double) width; )
1743 if ((flags & AspectValue) == 0)
1745 crop.x=(long) MagickRound((MagickRealType) (offset.x-
1746 (geometry.x > 0 ? 0 : geometry.x)));
1748 crop.width=(unsigned long) MagickRound((MagickRealType)
1749 (offset.x+(geometry.x < 0 ? 0 : geometry.x)));
1753 crop.x=(long) MagickRound((MagickRealType) (offset.x-
1754 (geometry.x > 0 ? geometry.x : 0)));
1756 crop.width=(unsigned long) MagickRound((MagickRealType)
1757 (offset.x+(geometry.x < 0 ? geometry.x : 0)));
1760 crop.x += transform_image->page.x;
1761 next=CropImage(transform_image,&crop,&(*image)->exception);
1762 if (next == (Image *) NULL)
1764 AppendImageToList(&crop_image,next);
1766 if (next == (Image *) NULL)
1771 if (((geometry.width == 0) && (geometry.height == 0)) ||
1772 ((flags & XValue) != 0) || ((flags & YValue) != 0))
1775 Crop a single region at +X+Y.
1777 crop_image=CropImage(transform_image,&geometry,
1778 &(*image)->exception);
1779 if ((crop_image != (Image *) NULL) && ((flags & AspectValue) != 0))
1781 crop_image->page.width=geometry.width;
1782 crop_image->page.height=geometry.height;
1783 crop_image->page.x-=geometry.x;
1784 crop_image->page.y-=geometry.y;
1788 if ((transform_image->columns > geometry.width) ||
1789 (transform_image->rows > geometry.height))
1794 MagickProgressMonitor
1804 Crop into tiles of fixed size WxH.
1806 if (transform_image->page.width == 0)
1807 transform_image->page.width=transform_image->columns;
1808 if (transform_image->page.height == 0)
1809 transform_image->page.height=transform_image->rows;
1810 width=geometry.width;
1812 width=transform_image->page.width;
1813 height=geometry.height;
1815 height=transform_image->page.height;
1816 next=NewImageList();
1820 for (y=0; y < (long) transform_image->page.height; y+=height)
1821 for (x=0; x < (long) transform_image->page.width; x+=width)
1823 for (y=0; y < (long) transform_image->page.height; y+=height)
1825 for (x=0; x < (long) transform_image->page.width; x+=width)
1827 progress_monitor=SetImageProgressMonitor(transform_image,
1828 (MagickProgressMonitor) NULL,transform_image->client_data);
1829 geometry.width=width;
1830 geometry.height=height;
1833 next=CropImage(transform_image,&geometry,&(*image)->exception);
1834 (void) SetImageProgressMonitor(transform_image,
1835 progress_monitor,transform_image->client_data);
1836 proceed=SetImageProgress(transform_image,CropImageTag,i++,
1838 if (proceed == MagickFalse)
1840 if (next == (Image *) NULL)
1842 (void) SetImageProgressMonitor(next,progress_monitor,
1844 if (crop_image == (Image *) NULL)
1848 next->previous=crop_image;
1849 crop_image->next=next;
1850 crop_image=crop_image->next;
1853 if (next == (Image *) NULL)
1855 if (proceed == MagickFalse)
1859 if (crop_image == (Image *) NULL)
1860 transform_image=CloneImage(*image,0,0,MagickTrue,&(*image)->exception);
1863 transform_image=DestroyImage(transform_image);
1864 transform_image=GetFirstImageInList(crop_image);
1866 *image=transform_image;
1868 if (image_geometry == (const char *) NULL)
1871 Scale image to a user specified size.
1873 flags=ParseRegionGeometry(transform_image,image_geometry,&geometry,
1874 &(*image)->exception);
1875 if ((transform_image->columns == geometry.width) &&
1876 (transform_image->rows == geometry.height))
1878 resize_image=ZoomImage(transform_image,geometry.width,geometry.height,
1879 &(*image)->exception);
1880 if (resize_image == (Image *) NULL)
1881 return(MagickFalse);
1882 transform_image=DestroyImage(transform_image);
1883 transform_image=resize_image;
1884 *image=transform_image;
1889 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1893 % T r a n s f o r m I m a g e s %
1896 % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1898 % TransformImages() calls TransformImage() on each image of a sequence.
1900 % The format of the TransformImage method is:
1902 % MagickBooleanType TransformImages(Image **image,
1903 % const char *crop_geometry,const char *image_geometry)
1905 % A description of each parameter follows:
1907 % o image: the image The transformed image is returned as this parameter.
1909 % o crop_geometry: A crop geometry string. This geometry defines a
1910 % subregion of the image to crop.
1912 % o image_geometry: An image geometry string. This geometry defines the
1913 % final size of the image.
1916 MagickExport MagickBooleanType TransformImages(Image **images,
1917 const char *crop_geometry,const char *image_geometry)
1930 assert(images != (Image **) NULL);
1931 assert((*images)->signature == MagickSignature);
1932 if ((*images)->debug != MagickFalse)
1933 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1934 (*images)->filename);
1935 image_list=ImageListToArray(*images,&(*images)->exception);
1936 if (image_list == (Image **) NULL)
1937 return(MagickFalse);
1939 transform_images=NewImageList();
1940 for (i=0; image_list[i] != (Image *) NULL; i++)
1942 image=image_list[i];
1943 status|=TransformImage(&image,crop_geometry,image_geometry);
1944 AppendImageToList(&transform_images,image);
1946 *images=transform_images;
1947 image_list=(Image **) RelinquishMagickMemory(image_list);
1948 return(status != 0 ? MagickTrue : MagickFalse);
1952 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1956 % T r a n s p o s e I m a g e %
1960 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1962 % TransposeImage() creates a horizontal mirror image by reflecting the pixels
1963 % around the central y-axis while rotating them by 90 degrees.
1965 % The format of the TransposeImage method is:
1967 % Image *TransposeImage(const Image *image,ExceptionInfo *exception)
1969 % A description of each parameter follows:
1971 % o image: the image.
1973 % o exception: return any errors or warnings in this structure.
1976 MagickExport Image *TransposeImage(const Image *image,ExceptionInfo *exception)
1978 #define TransposeImageTag "Transpose/Image"
1997 assert(image != (const Image *) NULL);
1998 assert(image->signature == MagickSignature);
1999 if (image->debug != MagickFalse)
2000 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2001 assert(exception != (ExceptionInfo *) NULL);
2002 assert(exception->signature == MagickSignature);
2003 transpose_image=CloneImage(image,image->rows,image->columns,MagickTrue,
2005 if (transpose_image == (Image *) NULL)
2006 return((Image *) NULL);
2012 image_view=AcquireCacheView(image);
2013 transpose_view=AcquireCacheView(transpose_image);
2014 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2015 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
2017 for (y=0; y < (long) image->rows; y++)
2019 register const PixelPacket
2022 register IndexPacket
2023 *restrict transpose_indexes,
2026 register PixelPacket
2029 if (status == MagickFalse)
2031 p=GetCacheViewVirtualPixels(image_view,0,(long) image->rows-y-1,
2032 image->columns,1,exception);
2033 q=QueueCacheViewAuthenticPixels(transpose_view,(long) (image->rows-y-1),0,
2034 1,transpose_image->rows,exception);
2035 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
2040 (void) CopyMagickMemory(q,p,(size_t) image->columns*sizeof(*q));
2041 indexes=GetCacheViewAuthenticIndexQueue(image_view);
2042 if (indexes != (IndexPacket *) NULL)
2044 transpose_indexes=GetCacheViewAuthenticIndexQueue(transpose_view);
2045 if (transpose_indexes != (IndexPacket *) NULL)
2046 (void) CopyMagickMemory(transpose_indexes,indexes,(size_t)
2047 image->columns*sizeof(*transpose_indexes));
2049 if (SyncCacheViewAuthenticPixels(transpose_view,exception) == MagickFalse)
2051 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2056 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2057 #pragma omp critical (MagickCore_TransposeImage)
2059 proceed=SetImageProgress(image,TransposeImageTag,progress++,
2061 if (proceed == MagickFalse)
2065 transpose_view=DestroyCacheView(transpose_view);
2066 image_view=DestroyCacheView(image_view);
2067 transpose_image->type=image->type;
2068 page=transpose_image->page;
2069 Swap(page.width,page.height);
2070 Swap(page.x,page.y);
2071 if (page.width != 0)
2072 page.x=(long) (page.width-transpose_image->columns-page.x);
2073 transpose_image->page=page;
2074 if (status == MagickFalse)
2075 transpose_image=DestroyImage(transpose_image);
2076 return(transpose_image);
2080 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2084 % T r a n s v e r s e I m a g e %
2088 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2090 % TransverseImage() creates a vertical mirror image by reflecting the pixels
2091 % around the central x-axis while rotating them by 270 degrees.
2093 % The format of the TransverseImage method is:
2095 % Image *TransverseImage(const Image *image,ExceptionInfo *exception)
2097 % A description of each parameter follows:
2099 % o image: the image.
2101 % o exception: return any errors or warnings in this structure.
2104 MagickExport Image *TransverseImage(const Image *image,ExceptionInfo *exception)
2106 #define TransverseImageTag "Transverse/Image"
2125 assert(image != (const Image *) NULL);
2126 assert(image->signature == MagickSignature);
2127 if (image->debug != MagickFalse)
2128 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2129 assert(exception != (ExceptionInfo *) NULL);
2130 assert(exception->signature == MagickSignature);
2131 transverse_image=CloneImage(image,image->rows,image->columns,MagickTrue,
2133 if (transverse_image == (Image *) NULL)
2134 return((Image *) NULL);
2140 image_view=AcquireCacheView(image);
2141 transverse_view=AcquireCacheView(transverse_image);
2142 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2143 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
2145 for (y=0; y < (long) image->rows; y++)
2150 register const PixelPacket
2153 register IndexPacket
2154 *restrict transverse_indexes,
2160 register PixelPacket
2163 if (status == MagickFalse)
2165 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2166 q=QueueCacheViewAuthenticPixels(transverse_view,(long) (image->rows-y-
2167 1),0,1,transverse_image->rows,exception);
2168 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
2174 for (x=0; x < (long) image->columns; x++)
2176 indexes=GetCacheViewAuthenticIndexQueue(image_view);
2177 if (indexes != (IndexPacket *) NULL)
2179 transverse_indexes=GetCacheViewAuthenticIndexQueue(transverse_view);
2180 if (transverse_indexes != (IndexPacket *) NULL)
2181 for (x=0; x < (long) image->columns; x++)
2182 transverse_indexes[image->columns-x-1]=indexes[x];
2184 sync=SyncCacheViewAuthenticPixels(transverse_view,exception);
2185 if (sync == MagickFalse)
2187 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2192 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2193 #pragma omp critical (MagickCore_TransverseImage)
2195 proceed=SetImageProgress(image,TransverseImageTag,progress++,
2197 if (proceed == MagickFalse)
2201 transverse_view=DestroyCacheView(transverse_view);
2202 image_view=DestroyCacheView(image_view);
2203 transverse_image->type=image->type;
2204 page=transverse_image->page;
2205 Swap(page.width,page.height);
2206 Swap(page.x,page.y);
2207 if (page.height != 0)
2208 page.y=(long) (page.height-transverse_image->rows-page.y);
2209 transverse_image->page=page;
2210 if (status == MagickFalse)
2211 transverse_image=DestroyImage(transverse_image);
2212 return(transverse_image);
2216 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2220 % T r i m I m a g e %
2224 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2226 % TrimImage() trims pixels from the image edges. It allocates the memory
2227 % necessary for the new Image structure and returns a pointer to the new
2230 % The format of the TrimImage method is:
2232 % Image *TrimImage(const Image *image,ExceptionInfo *exception)
2234 % A description of each parameter follows:
2236 % o image: the image.
2238 % o exception: return any errors or warnings in this structure.
2241 MagickExport Image *TrimImage(const Image *image,ExceptionInfo *exception)
2246 assert(image != (const Image *) NULL);
2247 assert(image->signature == MagickSignature);
2248 if (image->debug != MagickFalse)
2249 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2250 geometry=GetImageBoundingBox(image,exception);
2251 if ((geometry.width == 0) || (geometry.height == 0))
2256 crop_image=CloneImage(image,1,1,MagickTrue,exception);
2257 if (crop_image == (Image *) NULL)
2258 return((Image *) NULL);
2259 crop_image->background_color.opacity=(Quantum) TransparentOpacity;
2260 (void) SetImageBackgroundColor(crop_image);
2261 crop_image->page=image->page;
2262 crop_image->page.x=(-1);
2263 crop_image->page.y=(-1);
2266 geometry.x+=image->page.x;
2267 geometry.y+=image->page.y;
2268 return(CropImage(image,&geometry,exception));