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+(ssize_t) chop_info->width) < 0) ||
133 ((chop_info->y+(ssize_t) chop_info->height) < 0) ||
134 (chop_info->x > (ssize_t) image->columns) ||
135 (chop_info->y > (ssize_t) image->rows))
136 ThrowImageException(OptionWarning,"GeometryDoesNotContainImage");
138 if ((extent.x+(ssize_t) extent.width) > (ssize_t) image->columns)
139 extent.width=(size_t) ((ssize_t) image->columns-extent.x);
140 if ((extent.y+(ssize_t) extent.height) > (ssize_t) image->rows)
141 extent.height=(size_t) ((ssize_t) image->rows-extent.y);
144 extent.width-=(size_t) (-extent.x);
149 extent.height-=(size_t) (-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 < (ssize_t) 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 < (ssize_t) image->columns; x++)
193 if ((x < extent.x) || (x >= (ssize_t) (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,(MagickOffsetType) y,
209 if (proceed == MagickFalse)
215 i+=(ssize_t) extent.height;
216 for (y=0; y < (ssize_t) (image->rows-(extent.y+extent.height)); y++)
218 register const PixelPacket
222 *restrict chop_indexes,
231 if (status == MagickFalse)
233 p=GetCacheViewVirtualPixels(image_view,0,i++,image->columns,1,exception);
234 q=QueueCacheViewAuthenticPixels(chop_view,0,j++,chop_image->columns,1,
236 if ((p == (PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
241 indexes=GetCacheViewAuthenticIndexQueue(image_view);
242 chop_indexes=GetCacheViewAuthenticIndexQueue(chop_view);
243 for (x=0; x < (ssize_t) image->columns; x++)
245 if ((x < extent.x) || (x >= (ssize_t) (extent.x+extent.width)))
248 if (indexes != (IndexPacket *) NULL)
250 if (chop_indexes != (IndexPacket *) NULL)
251 *chop_indexes++=indexes[x];
257 if (SyncCacheViewAuthenticPixels(chop_view,exception) == MagickFalse)
259 proceed=SetImageProgress(image,ChopImageTag,(MagickOffsetType) y,
261 if (proceed == MagickFalse)
264 chop_view=DestroyCacheView(chop_view);
265 image_view=DestroyCacheView(image_view);
266 chop_image->type=image->type;
271 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
275 + C o n s o l i d a t e C M Y K I m a g e %
279 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
281 % ConsolidateCMYKImage() consolidates separate C, M, Y, and K planes into a
284 % The format of the ConsolidateCMYKImage method is:
286 % Image *ConsolidateCMYKImage(const Image *image,ExceptionInfo *exception)
288 % A description of each parameter follows:
290 % o image: the image sequence.
292 % o exception: return any errors or warnings in this structure.
295 MagickExport Image *ConsolidateCMYKImages(const Image *images,
296 ExceptionInfo *exception)
309 Consolidate separate C, M, Y, and K planes into a single image.
311 assert(images != (Image *) NULL);
312 assert(images->signature == MagickSignature);
313 if (images->debug != MagickFalse)
314 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
315 assert(exception != (ExceptionInfo *) NULL);
316 assert(exception->signature == MagickSignature);
317 cmyk_images=NewImageList();
318 for (i=0; i < (ssize_t) GetImageListLength(images); i+=4)
320 cmyk_image=CloneImage(images,images->columns,images->rows,MagickTrue,
322 if (cmyk_image == (Image *) NULL)
324 if (SetImageStorageClass(cmyk_image,DirectClass) == MagickFalse)
326 (void) SetImageColorspace(cmyk_image,CMYKColorspace);
327 for (y=0; y < (ssize_t) images->rows; y++)
329 register const PixelPacket
338 p=GetVirtualPixels(images,0,y,images->columns,1,exception);
339 q=QueueAuthenticPixels(cmyk_image,0,y,cmyk_image->columns,1,exception);
340 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
342 for (x=0; x < (ssize_t) images->columns; x++)
344 q->red=(Quantum) (QuantumRange-PixelIntensityToQuantum(p));
348 if (SyncAuthenticPixels(cmyk_image,exception) == MagickFalse)
351 images=GetNextImageInList(images);
352 if (images == (Image *) NULL)
354 for (y=0; y < (ssize_t) images->rows; y++)
356 register const PixelPacket
365 p=GetVirtualPixels(images,0,y,images->columns,1,exception);
366 q=GetAuthenticPixels(cmyk_image,0,y,cmyk_image->columns,1,exception);
367 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
369 for (x=0; x < (ssize_t) images->columns; x++)
371 q->green=(Quantum) (QuantumRange-PixelIntensityToQuantum(p));
375 if (SyncAuthenticPixels(cmyk_image,exception) == MagickFalse)
378 images=GetNextImageInList(images);
379 if (images == (Image *) NULL)
381 for (y=0; y < (ssize_t) images->rows; y++)
383 register const PixelPacket
392 p=GetVirtualPixels(images,0,y,images->columns,1,exception);
393 q=GetAuthenticPixels(cmyk_image,0,y,cmyk_image->columns,1,exception);
394 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
396 for (x=0; x < (ssize_t) images->columns; x++)
398 q->blue=(Quantum) (QuantumRange-PixelIntensityToQuantum(p));
402 if (SyncAuthenticPixels(cmyk_image,exception) == MagickFalse)
405 images=GetNextImageInList(images);
406 if (images == (Image *) NULL)
408 for (y=0; y < (ssize_t) images->rows; y++)
410 register const PixelPacket
422 p=GetVirtualPixels(images,0,y,images->columns,1,exception);
423 q=GetAuthenticPixels(cmyk_image,0,y,cmyk_image->columns,1,exception);
424 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
426 indexes=GetAuthenticIndexQueue(cmyk_image);
427 for (x=0; x < (ssize_t) images->columns; x++)
429 indexes[x]=(IndexPacket) (QuantumRange-PixelIntensityToQuantum(p));
432 if (SyncAuthenticPixels(cmyk_image,exception) == MagickFalse)
435 AppendImageToList(&cmyk_images,cmyk_image);
436 images=GetNextImageInList(images);
437 if (images == (Image *) NULL)
444 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
448 % C r o p I m a g e %
452 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
454 % CropImage() extracts a region of the image starting at the offset defined
457 % The format of the CropImage method is:
459 % Image *CropImage(const Image *image,const RectangleInfo *geometry,
460 % ExceptionInfo *exception)
462 % A description of each parameter follows:
464 % o image: the image.
466 % o geometry: Define the region of the image to crop with members
467 % x, y, width, and height.
469 % o exception: return any errors or warnings in this structure.
472 MagickExport Image *CropImage(const Image *image,const RectangleInfo *geometry,
473 ExceptionInfo *exception)
475 #define CropImageTag "Crop/Image"
500 assert(image != (const Image *) NULL);
501 assert(image->signature == MagickSignature);
502 if (image->debug != MagickFalse)
503 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
504 assert(geometry != (const RectangleInfo *) NULL);
505 assert(exception != (ExceptionInfo *) NULL);
506 assert(exception->signature == MagickSignature);
507 bounding_box=image->page;
508 if ((bounding_box.width == 0) || (bounding_box.height == 0))
510 bounding_box.width=image->columns;
511 bounding_box.height=image->rows;
515 page.width=bounding_box.width;
516 if (page.height == 0)
517 page.height=bounding_box.height;
518 if (((bounding_box.x-page.x) >= (ssize_t) page.width) ||
519 ((bounding_box.y-page.y) >= (ssize_t) page.height) ||
520 ((page.x-bounding_box.x) > (ssize_t) image->columns) ||
521 ((page.y-bounding_box.y) > (ssize_t) image->rows))
524 Crop is not within virtual canvas, return 1 pixel transparent image.
526 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
527 "GeometryDoesNotContainImage","`%s'",image->filename);
528 crop_image=CloneImage(image,1,1,MagickTrue,exception);
529 if (crop_image == (Image *) NULL)
530 return((Image *) NULL);
531 crop_image->background_color.opacity=(Quantum) TransparentOpacity;
532 (void) SetImageBackgroundColor(crop_image);
533 crop_image->page=bounding_box;
534 crop_image->page.x=(-1);
535 crop_image->page.y=(-1);
536 if (crop_image->dispose == BackgroundDispose)
537 crop_image->dispose=NoneDispose;
540 if ((page.x < 0) && (bounding_box.x >= 0))
542 page.width+=page.x-bounding_box.x;
547 page.width-=bounding_box.x-page.x;
548 page.x-=bounding_box.x;
552 if ((page.y < 0) && (bounding_box.y >= 0))
554 page.height+=page.y-bounding_box.y;
559 page.height-=bounding_box.y-page.y;
560 page.y-=bounding_box.y;
564 if ((size_t) (page.x+page.width) > image->columns)
565 page.width=image->columns-page.x;
566 if ((geometry->width != 0) && (page.width > geometry->width))
567 page.width=geometry->width;
568 if ((size_t) (page.y+page.height) > image->rows)
569 page.height=image->rows-page.y;
570 if ((geometry->height != 0) && (page.height > geometry->height))
571 page.height=geometry->height;
572 bounding_box.x+=page.x;
573 bounding_box.y+=page.y;
574 if ((page.width == 0) || (page.height == 0))
576 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
577 "GeometryDoesNotContainImage","`%s'",image->filename);
578 return((Image *) NULL);
581 Initialize crop image attributes.
583 crop_image=CloneImage(image,page.width,page.height,MagickTrue,exception);
584 if (crop_image == (Image *) NULL)
585 return((Image *) NULL);
586 crop_image->page.width=image->page.width;
587 crop_image->page.height=image->page.height;
588 if (((ssize_t) (bounding_box.x+bounding_box.width) > (ssize_t) image->page.width) ||
589 ((ssize_t) (bounding_box.y+bounding_box.height) > (ssize_t) image->page.height))
591 crop_image->page.width=bounding_box.width;
592 crop_image->page.height=bounding_box.height;
594 crop_image->page.x=bounding_box.x;
595 crop_image->page.y=bounding_box.y;
601 image_view=AcquireCacheView(image);
602 crop_view=AcquireCacheView(crop_image);
603 #if defined(MAGICKCORE_OPENMP_SUPPORT)
604 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
606 for (y=0; y < (ssize_t) crop_image->rows; y++)
608 register const IndexPacket
611 register const PixelPacket
615 *restrict crop_indexes;
620 if (status == MagickFalse)
622 p=GetCacheViewVirtualPixels(image_view,page.x,page.y+y,crop_image->columns,
624 q=QueueCacheViewAuthenticPixels(crop_view,0,y,crop_image->columns,1,
626 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
631 indexes=GetCacheViewVirtualIndexQueue(image_view);
632 crop_indexes=GetCacheViewAuthenticIndexQueue(crop_view);
633 (void) CopyMagickMemory(q,p,(size_t) crop_image->columns*sizeof(*q));
634 if ((indexes != (IndexPacket *) NULL) &&
635 (crop_indexes != (IndexPacket *) NULL))
636 (void) CopyMagickMemory(crop_indexes,indexes,(size_t) crop_image->columns*
637 sizeof(*crop_indexes));
638 if (SyncCacheViewAuthenticPixels(crop_view,exception) == MagickFalse)
640 if (image->progress_monitor != (MagickProgressMonitor) NULL)
645 #if defined(MAGICKCORE_OPENMP_SUPPORT)
646 #pragma omp critical (MagickCore_CropImage)
648 proceed=SetImageProgress(image,CropImageTag,progress++,image->rows);
649 if (proceed == MagickFalse)
653 crop_view=DestroyCacheView(crop_view);
654 image_view=DestroyCacheView(image_view);
655 crop_image->type=image->type;
656 if (status == MagickFalse)
657 crop_image=DestroyImage(crop_image);
662 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
666 % E x c e r p t I m a g e %
670 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
672 % ExcerptImage() returns a excerpt of the image as defined by the geometry.
674 % The format of the ExcerptImage method is:
676 % Image *ExcerptImage(const Image *image,const RectangleInfo *geometry,
677 % ExceptionInfo *exception)
679 % A description of each parameter follows:
681 % o image: the image.
683 % o geometry: Define the region of the image to extend with members
684 % x, y, width, and height.
686 % o exception: return any errors or warnings in this structure.
689 MagickExport Image *ExcerptImage(const Image *image,
690 const RectangleInfo *geometry,ExceptionInfo *exception)
692 #define ExcerptImageTag "Excerpt/Image"
711 Allocate excerpt image.
713 assert(image != (const Image *) NULL);
714 assert(image->signature == MagickSignature);
715 if (image->debug != MagickFalse)
716 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
717 assert(geometry != (const RectangleInfo *) NULL);
718 assert(exception != (ExceptionInfo *) NULL);
719 assert(exception->signature == MagickSignature);
720 excerpt_image=CloneImage(image,geometry->width,geometry->height,MagickTrue,
722 if (excerpt_image == (Image *) NULL)
723 return((Image *) NULL);
729 image_view=AcquireCacheView(image);
730 excerpt_view=AcquireCacheView(excerpt_image);
731 #if defined(MAGICKCORE_OPENMP_SUPPORT)
732 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
734 for (y=0; y < (ssize_t) excerpt_image->rows; y++)
736 register const PixelPacket
740 *restrict excerpt_indexes,
746 if (status == MagickFalse)
748 p=GetCacheViewVirtualPixels(image_view,geometry->x,geometry->y+y,
749 geometry->width,1,exception);
750 q=GetCacheViewAuthenticPixels(excerpt_view,0,y,excerpt_image->columns,1,
752 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
757 (void) CopyMagickMemory(q,p,(size_t) excerpt_image->columns*sizeof(*q));
758 indexes=GetCacheViewAuthenticIndexQueue(image_view);
759 if (indexes != (IndexPacket *) NULL)
761 excerpt_indexes=GetCacheViewAuthenticIndexQueue(excerpt_view);
762 if (excerpt_indexes != (IndexPacket *) NULL)
763 (void) CopyMagickMemory(excerpt_indexes,indexes,(size_t)
764 excerpt_image->columns*sizeof(*excerpt_indexes));
766 if (SyncCacheViewAuthenticPixels(excerpt_view,exception) == MagickFalse)
768 if (image->progress_monitor != (MagickProgressMonitor) NULL)
773 #if defined(MAGICKCORE_OPENMP_SUPPORT)
774 #pragma omp critical (MagickCore_ExcerptImage)
776 proceed=SetImageProgress(image,ExcerptImageTag,progress++,image->rows);
777 if (proceed == MagickFalse)
781 excerpt_view=DestroyCacheView(excerpt_view);
782 image_view=DestroyCacheView(image_view);
783 excerpt_image->type=image->type;
784 if (status == MagickFalse)
785 excerpt_image=DestroyImage(excerpt_image);
786 return(excerpt_image);
790 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
794 % E x t e n t I m a g e %
798 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
800 % ExtentImage() extends the image as defined by the geometry, gravity, and
801 % image background color. Set the (x,y) offset of the geometry to move the
802 % original image relative to the extended image.
804 % The format of the ExtentImage method is:
806 % Image *ExtentImage(const Image *image,const RectangleInfo *geometry,
807 % ExceptionInfo *exception)
809 % A description of each parameter follows:
811 % o image: the image.
813 % o geometry: Define the region of the image to extend with members
814 % x, y, width, and height.
816 % o exception: return any errors or warnings in this structure.
819 MagickExport Image *ExtentImage(const Image *image,
820 const RectangleInfo *geometry,ExceptionInfo *exception)
826 Allocate extent image.
828 assert(image != (const Image *) NULL);
829 assert(image->signature == MagickSignature);
830 if (image->debug != MagickFalse)
831 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
832 assert(geometry != (const RectangleInfo *) NULL);
833 assert(exception != (ExceptionInfo *) NULL);
834 assert(exception->signature == MagickSignature);
835 extent_image=CloneImage(image,geometry->width,geometry->height,MagickTrue,
837 if (extent_image == (Image *) NULL)
838 return((Image *) NULL);
839 if (SetImageStorageClass(extent_image,DirectClass) == MagickFalse)
841 InheritException(exception,&extent_image->exception);
842 extent_image=DestroyImage(extent_image);
843 return((Image *) NULL);
845 if (extent_image->background_color.opacity != OpaqueOpacity)
846 extent_image->matte=MagickTrue;
847 (void) SetImageBackgroundColor(extent_image);
848 (void) CompositeImage(extent_image,image->compose,image,geometry->x,
850 return(extent_image);
854 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
858 % F l i p I m a g e %
862 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
864 % FlipImage() creates a vertical mirror image by reflecting the pixels
865 % around the central x-axis.
867 % The format of the FlipImage method is:
869 % Image *FlipImage(const Image *image,ExceptionInfo *exception)
871 % A description of each parameter follows:
873 % o image: the image.
875 % o exception: return any errors or warnings in this structure.
878 MagickExport Image *FlipImage(const Image *image,ExceptionInfo *exception)
880 #define FlipImageTag "Flip/Image"
898 assert(image != (const Image *) NULL);
899 assert(image->signature == MagickSignature);
900 if (image->debug != MagickFalse)
901 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
902 assert(exception != (ExceptionInfo *) NULL);
903 assert(exception->signature == MagickSignature);
904 flip_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
905 if (flip_image == (Image *) NULL)
906 return((Image *) NULL);
912 image_view=AcquireCacheView(image);
913 flip_view=AcquireCacheView(flip_image);
914 #if defined(MAGICKCORE_OPENMP_SUPPORT)
915 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
917 for (y=0; y < (ssize_t) flip_image->rows; y++)
919 register const IndexPacket
922 register const PixelPacket
926 *restrict flip_indexes;
931 if (status == MagickFalse)
933 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
934 q=QueueCacheViewAuthenticPixels(flip_view,0,(ssize_t) (flip_image->rows-y-
935 1),flip_image->columns,1,exception);
936 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
941 (void) CopyMagickMemory(q,p,(size_t) image->columns*sizeof(*q));
942 indexes=GetCacheViewVirtualIndexQueue(image_view);
943 if (indexes != (const IndexPacket *) NULL)
945 flip_indexes=GetCacheViewAuthenticIndexQueue(flip_view);
946 if (flip_indexes != (IndexPacket *) NULL)
947 (void) CopyMagickMemory(flip_indexes,indexes,(size_t) image->columns*
948 sizeof(*flip_indexes));
950 if (SyncCacheViewAuthenticPixels(flip_view,exception) == MagickFalse)
952 if (image->progress_monitor != (MagickProgressMonitor) NULL)
957 #if defined(MAGICKCORE_OPENMP_SUPPORT)
958 #pragma omp critical (MagickCore_FlipImage)
960 proceed=SetImageProgress(image,FlipImageTag,progress++,image->rows);
961 if (proceed == MagickFalse)
965 flip_view=DestroyCacheView(flip_view);
966 image_view=DestroyCacheView(image_view);
967 flip_image->type=image->type;
968 if (status == MagickFalse)
969 flip_image=DestroyImage(flip_image);
974 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
978 % F l o p I m a g e %
982 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
984 % FlopImage() creates a horizontal mirror image by reflecting the pixels
985 % around the central y-axis.
987 % The format of the FlopImage method is:
989 % Image *FlopImage(const Image *image,ExceptionInfo *exception)
991 % A description of each parameter follows:
993 % o image: the image.
995 % o exception: return any errors or warnings in this structure.
998 MagickExport Image *FlopImage(const Image *image,ExceptionInfo *exception)
1000 #define FlopImageTag "Flop/Image"
1018 assert(image != (const Image *) NULL);
1019 assert(image->signature == MagickSignature);
1020 if (image->debug != MagickFalse)
1021 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1022 assert(exception != (ExceptionInfo *) NULL);
1023 assert(exception->signature == MagickSignature);
1024 flop_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
1025 if (flop_image == (Image *) NULL)
1026 return((Image *) NULL);
1032 image_view=AcquireCacheView(image);
1033 flop_view=AcquireCacheView(flop_image);
1034 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1035 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
1037 for (y=0; y < (ssize_t) flop_image->rows; y++)
1039 register const IndexPacket
1042 register const PixelPacket
1045 register IndexPacket
1046 *restrict flop_indexes;
1051 register PixelPacket
1054 if (status == MagickFalse)
1056 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1057 q=QueueCacheViewAuthenticPixels(flop_view,0,y,flop_image->columns,1,
1059 if ((p == (PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
1064 q+=flop_image->columns;
1065 indexes=GetCacheViewVirtualIndexQueue(image_view);
1066 flop_indexes=GetCacheViewAuthenticIndexQueue(flop_view);
1067 for (x=0; x < (ssize_t) flop_image->columns; x++)
1070 if ((indexes != (const IndexPacket *) NULL) &&
1071 (flop_indexes != (IndexPacket *) NULL))
1072 flop_indexes[flop_image->columns-x-1]=indexes[x];
1074 if (SyncCacheViewAuthenticPixels(flop_view,exception) == MagickFalse)
1076 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1081 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1082 #pragma omp critical (MagickCore_FlopImage)
1084 proceed=SetImageProgress(image,FlopImageTag,progress++,image->rows);
1085 if (proceed == MagickFalse)
1089 flop_view=DestroyCacheView(flop_view);
1090 image_view=DestroyCacheView(image_view);
1091 flop_image->type=image->type;
1092 if (status == MagickFalse)
1093 flop_image=DestroyImage(flop_image);
1098 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1102 % R o l l I m a g e %
1106 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1108 % RollImage() offsets an image as defined by x_offset and y_offset.
1110 % The format of the RollImage method is:
1112 % Image *RollImage(const Image *image,const ssize_t x_offset,
1113 % const ssize_t y_offset,ExceptionInfo *exception)
1115 % A description of each parameter follows:
1117 % o image: the image.
1119 % o x_offset: the number of columns to roll in the horizontal direction.
1121 % o y_offset: the number of rows to roll in the vertical direction.
1123 % o exception: return any errors or warnings in this structure.
1127 static inline MagickBooleanType CopyImageRegion(Image *destination,
1128 const Image *source,const size_t columns,const size_t rows,
1129 const ssize_t sx,const ssize_t sy,const ssize_t dx,const ssize_t dy,
1130 ExceptionInfo *exception)
1143 source_view=AcquireCacheView(source);
1144 destination_view=AcquireCacheView(destination);
1145 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1146 #pragma omp parallel for schedule(dynamic,4) shared(status)
1148 for (y=0; y < (ssize_t) rows; y++)
1153 register const IndexPacket
1156 register const PixelPacket
1159 register IndexPacket
1160 *restrict destination_indexes;
1162 register PixelPacket
1168 if (status == MagickFalse)
1170 p=GetCacheViewVirtualPixels(source_view,sx,sy+y,columns,1,exception);
1171 q=GetCacheViewAuthenticPixels(destination_view,dx,dy+y,columns,1,exception);
1172 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
1177 indexes=GetCacheViewVirtualIndexQueue(source_view);
1178 (void) CopyMagickMemory(q,p,(size_t) columns*sizeof(*p));
1179 if (indexes != (IndexPacket *) NULL)
1181 destination_indexes=GetCacheViewAuthenticIndexQueue(destination_view);
1182 if (destination_indexes != (IndexPacket *) NULL)
1183 (void) CopyMagickMemory(destination_indexes,indexes,(size_t)
1184 columns*sizeof(*indexes));
1186 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
1187 if (sync == MagickFalse)
1190 destination_view=DestroyCacheView(destination_view);
1191 source_view=DestroyCacheView(source_view);
1195 MagickExport Image *RollImage(const Image *image,const ssize_t x_offset,
1196 const ssize_t y_offset,ExceptionInfo *exception)
1198 #define RollImageTag "Roll/Image"
1210 Initialize roll image attributes.
1212 assert(image != (const Image *) NULL);
1213 assert(image->signature == MagickSignature);
1214 if (image->debug != MagickFalse)
1215 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1216 assert(exception != (ExceptionInfo *) NULL);
1217 assert(exception->signature == MagickSignature);
1218 roll_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
1219 if (roll_image == (Image *) NULL)
1220 return((Image *) NULL);
1223 while (offset.x < 0)
1224 offset.x+=(ssize_t) image->columns;
1225 while (offset.x >= (ssize_t) image->columns)
1226 offset.x-=(ssize_t) image->columns;
1227 while (offset.y < 0)
1228 offset.y+=(ssize_t) image->rows;
1229 while (offset.y >= (ssize_t) image->rows)
1230 offset.y-=(ssize_t) image->rows;
1234 status=CopyImageRegion(roll_image,image,(size_t) offset.x,
1235 (size_t) offset.y,(ssize_t) image->columns-offset.x,(ssize_t) image->rows-
1236 offset.y,0,0,exception);
1237 (void) SetImageProgress(image,RollImageTag,0,3);
1238 status|=CopyImageRegion(roll_image,image,image->columns-offset.x,
1239 (size_t) offset.y,0,(ssize_t) image->rows-offset.y,offset.x,0,
1241 (void) SetImageProgress(image,RollImageTag,1,3);
1242 status|=CopyImageRegion(roll_image,image,(size_t) offset.x,image->rows-
1243 offset.y,(ssize_t) image->columns-offset.x,0,0,offset.y,exception);
1244 (void) SetImageProgress(image,RollImageTag,2,3);
1245 status|=CopyImageRegion(roll_image,image,image->columns-offset.x,image->rows-
1246 offset.y,0,0,offset.x,offset.y,exception);
1247 (void) SetImageProgress(image,RollImageTag,3,3);
1248 roll_image->type=image->type;
1249 if (status == MagickFalse)
1250 roll_image=DestroyImage(roll_image);
1255 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1259 % S h a v e I m a g e %
1263 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1265 % ShaveImage() shaves pixels from the image edges. It allocates the memory
1266 % necessary for the new Image structure and returns a pointer to the new
1269 % The format of the ShaveImage method is:
1271 % Image *ShaveImage(const Image *image,const RectangleInfo *shave_info,
1272 % ExceptionInfo *exception)
1274 % A description of each parameter follows:
1276 % o shave_image: Method ShaveImage returns a pointer to the shaved
1277 % image. A null image is returned if there is a memory shortage or
1278 % if the image width or height is zero.
1280 % o image: the image.
1282 % o shave_info: Specifies a pointer to a RectangleInfo which defines the
1283 % region of the image to crop.
1285 % o exception: return any errors or warnings in this structure.
1288 MagickExport Image *ShaveImage(const Image *image,
1289 const RectangleInfo *shave_info,ExceptionInfo *exception)
1297 assert(image != (const Image *) NULL);
1298 assert(image->signature == MagickSignature);
1299 if (image->debug != MagickFalse)
1300 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1301 if (((2*shave_info->width) >= image->columns) ||
1302 ((2*shave_info->height) >= image->rows))
1303 ThrowImageException(OptionWarning,"GeometryDoesNotContainImage");
1304 SetGeometry(image,&geometry);
1305 geometry.width-=2*shave_info->width;
1306 geometry.height-=2*shave_info->height;
1307 geometry.x=(ssize_t) shave_info->width+image->page.x;
1308 geometry.y=(ssize_t) shave_info->height+image->page.y;
1309 shave_image=CropImage(image,&geometry,exception);
1310 if (shave_image == (Image *) NULL)
1311 return((Image *) NULL);
1312 shave_image->page.width-=2*shave_info->width;
1313 shave_image->page.height-=2*shave_info->height;
1314 shave_image->page.x-=(ssize_t) shave_info->width;
1315 shave_image->page.y-=(ssize_t) shave_info->height;
1316 return(shave_image);
1320 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1324 % S p l i c e I m a g e %
1328 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1330 % SpliceImage() splices a solid color into the image as defined by the
1333 % The format of the SpliceImage method is:
1335 % Image *SpliceImage(const Image *image,const RectangleInfo *geometry,
1336 % ExceptionInfo *exception)
1338 % A description of each parameter follows:
1340 % o image: the image.
1342 % o geometry: Define the region of the image to splice with members
1343 % x, y, width, and height.
1345 % o exception: return any errors or warnings in this structure.
1348 MagickExport Image *SpliceImage(const Image *image,
1349 const RectangleInfo *geometry,ExceptionInfo *exception)
1351 #define SpliceImageTag "Splice/Image"
1377 Allocate splice image.
1379 assert(image != (const Image *) NULL);
1380 assert(image->signature == MagickSignature);
1381 if (image->debug != MagickFalse)
1382 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1383 assert(geometry != (const RectangleInfo *) NULL);
1384 assert(exception != (ExceptionInfo *) NULL);
1385 assert(exception->signature == MagickSignature);
1386 splice_geometry=(*geometry);
1387 splice_image=CloneImage(image,image->columns+splice_geometry.width,
1388 image->rows+splice_geometry.height,MagickTrue,exception);
1389 if (splice_image == (Image *) NULL)
1390 return((Image *) NULL);
1391 if (SetImageStorageClass(splice_image,DirectClass) == MagickFalse)
1393 InheritException(exception,&splice_image->exception);
1394 splice_image=DestroyImage(splice_image);
1395 return((Image *) NULL);
1397 (void) SetImageBackgroundColor(splice_image);
1399 Respect image geometry.
1401 switch (image->gravity)
1404 case UndefinedGravity:
1405 case NorthWestGravity:
1409 splice_geometry.x+=(ssize_t) splice_geometry.width/2;
1412 case NorthEastGravity:
1414 splice_geometry.x+=(ssize_t) splice_geometry.width;
1419 splice_geometry.y+=(ssize_t) splice_geometry.width/2;
1425 splice_geometry.x+=(ssize_t) splice_geometry.width/2;
1426 splice_geometry.y+=(ssize_t) splice_geometry.height/2;
1431 splice_geometry.x+=(ssize_t) splice_geometry.width;
1432 splice_geometry.y+=(ssize_t) splice_geometry.height/2;
1435 case SouthWestGravity:
1437 splice_geometry.y+=(ssize_t) splice_geometry.height;
1442 splice_geometry.x+=(ssize_t) splice_geometry.width/2;
1443 splice_geometry.y+=(ssize_t) splice_geometry.height;
1446 case SouthEastGravity:
1448 splice_geometry.x+=(ssize_t) splice_geometry.width;
1449 splice_geometry.y+=(ssize_t) splice_geometry.height;
1459 image_view=AcquireCacheView(image);
1460 splice_view=AcquireCacheView(splice_image);
1461 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1462 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
1464 for (y=0; y < (ssize_t) splice_geometry.y; y++)
1466 register const PixelPacket
1469 register IndexPacket
1471 *restrict splice_indexes;
1476 register PixelPacket
1479 if (status == MagickFalse)
1481 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1482 q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1,
1484 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
1489 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1490 splice_indexes=GetCacheViewAuthenticIndexQueue(splice_view);
1491 for (x=0; x < splice_geometry.x; x++)
1493 SetRedPixelComponent(q,GetRedPixelComponent(p));
1494 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
1495 SetBluePixelComponent(q,GetBluePixelComponent(p));
1496 SetOpacityPixelComponent(q,OpaqueOpacity);
1497 if (image->matte != MagickFalse)
1498 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
1499 if (image->colorspace == CMYKColorspace)
1500 splice_indexes[x]=(*indexes++);
1504 for ( ; x < (ssize_t) (splice_geometry.x+splice_geometry.width); x++)
1506 for ( ; x < (ssize_t) splice_image->columns; x++)
1508 SetRedPixelComponent(q,GetRedPixelComponent(p));
1509 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
1510 SetBluePixelComponent(q,GetBluePixelComponent(p));
1511 SetOpacityPixelComponent(q,OpaqueOpacity);
1512 if (image->matte != MagickFalse)
1513 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
1514 if (image->colorspace == CMYKColorspace)
1515 splice_indexes[x]=(*indexes++);
1519 if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse)
1521 proceed=SetImageProgress(image,SpliceImageTag,(MagickOffsetType) y,
1522 splice_image->rows);
1523 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1528 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1529 #pragma omp critical (MagickCore_TransposeImage)
1531 proceed=SetImageProgress(image,SpliceImageTag,progress++,
1532 splice_image->rows);
1533 if (proceed == MagickFalse)
1537 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1538 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
1540 for (y=(ssize_t) (splice_geometry.y+splice_geometry.height);
1541 y < (ssize_t) splice_image->rows; y++)
1543 register const PixelPacket
1546 register IndexPacket
1548 *restrict splice_indexes;
1553 register PixelPacket
1556 if (status == MagickFalse)
1558 p=GetCacheViewVirtualPixels(image_view,0,y-(ssize_t) splice_geometry.height,
1559 image->columns,1,exception);
1560 q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1,
1562 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
1567 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1568 splice_indexes=GetCacheViewAuthenticIndexQueue(splice_view);
1569 for (x=0; x < splice_geometry.x; x++)
1571 SetRedPixelComponent(q,GetRedPixelComponent(p));
1572 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
1573 SetBluePixelComponent(q,GetBluePixelComponent(p));
1574 SetOpacityPixelComponent(q,OpaqueOpacity);
1575 if (image->matte != MagickFalse)
1576 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
1577 if (image->colorspace == CMYKColorspace)
1578 splice_indexes[x]=(*indexes++);
1582 for ( ; x < (ssize_t) (splice_geometry.x+splice_geometry.width); x++)
1584 for ( ; x < (ssize_t) splice_image->columns; x++)
1586 SetRedPixelComponent(q,GetRedPixelComponent(p));
1587 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
1588 SetBluePixelComponent(q,GetBluePixelComponent(p));
1589 SetOpacityPixelComponent(q,OpaqueOpacity);
1590 if (image->matte != MagickFalse)
1591 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
1592 if (image->colorspace == CMYKColorspace)
1593 splice_indexes[x]=(*indexes++);
1597 if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse)
1599 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1604 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1605 #pragma omp critical (MagickCore_TransposeImage)
1607 proceed=SetImageProgress(image,SpliceImageTag,progress++,
1608 splice_image->rows);
1609 if (proceed == MagickFalse)
1613 splice_view=DestroyCacheView(splice_view);
1614 image_view=DestroyCacheView(image_view);
1615 if (status == MagickFalse)
1616 splice_image=DestroyImage(splice_image);
1617 return(splice_image);
1621 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1625 % T r a n s f o r m I m a g e %
1629 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1631 % TransformImage() is a convenience method that behaves like ResizeImage() or
1632 % CropImage() but accepts scaling and/or cropping information as a region
1633 % geometry specification. If the operation fails, the original image handle
1636 % The format of the TransformImage method is:
1638 % MagickBooleanType TransformImage(Image **image,const char *crop_geometry,
1639 % const char *image_geometry)
1641 % A description of each parameter follows:
1643 % o image: the image The transformed image is returned as this parameter.
1645 % o crop_geometry: A crop geometry string. This geometry defines a
1646 % subregion of the image to crop.
1648 % o image_geometry: An image geometry string. This geometry defines the
1649 % final size of the image.
1652 static inline ssize_t MagickRound(MagickRealType x)
1655 Round the fraction to nearest integer.
1658 return((ssize_t) (x+0.5));
1659 return((ssize_t) (x-0.5));
1662 MagickExport MagickBooleanType TransformImage(Image **image,
1663 const char *crop_geometry,const char *image_geometry)
1684 assert(image != (Image **) NULL);
1685 assert((*image)->signature == MagickSignature);
1686 if ((*image)->debug != MagickFalse)
1687 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
1688 transform_image=(*image);
1689 if (crop_geometry != (const char *) NULL)
1698 Crop image to a user specified size.
1700 crop_image=NewImageList();
1701 flags=ParseGravityGeometry(transform_image,crop_geometry,&geometry,
1702 &(*image)->exception);
1703 if ((flags & AreaValue) != 0)
1713 Crop into NxM tiles (@ flag) - AT.
1715 if (geometry.width == 0)
1717 if (geometry.height == 0)
1719 width=transform_image->columns;
1720 height=transform_image->rows;
1721 if ((flags & AspectValue) == 0)
1723 width-=(geometry.x < 0 ? -1 : 1)*geometry.x;
1724 height-=(geometry.y < 0 ? -1 : 1)*geometry.y;
1728 width+=(geometry.x < 0 ? -1 : 1)*geometry.x;
1729 height+=(geometry.y < 0 ? -1 : 1)*geometry.y;
1731 delta.x=(double) width/geometry.width;
1732 delta.y=(double) height/geometry.height;
1733 next=NewImageList();
1734 for (offset.y=0; offset.y < (double) height; )
1736 if ((flags & AspectValue) == 0)
1738 crop.y=(ssize_t) MagickRound((MagickRealType) (offset.y-
1739 (geometry.y > 0 ? 0 : geometry.y)));
1741 crop.height=(size_t) MagickRound((MagickRealType)
1742 (offset.y+(geometry.y < 0 ? 0 : geometry.y)));
1746 crop.y=(ssize_t) MagickRound((MagickRealType) (offset.y-
1747 (geometry.y > 0 ? geometry.y : 0)));
1749 crop.height=(size_t) MagickRound((MagickRealType)
1750 (offset.y+(geometry.y < 0 ? geometry.y : 0)));
1752 crop.height-=crop.y;
1753 crop.y+=transform_image->page.y;
1754 for (offset.x=0; offset.x < (double) width; )
1756 if ((flags & AspectValue) == 0)
1758 crop.x=(ssize_t) MagickRound((MagickRealType) (offset.x-
1759 (geometry.x > 0 ? 0 : geometry.x)));
1761 crop.width=(size_t) MagickRound((MagickRealType)
1762 (offset.x+(geometry.x < 0 ? 0 : geometry.x)));
1766 crop.x=(ssize_t) MagickRound((MagickRealType) (offset.x-
1767 (geometry.x > 0 ? geometry.x : 0)));
1769 crop.width=(size_t) MagickRound((MagickRealType)
1770 (offset.x+(geometry.x < 0 ? geometry.x : 0)));
1773 crop.x+=transform_image->page.x;
1774 next=CropImage(transform_image,&crop,&(*image)->exception);
1775 if (next == (Image *) NULL)
1777 AppendImageToList(&crop_image,next);
1779 if (next == (Image *) NULL)
1784 if (((geometry.width == 0) && (geometry.height == 0)) ||
1785 ((flags & XValue) != 0) || ((flags & YValue) != 0))
1788 Crop a single region at +X+Y.
1790 crop_image=CropImage(transform_image,&geometry,
1791 &(*image)->exception);
1792 if ((crop_image != (Image *) NULL) && ((flags & AspectValue) != 0))
1794 crop_image->page.width=geometry.width;
1795 crop_image->page.height=geometry.height;
1796 crop_image->page.x-=geometry.x;
1797 crop_image->page.y-=geometry.y;
1801 if ((transform_image->columns > geometry.width) ||
1802 (transform_image->rows > geometry.height))
1807 MagickProgressMonitor
1817 Crop into tiles of fixed size WxH.
1819 if (transform_image->page.width == 0)
1820 transform_image->page.width=transform_image->columns;
1821 if (transform_image->page.height == 0)
1822 transform_image->page.height=transform_image->rows;
1823 width=geometry.width;
1825 width=transform_image->page.width;
1826 height=geometry.height;
1828 height=transform_image->page.height;
1829 next=NewImageList();
1833 for (y=0; y < (ssize_t) transform_image->page.height; y+=(ssize_t) height)
1834 for (x=0; x < (ssize_t) transform_image->page.width; x+=(ssize_t) width)
1836 for (y=0; y < (ssize_t) transform_image->page.height; y+=(ssize_t) height)
1838 for (x=0; x < (ssize_t) transform_image->page.width; x+=(ssize_t) width)
1840 progress_monitor=SetImageProgressMonitor(transform_image,
1841 (MagickProgressMonitor) NULL,transform_image->client_data);
1842 geometry.width=width;
1843 geometry.height=height;
1846 next=CropImage(transform_image,&geometry,&(*image)->exception);
1847 (void) SetImageProgressMonitor(transform_image,
1848 progress_monitor,transform_image->client_data);
1849 proceed=SetImageProgress(transform_image,CropImageTag,i++,
1851 if (proceed == MagickFalse)
1853 if (next == (Image *) NULL)
1855 (void) SetImageProgressMonitor(next,progress_monitor,
1857 if (crop_image == (Image *) NULL)
1861 next->previous=crop_image;
1862 crop_image->next=next;
1863 crop_image=crop_image->next;
1866 if (next == (Image *) NULL)
1868 if (proceed == MagickFalse)
1872 if (crop_image == (Image *) NULL)
1873 transform_image=CloneImage(*image,0,0,MagickTrue,&(*image)->exception);
1876 transform_image=DestroyImage(transform_image);
1877 transform_image=GetFirstImageInList(crop_image);
1879 *image=transform_image;
1881 if (image_geometry == (const char *) NULL)
1884 Scale image to a user specified size.
1886 flags=ParseRegionGeometry(transform_image,image_geometry,&geometry,
1887 &(*image)->exception);
1888 if ((transform_image->columns == geometry.width) &&
1889 (transform_image->rows == geometry.height))
1891 resize_image=ZoomImage(transform_image,geometry.width,geometry.height,
1892 &(*image)->exception);
1893 if (resize_image == (Image *) NULL)
1894 return(MagickFalse);
1895 transform_image=DestroyImage(transform_image);
1896 transform_image=resize_image;
1897 *image=transform_image;
1902 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1906 % T r a n s f o r m I m a g e s %
1909 % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1911 % TransformImages() calls TransformImage() on each image of a sequence.
1913 % The format of the TransformImage method is:
1915 % MagickBooleanType TransformImages(Image **image,
1916 % const char *crop_geometry,const char *image_geometry)
1918 % A description of each parameter follows:
1920 % o image: the image The transformed image is returned as this parameter.
1922 % o crop_geometry: A crop geometry string. This geometry defines a
1923 % subregion of the image to crop.
1925 % o image_geometry: An image geometry string. This geometry defines the
1926 % final size of the image.
1929 MagickExport MagickBooleanType TransformImages(Image **images,
1930 const char *crop_geometry,const char *image_geometry)
1943 assert(images != (Image **) NULL);
1944 assert((*images)->signature == MagickSignature);
1945 if ((*images)->debug != MagickFalse)
1946 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1947 (*images)->filename);
1948 image_list=ImageListToArray(*images,&(*images)->exception);
1949 if (image_list == (Image **) NULL)
1950 return(MagickFalse);
1952 transform_images=NewImageList();
1953 for (i=0; image_list[i] != (Image *) NULL; i++)
1955 image=image_list[i];
1956 status|=TransformImage(&image,crop_geometry,image_geometry);
1957 AppendImageToList(&transform_images,image);
1959 *images=transform_images;
1960 image_list=(Image **) RelinquishMagickMemory(image_list);
1961 return(status != 0 ? MagickTrue : MagickFalse);
1965 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1969 % T r a n s p o s e I m a g e %
1973 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1975 % TransposeImage() creates a horizontal mirror image by reflecting the pixels
1976 % around the central y-axis while rotating them by 90 degrees.
1978 % The format of the TransposeImage method is:
1980 % Image *TransposeImage(const Image *image,ExceptionInfo *exception)
1982 % A description of each parameter follows:
1984 % o image: the image.
1986 % o exception: return any errors or warnings in this structure.
1989 MagickExport Image *TransposeImage(const Image *image,ExceptionInfo *exception)
1991 #define TransposeImageTag "Transpose/Image"
2012 assert(image != (const Image *) NULL);
2013 assert(image->signature == MagickSignature);
2014 if (image->debug != MagickFalse)
2015 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2016 assert(exception != (ExceptionInfo *) NULL);
2017 assert(exception->signature == MagickSignature);
2018 transpose_image=CloneImage(image,image->rows,image->columns,MagickTrue,
2020 if (transpose_image == (Image *) NULL)
2021 return((Image *) NULL);
2027 image_view=AcquireCacheView(image);
2028 transpose_view=AcquireCacheView(transpose_image);
2029 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2030 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
2032 for (y=0; y < (ssize_t) image->rows; y++)
2034 register const PixelPacket
2037 register IndexPacket
2038 *restrict transpose_indexes,
2041 register PixelPacket
2044 if (status == MagickFalse)
2046 p=GetCacheViewVirtualPixels(image_view,0,(ssize_t) image->rows-y-1,
2047 image->columns,1,exception);
2048 q=QueueCacheViewAuthenticPixels(transpose_view,(ssize_t) (image->rows-y-1),0,
2049 1,transpose_image->rows,exception);
2050 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
2055 (void) CopyMagickMemory(q,p,(size_t) image->columns*sizeof(*q));
2056 indexes=GetCacheViewAuthenticIndexQueue(image_view);
2057 if (indexes != (IndexPacket *) NULL)
2059 transpose_indexes=GetCacheViewAuthenticIndexQueue(transpose_view);
2060 if (transpose_indexes != (IndexPacket *) NULL)
2061 (void) CopyMagickMemory(transpose_indexes,indexes,(size_t)
2062 image->columns*sizeof(*transpose_indexes));
2064 if (SyncCacheViewAuthenticPixels(transpose_view,exception) == MagickFalse)
2066 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2071 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2072 #pragma omp critical (MagickCore_TransposeImage)
2074 proceed=SetImageProgress(image,TransposeImageTag,progress++,
2076 if (proceed == MagickFalse)
2080 transpose_view=DestroyCacheView(transpose_view);
2081 image_view=DestroyCacheView(image_view);
2082 transpose_image->type=image->type;
2083 page=transpose_image->page;
2084 Swap(page.width,page.height);
2085 Swap(page.x,page.y);
2086 if (page.width != 0)
2087 page.x=(ssize_t) (page.width-transpose_image->columns-page.x);
2088 transpose_image->page=page;
2089 if (status == MagickFalse)
2090 transpose_image=DestroyImage(transpose_image);
2091 return(transpose_image);
2095 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2099 % T r a n s v e r s e I m a g e %
2103 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2105 % TransverseImage() creates a vertical mirror image by reflecting the pixels
2106 % around the central x-axis while rotating them by 270 degrees.
2108 % The format of the TransverseImage method is:
2110 % Image *TransverseImage(const Image *image,ExceptionInfo *exception)
2112 % A description of each parameter follows:
2114 % o image: the image.
2116 % o exception: return any errors or warnings in this structure.
2119 MagickExport Image *TransverseImage(const Image *image,ExceptionInfo *exception)
2121 #define TransverseImageTag "Transverse/Image"
2142 assert(image != (const Image *) NULL);
2143 assert(image->signature == MagickSignature);
2144 if (image->debug != MagickFalse)
2145 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2146 assert(exception != (ExceptionInfo *) NULL);
2147 assert(exception->signature == MagickSignature);
2148 transverse_image=CloneImage(image,image->rows,image->columns,MagickTrue,
2150 if (transverse_image == (Image *) NULL)
2151 return((Image *) NULL);
2157 image_view=AcquireCacheView(image);
2158 transverse_view=AcquireCacheView(transverse_image);
2159 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2160 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
2162 for (y=0; y < (ssize_t) image->rows; y++)
2167 register const PixelPacket
2170 register IndexPacket
2171 *restrict transverse_indexes,
2177 register PixelPacket
2180 if (status == MagickFalse)
2182 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2183 q=QueueCacheViewAuthenticPixels(transverse_view,(ssize_t) (image->rows-y-
2184 1),0,1,transverse_image->rows,exception);
2185 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
2191 for (x=0; x < (ssize_t) image->columns; x++)
2193 indexes=GetCacheViewAuthenticIndexQueue(image_view);
2194 if (indexes != (IndexPacket *) NULL)
2196 transverse_indexes=GetCacheViewAuthenticIndexQueue(transverse_view);
2197 if (transverse_indexes != (IndexPacket *) NULL)
2198 for (x=0; x < (ssize_t) image->columns; x++)
2199 transverse_indexes[image->columns-x-1]=indexes[x];
2201 sync=SyncCacheViewAuthenticPixels(transverse_view,exception);
2202 if (sync == MagickFalse)
2204 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2209 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2210 #pragma omp critical (MagickCore_TransverseImage)
2212 proceed=SetImageProgress(image,TransverseImageTag,progress++,
2214 if (proceed == MagickFalse)
2218 transverse_view=DestroyCacheView(transverse_view);
2219 image_view=DestroyCacheView(image_view);
2220 transverse_image->type=image->type;
2221 page=transverse_image->page;
2222 Swap(page.width,page.height);
2223 Swap(page.x,page.y);
2224 if (page.height != 0)
2225 page.y=(ssize_t) (page.height-transverse_image->rows-page.y);
2226 transverse_image->page=page;
2227 if (status == MagickFalse)
2228 transverse_image=DestroyImage(transverse_image);
2229 return(transverse_image);
2233 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2237 % T r i m I m a g e %
2241 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2243 % TrimImage() trims pixels from the image edges. It allocates the memory
2244 % necessary for the new Image structure and returns a pointer to the new
2247 % The format of the TrimImage method is:
2249 % Image *TrimImage(const Image *image,ExceptionInfo *exception)
2251 % A description of each parameter follows:
2253 % o image: the image.
2255 % o exception: return any errors or warnings in this structure.
2258 MagickExport Image *TrimImage(const Image *image,ExceptionInfo *exception)
2263 assert(image != (const Image *) NULL);
2264 assert(image->signature == MagickSignature);
2265 if (image->debug != MagickFalse)
2266 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2267 geometry=GetImageBoundingBox(image,exception);
2268 if ((geometry.width == 0) || (geometry.height == 0))
2273 crop_image=CloneImage(image,1,1,MagickTrue,exception);
2274 if (crop_image == (Image *) NULL)
2275 return((Image *) NULL);
2276 crop_image->background_color.opacity=(Quantum) TransparentOpacity;
2277 (void) SetImageBackgroundColor(crop_image);
2278 crop_image->page=image->page;
2279 crop_image->page.x=(-1);
2280 crop_image->page.y=(-1);
2283 geometry.x+=image->page.x;
2284 geometry.y+=image->page.y;
2285 return(CropImage(image,&geometry,exception));