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 PixelPacket
1146 register IndexPacket
1148 *restrict destination_indexes;
1153 register PixelPacket
1159 if (status == MagickFalse)
1161 p=GetCacheViewVirtualPixels(source_view,sx,sy+y,columns,1,exception);
1162 q=GetCacheViewAuthenticPixels(destination_view,dx,dy+y,columns,1,exception);
1163 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
1168 indexes=GetCacheViewAuthenticIndexQueue(source_view);
1169 for (x=0; x < (long) columns; x++)
1171 if (indexes != (IndexPacket *) NULL)
1173 destination_indexes=GetCacheViewAuthenticIndexQueue(destination_view);
1174 for (x=0; x < (long) columns; x++)
1175 destination_indexes[x]=indexes[x];
1177 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
1178 if (sync == MagickFalse)
1181 destination_view=DestroyCacheView(destination_view);
1182 source_view=DestroyCacheView(source_view);
1186 MagickExport Image *RollImage(const Image *image,const long x_offset,
1187 const long y_offset,ExceptionInfo *exception)
1189 #define RollImageTag "Roll/Image"
1201 Initialize roll image attributes.
1203 assert(image != (const Image *) NULL);
1204 assert(image->signature == MagickSignature);
1205 if (image->debug != MagickFalse)
1206 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1207 assert(exception != (ExceptionInfo *) NULL);
1208 assert(exception->signature == MagickSignature);
1209 roll_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
1210 if (roll_image == (Image *) NULL)
1211 return((Image *) NULL);
1214 while (offset.x < 0)
1215 offset.x+=image->columns;
1216 while (offset.x >= (long) image->columns)
1217 offset.x-=image->columns;
1218 while (offset.y < 0)
1219 offset.y+=image->rows;
1220 while (offset.y >= (long) image->rows)
1221 offset.y-=image->rows;
1225 status=CopyImageRegion(roll_image,image,(unsigned long) offset.x,
1226 (unsigned long) offset.y,(long) image->columns-offset.x,(long) image->rows-
1227 offset.y,0,0,exception);
1228 (void) SetImageProgress(image,RollImageTag,0,3);
1229 status|=CopyImageRegion(roll_image,image,image->columns-offset.x,
1230 (unsigned long) offset.y,0,(long) image->rows-offset.y,offset.x,0,
1232 (void) SetImageProgress(image,RollImageTag,1,3);
1233 status|=CopyImageRegion(roll_image,image,(unsigned long) offset.x,image->rows-
1234 offset.y,(long) image->columns-offset.x,0,0,offset.y,exception);
1235 (void) SetImageProgress(image,RollImageTag,2,3);
1236 status|=CopyImageRegion(roll_image,image,image->columns-offset.x,image->rows-
1237 offset.y,0,0,offset.x,offset.y,exception);
1238 (void) SetImageProgress(image,RollImageTag,3,3);
1239 roll_image->type=image->type;
1240 if (status == MagickFalse)
1241 roll_image=DestroyImage(roll_image);
1246 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1250 % S h a v e I m a g e %
1254 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1256 % ShaveImage() shaves pixels from the image edges. It allocates the memory
1257 % necessary for the new Image structure and returns a pointer to the new
1260 % The format of the ShaveImage method is:
1262 % Image *ShaveImage(const Image *image,const RectangleInfo *shave_info,
1263 % ExceptionInfo *exception)
1265 % A description of each parameter follows:
1267 % o shave_image: Method ShaveImage returns a pointer to the shaved
1268 % image. A null image is returned if there is a memory shortage or
1269 % if the image width or height is zero.
1271 % o image: the image.
1273 % o shave_info: Specifies a pointer to a RectangleInfo which defines the
1274 % region of the image to crop.
1276 % o exception: return any errors or warnings in this structure.
1279 MagickExport Image *ShaveImage(const Image *image,
1280 const RectangleInfo *shave_info,ExceptionInfo *exception)
1288 assert(image != (const Image *) NULL);
1289 assert(image->signature == MagickSignature);
1290 if (image->debug != MagickFalse)
1291 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1292 if (((2*shave_info->width) >= image->columns) ||
1293 ((2*shave_info->height) >= image->rows))
1294 ThrowImageException(OptionWarning,"GeometryDoesNotContainImage");
1295 SetGeometry(image,&geometry);
1296 geometry.width-=2*shave_info->width;
1297 geometry.height-=2*shave_info->height;
1298 geometry.x=(long) shave_info->width+image->page.x;
1299 geometry.y=(long) shave_info->height+image->page.y;
1300 shave_image=CropImage(image,&geometry,exception);
1301 if (shave_image == (Image *) NULL)
1302 return((Image *) NULL);
1303 shave_image->page.width-=2*shave_info->width;
1304 shave_image->page.height-=2*shave_info->height;
1305 shave_image->page.x-=shave_info->width;
1306 shave_image->page.y-=shave_info->height;
1307 return(shave_image);
1311 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1315 % S p l i c e I m a g e %
1319 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1321 % SpliceImage() splices a solid color into the image as defined by the
1324 % The format of the SpliceImage method is:
1326 % Image *SpliceImage(const Image *image,const RectangleInfo *geometry,
1327 % ExceptionInfo *exception)
1329 % A description of each parameter follows:
1331 % o image: the image.
1333 % o geometry: Define the region of the image to splice with members
1334 % x, y, width, and height.
1336 % o exception: return any errors or warnings in this structure.
1339 MagickExport Image *SpliceImage(const Image *image,
1340 const RectangleInfo *geometry,ExceptionInfo *exception)
1342 #define SpliceImageTag "Splice/Image"
1366 Allocate splice image.
1368 assert(image != (const Image *) NULL);
1369 assert(image->signature == MagickSignature);
1370 if (image->debug != MagickFalse)
1371 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1372 assert(geometry != (const RectangleInfo *) NULL);
1373 assert(exception != (ExceptionInfo *) NULL);
1374 assert(exception->signature == MagickSignature);
1375 splice_geometry=(*geometry);
1376 splice_image=CloneImage(image,image->columns+splice_geometry.width,
1377 image->rows+splice_geometry.height,MagickTrue,exception);
1378 if (splice_image == (Image *) NULL)
1379 return((Image *) NULL);
1380 if (SetImageStorageClass(splice_image,DirectClass) == MagickFalse)
1382 InheritException(exception,&splice_image->exception);
1383 splice_image=DestroyImage(splice_image);
1384 return((Image *) NULL);
1386 (void) SetImageBackgroundColor(splice_image);
1388 Respect image geometry.
1390 switch (image->gravity)
1393 case UndefinedGravity:
1394 case NorthWestGravity:
1398 splice_geometry.x+=splice_geometry.width/2;
1401 case NorthEastGravity:
1403 splice_geometry.x+=splice_geometry.width;
1408 splice_geometry.y+=splice_geometry.width/2;
1414 splice_geometry.x+=splice_geometry.width/2;
1415 splice_geometry.y+=splice_geometry.height/2;
1420 splice_geometry.x+=splice_geometry.width;
1421 splice_geometry.y+=splice_geometry.height/2;
1424 case SouthWestGravity:
1426 splice_geometry.y+=splice_geometry.height;
1431 splice_geometry.x+=splice_geometry.width/2;
1432 splice_geometry.y+=splice_geometry.height;
1435 case SouthEastGravity:
1437 splice_geometry.x+=splice_geometry.width;
1438 splice_geometry.y+=splice_geometry.height;
1448 image_view=AcquireCacheView(image);
1449 splice_view=AcquireCacheView(splice_image);
1450 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1451 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
1453 for (y=0; y < (long) splice_geometry.y; y++)
1455 register const PixelPacket
1458 register IndexPacket
1460 *restrict splice_indexes;
1465 register PixelPacket
1468 if (status == MagickFalse)
1470 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1471 q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1,
1473 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
1478 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1479 splice_indexes=GetCacheViewAuthenticIndexQueue(splice_view);
1480 for (x=0; x < splice_geometry.x; x++)
1482 SetRedPixelComponent(q,GetRedPixelComponent(p));
1483 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
1484 SetBluePixelComponent(q,GetBluePixelComponent(p));
1485 SetOpacityPixelComponent(q,OpaqueOpacity);
1486 if (image->matte != MagickFalse)
1487 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
1488 if (image->colorspace == CMYKColorspace)
1489 splice_indexes[x]=(*indexes++);
1493 for ( ; x < (long) (splice_geometry.x+splice_geometry.width); x++)
1495 for ( ; x < (long) splice_image->columns; x++)
1497 SetRedPixelComponent(q,GetRedPixelComponent(p));
1498 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
1499 SetBluePixelComponent(q,GetBluePixelComponent(p));
1500 SetOpacityPixelComponent(q,OpaqueOpacity);
1501 if (image->matte != MagickFalse)
1502 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
1503 if (image->colorspace == CMYKColorspace)
1504 splice_indexes[x]=(*indexes++);
1508 if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse)
1510 proceed=SetImageProgress(image,SpliceImageTag,y,splice_image->rows);
1511 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1516 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1517 #pragma omp critical (MagickCore_TransposeImage)
1519 proceed=SetImageProgress(image,SpliceImageTag,progress++,
1520 splice_image->rows);
1521 if (proceed == MagickFalse)
1525 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1526 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
1528 for (y=(long) (splice_geometry.y+splice_geometry.height);
1529 y < (long) splice_image->rows; y++)
1531 register const PixelPacket
1534 register IndexPacket
1536 *restrict splice_indexes;
1541 register PixelPacket
1544 if (status == MagickFalse)
1546 p=GetCacheViewVirtualPixels(image_view,0,y-splice_geometry.height,
1547 image->columns,1,exception);
1548 q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1,
1550 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
1555 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1556 splice_indexes=GetCacheViewAuthenticIndexQueue(splice_view);
1557 for (x=0; x < splice_geometry.x; x++)
1559 SetRedPixelComponent(q,GetRedPixelComponent(p));
1560 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
1561 SetBluePixelComponent(q,GetBluePixelComponent(p));
1562 SetOpacityPixelComponent(q,OpaqueOpacity);
1563 if (image->matte != MagickFalse)
1564 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
1565 if (image->colorspace == CMYKColorspace)
1566 splice_indexes[x]=(*indexes++);
1570 for ( ; x < (long) (splice_geometry.x+splice_geometry.width); x++)
1572 for ( ; x < (long) splice_image->columns; x++)
1574 SetRedPixelComponent(q,GetRedPixelComponent(p));
1575 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
1576 SetBluePixelComponent(q,GetBluePixelComponent(p));
1577 SetOpacityPixelComponent(q,OpaqueOpacity);
1578 if (image->matte != MagickFalse)
1579 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
1580 if (image->colorspace == CMYKColorspace)
1581 splice_indexes[x]=(*indexes++);
1585 if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse)
1587 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1592 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1593 #pragma omp critical (MagickCore_TransposeImage)
1595 proceed=SetImageProgress(image,SpliceImageTag,progress++,
1596 splice_image->rows);
1597 if (proceed == MagickFalse)
1601 splice_view=DestroyCacheView(splice_view);
1602 image_view=DestroyCacheView(image_view);
1603 if (status == MagickFalse)
1604 splice_image=DestroyImage(splice_image);
1605 return(splice_image);
1609 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1613 % T r a n s f o r m I m a g e %
1617 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1619 % TransformImage() is a convenience method that behaves like ResizeImage() or
1620 % CropImage() but accepts scaling and/or cropping information as a region
1621 % geometry specification. If the operation fails, the original image handle
1624 % The format of the TransformImage method is:
1626 % MagickBooleanType TransformImage(Image **image,const char *crop_geometry,
1627 % const char *image_geometry)
1629 % A description of each parameter follows:
1631 % o image: the image The transformed image is returned as this parameter.
1633 % o crop_geometry: A crop geometry string. This geometry defines a
1634 % subregion of the image to crop.
1636 % o image_geometry: An image geometry string. This geometry defines the
1637 % final size of the image.
1640 static inline long MagickRound(MagickRealType x)
1643 Round the fraction to nearest integer.
1646 return((long) (x+0.5));
1647 return((long) (x-0.5));
1650 MagickExport MagickBooleanType TransformImage(Image **image,
1651 const char *crop_geometry,const char *image_geometry)
1672 assert(image != (Image **) NULL);
1673 assert((*image)->signature == MagickSignature);
1674 if ((*image)->debug != MagickFalse)
1675 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
1676 transform_image=(*image);
1677 if (crop_geometry != (const char *) NULL)
1686 Crop image to a user specified size.
1688 crop_image=NewImageList();
1689 flags=ParseGravityGeometry(transform_image,crop_geometry,&geometry,
1690 &(*image)->exception);
1691 if ((flags & AreaValue) != 0)
1701 Crop into NxM tiles (@ flag) - AT.
1703 if (geometry.width == 0)
1705 if (geometry.height == 0)
1707 width=transform_image->columns;
1708 height=transform_image->rows;
1709 if ((flags & AspectValue) == 0)
1711 width-=(geometry.x < 0 ? -1 : 1)*geometry.x;
1712 height-=(geometry.y < 0 ? -1 : 1)*geometry.y;
1716 width+=(geometry.x < 0 ? -1 : 1)*geometry.x;
1717 height+=(geometry.y < 0 ? -1 : 1)*geometry.y;
1719 delta.x=(double) width/geometry.width;
1720 delta.y=(double) height/geometry.height;
1721 next=NewImageList();
1722 for (offset.y=0; offset.y < (double) height; )
1724 if ((flags & AspectValue) == 0)
1726 crop.y=(long) MagickRound((MagickRealType) (offset.y-
1727 (geometry.y > 0 ? 0 : geometry.y)));
1729 crop.height=(unsigned long) MagickRound((MagickRealType)
1730 (offset.y+(geometry.y < 0 ? 0 : geometry.y)));
1734 crop.y=(long) MagickRound((MagickRealType) (offset.y-
1735 (geometry.y > 0 ? geometry.y : 0)));
1737 crop.height=(unsigned long) MagickRound((MagickRealType)
1738 (offset.y+(geometry.y < 0 ? geometry.y : 0)));
1740 crop.height-=crop.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 next=CropImage(transform_image,&crop,&(*image)->exception);
1761 if (next == (Image *) NULL)
1763 AppendImageToList(&crop_image,next);
1765 if (next == (Image *) NULL)
1770 if (((geometry.width == 0) && (geometry.height == 0)) ||
1771 ((flags & XValue) != 0) || ((flags & YValue) != 0))
1774 Crop a single region at +X+Y.
1776 crop_image=CropImage(transform_image,&geometry,
1777 &(*image)->exception);
1778 if ((crop_image != (Image *) NULL) && ((flags & AspectValue) != 0))
1780 crop_image->page.width=geometry.width;
1781 crop_image->page.height=geometry.height;
1782 crop_image->page.x-=geometry.x;
1783 crop_image->page.y-=geometry.y;
1787 if ((transform_image->columns > geometry.width) ||
1788 (transform_image->rows > geometry.height))
1793 MagickProgressMonitor
1803 Crop into tiles of fixed size WxH.
1805 if (transform_image->page.width == 0)
1806 transform_image->page.width=transform_image->columns;
1807 if (transform_image->page.height == 0)
1808 transform_image->page.height=transform_image->rows;
1809 width=geometry.width;
1811 width=transform_image->page.width;
1812 height=geometry.height;
1814 height=transform_image->page.height;
1815 next=NewImageList();
1819 for (y=0; y < (long) transform_image->page.height; y+=height)
1820 for (x=0; x < (long) transform_image->page.width; x+=width)
1822 for (y=0; y < (long) transform_image->page.height; y+=height)
1824 for (x=0; x < (long) transform_image->page.width; x+=width)
1826 progress_monitor=SetImageProgressMonitor(transform_image,
1827 (MagickProgressMonitor) NULL,transform_image->client_data);
1828 geometry.width=width;
1829 geometry.height=height;
1832 next=CropImage(transform_image,&geometry,&(*image)->exception);
1833 (void) SetImageProgressMonitor(transform_image,
1834 progress_monitor,transform_image->client_data);
1835 proceed=SetImageProgress(transform_image,CropImageTag,i++,
1837 if (proceed == MagickFalse)
1839 if (next == (Image *) NULL)
1841 (void) SetImageProgressMonitor(next,progress_monitor,
1843 if (crop_image == (Image *) NULL)
1847 next->previous=crop_image;
1848 crop_image->next=next;
1849 crop_image=crop_image->next;
1852 if (next == (Image *) NULL)
1854 if (proceed == MagickFalse)
1858 if (crop_image == (Image *) NULL)
1859 transform_image=CloneImage(*image,0,0,MagickTrue,&(*image)->exception);
1862 transform_image=DestroyImage(transform_image);
1863 transform_image=GetFirstImageInList(crop_image);
1865 *image=transform_image;
1867 if (image_geometry == (const char *) NULL)
1870 Scale image to a user specified size.
1872 flags=ParseRegionGeometry(transform_image,image_geometry,&geometry,
1873 &(*image)->exception);
1874 if ((transform_image->columns == geometry.width) &&
1875 (transform_image->rows == geometry.height))
1877 resize_image=ZoomImage(transform_image,geometry.width,geometry.height,
1878 &(*image)->exception);
1879 if (resize_image == (Image *) NULL)
1880 return(MagickFalse);
1881 transform_image=DestroyImage(transform_image);
1882 transform_image=resize_image;
1883 *image=transform_image;
1888 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1892 % T r a n s f o r m I m a g e s %
1895 % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1897 % TransformImages() calls TransformImage() on each image of a sequence.
1899 % The format of the TransformImage method is:
1901 % MagickBooleanType TransformImages(Image **image,
1902 % const char *crop_geometry,const char *image_geometry)
1904 % A description of each parameter follows:
1906 % o image: the image The transformed image is returned as this parameter.
1908 % o crop_geometry: A crop geometry string. This geometry defines a
1909 % subregion of the image to crop.
1911 % o image_geometry: An image geometry string. This geometry defines the
1912 % final size of the image.
1915 MagickExport MagickBooleanType TransformImages(Image **images,
1916 const char *crop_geometry,const char *image_geometry)
1929 assert(images != (Image **) NULL);
1930 assert((*images)->signature == MagickSignature);
1931 if ((*images)->debug != MagickFalse)
1932 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1933 (*images)->filename);
1934 image_list=ImageListToArray(*images,&(*images)->exception);
1935 if (image_list == (Image **) NULL)
1936 return(MagickFalse);
1938 transform_images=NewImageList();
1939 for (i=0; image_list[i] != (Image *) NULL; i++)
1941 image=image_list[i];
1942 status|=TransformImage(&image,crop_geometry,image_geometry);
1943 AppendImageToList(&transform_images,image);
1945 *images=transform_images;
1946 image_list=(Image **) RelinquishMagickMemory(image_list);
1947 return(status != 0 ? MagickTrue : MagickFalse);
1951 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1955 % T r a n s p o s e I m a g e %
1959 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1961 % TransposeImage() creates a horizontal mirror image by reflecting the pixels
1962 % around the central y-axis while rotating them by 90 degrees.
1964 % The format of the TransposeImage method is:
1966 % Image *TransposeImage(const Image *image,ExceptionInfo *exception)
1968 % A description of each parameter follows:
1970 % o image: the image.
1972 % o exception: return any errors or warnings in this structure.
1975 MagickExport Image *TransposeImage(const Image *image,ExceptionInfo *exception)
1977 #define TransposeImageTag "Transpose/Image"
1996 assert(image != (const Image *) NULL);
1997 assert(image->signature == MagickSignature);
1998 if (image->debug != MagickFalse)
1999 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2000 assert(exception != (ExceptionInfo *) NULL);
2001 assert(exception->signature == MagickSignature);
2002 transpose_image=CloneImage(image,image->rows,image->columns,MagickTrue,
2004 if (transpose_image == (Image *) NULL)
2005 return((Image *) NULL);
2011 image_view=AcquireCacheView(image);
2012 transpose_view=AcquireCacheView(transpose_image);
2013 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2014 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
2016 for (y=0; y < (long) image->rows; y++)
2018 register const PixelPacket
2021 register IndexPacket
2022 *restrict transpose_indexes,
2025 register PixelPacket
2028 if (status == MagickFalse)
2030 p=GetCacheViewVirtualPixels(image_view,0,(long) image->rows-y-1,
2031 image->columns,1,exception);
2032 q=QueueCacheViewAuthenticPixels(transpose_view,(long) (image->rows-y-1),0,
2033 1,transpose_image->rows,exception);
2034 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
2039 (void) CopyMagickMemory(q,p,(size_t) image->columns*sizeof(*q));
2040 indexes=GetCacheViewAuthenticIndexQueue(image_view);
2041 if (indexes != (IndexPacket *) NULL)
2043 transpose_indexes=GetCacheViewAuthenticIndexQueue(transpose_view);
2044 if (transpose_indexes != (IndexPacket *) NULL)
2045 (void) CopyMagickMemory(transpose_indexes,indexes,(size_t)
2046 image->columns*sizeof(*transpose_indexes));
2048 if (SyncCacheViewAuthenticPixels(transpose_view,exception) == MagickFalse)
2050 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2055 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2056 #pragma omp critical (MagickCore_TransposeImage)
2058 proceed=SetImageProgress(image,TransposeImageTag,progress++,
2060 if (proceed == MagickFalse)
2064 transpose_view=DestroyCacheView(transpose_view);
2065 image_view=DestroyCacheView(image_view);
2066 transpose_image->type=image->type;
2067 page=transpose_image->page;
2068 Swap(page.width,page.height);
2069 Swap(page.x,page.y);
2070 if (page.width != 0)
2071 page.x=(long) (page.width-transpose_image->columns-page.x);
2072 transpose_image->page=page;
2073 if (status == MagickFalse)
2074 transpose_image=DestroyImage(transpose_image);
2075 return(transpose_image);
2079 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2083 % T r a n s v e r s e I m a g e %
2087 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2089 % TransverseImage() creates a vertical mirror image by reflecting the pixels
2090 % around the central x-axis while rotating them by 270 degrees.
2092 % The format of the TransverseImage method is:
2094 % Image *TransverseImage(const Image *image,ExceptionInfo *exception)
2096 % A description of each parameter follows:
2098 % o image: the image.
2100 % o exception: return any errors or warnings in this structure.
2103 MagickExport Image *TransverseImage(const Image *image,ExceptionInfo *exception)
2105 #define TransverseImageTag "Transverse/Image"
2124 assert(image != (const Image *) NULL);
2125 assert(image->signature == MagickSignature);
2126 if (image->debug != MagickFalse)
2127 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2128 assert(exception != (ExceptionInfo *) NULL);
2129 assert(exception->signature == MagickSignature);
2130 transverse_image=CloneImage(image,image->rows,image->columns,MagickTrue,
2132 if (transverse_image == (Image *) NULL)
2133 return((Image *) NULL);
2139 image_view=AcquireCacheView(image);
2140 transverse_view=AcquireCacheView(transverse_image);
2141 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2142 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
2144 for (y=0; y < (long) image->rows; y++)
2149 register const PixelPacket
2152 register IndexPacket
2153 *restrict transverse_indexes,
2159 register PixelPacket
2162 if (status == MagickFalse)
2164 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2165 q=QueueCacheViewAuthenticPixels(transverse_view,(long) (image->rows-y-
2166 1),0,1,transverse_image->rows,exception);
2167 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
2173 for (x=0; x < (long) image->columns; x++)
2175 indexes=GetCacheViewAuthenticIndexQueue(image_view);
2176 if (indexes != (IndexPacket *) NULL)
2178 transverse_indexes=GetCacheViewAuthenticIndexQueue(transverse_view);
2179 if (transverse_indexes != (IndexPacket *) NULL)
2180 for (x=0; x < (long) image->columns; x++)
2181 transverse_indexes[image->columns-x-1]=indexes[x];
2183 sync=SyncCacheViewAuthenticPixels(transverse_view,exception);
2184 if (sync == MagickFalse)
2186 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2191 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2192 #pragma omp critical (MagickCore_TransverseImage)
2194 proceed=SetImageProgress(image,TransverseImageTag,progress++,
2196 if (proceed == MagickFalse)
2200 transverse_view=DestroyCacheView(transverse_view);
2201 image_view=DestroyCacheView(image_view);
2202 transverse_image->type=image->type;
2203 page=transverse_image->page;
2204 Swap(page.width,page.height);
2205 Swap(page.x,page.y);
2206 if (page.height != 0)
2207 page.y=(long) (page.height-transverse_image->rows-page.y);
2208 transverse_image->page=page;
2209 if (status == MagickFalse)
2210 transverse_image=DestroyImage(transverse_image);
2211 return(transverse_image);
2215 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2219 % T r i m I m a g e %
2223 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2225 % TrimImage() trims pixels from the image edges. It allocates the memory
2226 % necessary for the new Image structure and returns a pointer to the new
2229 % The format of the TrimImage method is:
2231 % Image *TrimImage(const Image *image,ExceptionInfo *exception)
2233 % A description of each parameter follows:
2235 % o image: the image.
2237 % o exception: return any errors or warnings in this structure.
2240 MagickExport Image *TrimImage(const Image *image,ExceptionInfo *exception)
2245 assert(image != (const Image *) NULL);
2246 assert(image->signature == MagickSignature);
2247 if (image->debug != MagickFalse)
2248 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2249 geometry=GetImageBoundingBox(image,exception);
2250 if ((geometry.width == 0) || (geometry.height == 0))
2255 crop_image=CloneImage(image,1,1,MagickTrue,exception);
2256 if (crop_image == (Image *) NULL)
2257 return((Image *) NULL);
2258 crop_image->background_color.opacity=(Quantum) TransparentOpacity;
2259 (void) SetImageBackgroundColor(crop_image);
2260 crop_image->page=image->page;
2261 crop_image->page.x=(-1);
2262 crop_image->page.y=(-1);
2265 geometry.x+=image->page.x;
2266 geometry.y+=image->page.y;
2267 return(CropImage(image,&geometry,exception));