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)
313 Consolidate separate C, M, Y, and K planes into a single image.
315 assert(images != (Image *) NULL);
316 assert(images->signature == MagickSignature);
317 if (images->debug != MagickFalse)
318 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
319 assert(exception != (ExceptionInfo *) NULL);
320 assert(exception->signature == MagickSignature);
321 cmyk_images=NewImageList();
322 for (i=0; i < (ssize_t) GetImageListLength(images); i+=4)
324 cmyk_image=CloneImage(images,images->columns,images->rows,MagickTrue,
326 if (cmyk_image == (Image *) NULL)
328 if (SetImageStorageClass(cmyk_image,DirectClass) == MagickFalse)
330 (void) SetImageColorspace(cmyk_image,CMYKColorspace);
331 image_view=AcquireCacheView(images);
332 cmyk_view=AcquireCacheView(cmyk_image);
333 for (y=0; y < (ssize_t) images->rows; y++)
335 register const PixelPacket
344 p=GetCacheViewVirtualPixels(image_view,0,y,images->columns,1,exception);
345 q=QueueCacheViewAuthenticPixels(cmyk_view,0,y,cmyk_image->columns,1,
347 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
349 for (x=0; x < (ssize_t) images->columns; x++)
351 q->red=(Quantum) (QuantumRange-PixelIntensityToQuantum(p));
355 if (SyncCacheViewAuthenticPixels(cmyk_view,exception) == MagickFalse)
358 cmyk_view=DestroyCacheView(cmyk_view);
359 image_view=DestroyCacheView(image_view);
360 images=GetNextImageInList(images);
361 if (images == (Image *) NULL)
363 image_view=AcquireCacheView(images);
364 cmyk_view=AcquireCacheView(cmyk_image);
365 for (y=0; y < (ssize_t) images->rows; y++)
367 register const PixelPacket
376 p=GetCacheViewVirtualPixels(image_view,0,y,images->columns,1,exception);
377 q=GetCacheViewAuthenticPixels(cmyk_view,0,y,cmyk_image->columns,1,
379 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
381 for (x=0; x < (ssize_t) images->columns; x++)
383 q->green=(Quantum) (QuantumRange-PixelIntensityToQuantum(p));
387 if (SyncCacheViewAuthenticPixels(cmyk_view,exception) == MagickFalse)
390 cmyk_view=DestroyCacheView(cmyk_view);
391 image_view=DestroyCacheView(image_view);
392 images=GetNextImageInList(images);
393 if (images == (Image *) NULL)
395 image_view=AcquireCacheView(images);
396 cmyk_view=AcquireCacheView(cmyk_image);
397 for (y=0; y < (ssize_t) images->rows; y++)
399 register const PixelPacket
408 p=GetCacheViewVirtualPixels(image_view,0,y,images->columns,1,exception);
409 q=GetCacheViewAuthenticPixels(cmyk_view,0,y,cmyk_image->columns,1,
411 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
413 for (x=0; x < (ssize_t) images->columns; x++)
415 q->blue=(Quantum) (QuantumRange-PixelIntensityToQuantum(p));
419 if (SyncCacheViewAuthenticPixels(cmyk_view,exception) == MagickFalse)
422 cmyk_view=DestroyCacheView(cmyk_view);
423 image_view=DestroyCacheView(image_view);
424 images=GetNextImageInList(images);
425 if (images == (Image *) NULL)
427 image_view=AcquireCacheView(images);
428 cmyk_view=AcquireCacheView(cmyk_image);
429 for (y=0; y < (ssize_t) images->rows; y++)
431 register const PixelPacket
443 p=GetCacheViewVirtualPixels(image_view,0,y,images->columns,1,exception);
444 q=GetCacheViewAuthenticPixels(cmyk_view,0,y,cmyk_image->columns,1,
446 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
448 indexes=GetCacheViewAuthenticIndexQueue(cmyk_view);
449 for (x=0; x < (ssize_t) images->columns; x++)
451 indexes[x]=(IndexPacket) (QuantumRange-PixelIntensityToQuantum(p));
454 if (SyncCacheViewAuthenticPixels(cmyk_view,exception) == MagickFalse)
457 cmyk_view=DestroyCacheView(cmyk_view);
458 image_view=DestroyCacheView(image_view);
459 AppendImageToList(&cmyk_images,cmyk_image);
460 images=GetNextImageInList(images);
461 if (images == (Image *) NULL)
468 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
472 % C r o p I m a g e %
476 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
478 % CropImage() extracts a region of the image starting at the offset defined
481 % The format of the CropImage method is:
483 % Image *CropImage(const Image *image,const RectangleInfo *geometry,
484 % ExceptionInfo *exception)
486 % A description of each parameter follows:
488 % o image: the image.
490 % o geometry: Define the region of the image to crop with members
491 % x, y, width, and height.
493 % o exception: return any errors or warnings in this structure.
496 MagickExport Image *CropImage(const Image *image,const RectangleInfo *geometry,
497 ExceptionInfo *exception)
499 #define CropImageTag "Crop/Image"
524 assert(image != (const Image *) NULL);
525 assert(image->signature == MagickSignature);
526 if (image->debug != MagickFalse)
527 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
528 assert(geometry != (const RectangleInfo *) NULL);
529 assert(exception != (ExceptionInfo *) NULL);
530 assert(exception->signature == MagickSignature);
531 bounding_box=image->page;
532 if ((bounding_box.width == 0) || (bounding_box.height == 0))
534 bounding_box.width=image->columns;
535 bounding_box.height=image->rows;
539 page.width=bounding_box.width;
540 if (page.height == 0)
541 page.height=bounding_box.height;
542 if (((bounding_box.x-page.x) >= (ssize_t) page.width) ||
543 ((bounding_box.y-page.y) >= (ssize_t) page.height) ||
544 ((page.x-bounding_box.x) > (ssize_t) image->columns) ||
545 ((page.y-bounding_box.y) > (ssize_t) image->rows))
548 Crop is not within virtual canvas, return 1 pixel transparent image.
550 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
551 "GeometryDoesNotContainImage","`%s'",image->filename);
552 crop_image=CloneImage(image,1,1,MagickTrue,exception);
553 if (crop_image == (Image *) NULL)
554 return((Image *) NULL);
555 crop_image->background_color.opacity=(Quantum) TransparentOpacity;
556 (void) SetImageBackgroundColor(crop_image);
557 crop_image->page=bounding_box;
558 crop_image->page.x=(-1);
559 crop_image->page.y=(-1);
560 if (crop_image->dispose == BackgroundDispose)
561 crop_image->dispose=NoneDispose;
564 if ((page.x < 0) && (bounding_box.x >= 0))
566 page.width+=page.x-bounding_box.x;
571 page.width-=bounding_box.x-page.x;
572 page.x-=bounding_box.x;
576 if ((page.y < 0) && (bounding_box.y >= 0))
578 page.height+=page.y-bounding_box.y;
583 page.height-=bounding_box.y-page.y;
584 page.y-=bounding_box.y;
588 if ((size_t) (page.x+page.width) > image->columns)
589 page.width=image->columns-page.x;
590 if ((geometry->width != 0) && (page.width > geometry->width))
591 page.width=geometry->width;
592 if ((size_t) (page.y+page.height) > image->rows)
593 page.height=image->rows-page.y;
594 if ((geometry->height != 0) && (page.height > geometry->height))
595 page.height=geometry->height;
596 bounding_box.x+=page.x;
597 bounding_box.y+=page.y;
598 if ((page.width == 0) || (page.height == 0))
600 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
601 "GeometryDoesNotContainImage","`%s'",image->filename);
602 return((Image *) NULL);
605 Initialize crop image attributes.
607 crop_image=CloneImage(image,page.width,page.height,MagickTrue,exception);
608 if (crop_image == (Image *) NULL)
609 return((Image *) NULL);
610 crop_image->page.width=image->page.width;
611 crop_image->page.height=image->page.height;
612 if (((ssize_t) (bounding_box.x+bounding_box.width) > (ssize_t) image->page.width) ||
613 ((ssize_t) (bounding_box.y+bounding_box.height) > (ssize_t) image->page.height))
615 crop_image->page.width=bounding_box.width;
616 crop_image->page.height=bounding_box.height;
618 crop_image->page.x=bounding_box.x;
619 crop_image->page.y=bounding_box.y;
625 image_view=AcquireCacheView(image);
626 crop_view=AcquireCacheView(crop_image);
627 #if defined(MAGICKCORE_OPENMP_SUPPORT)
628 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
630 for (y=0; y < (ssize_t) crop_image->rows; y++)
632 register const IndexPacket
635 register const PixelPacket
639 *restrict crop_indexes;
644 if (status == MagickFalse)
646 p=GetCacheViewVirtualPixels(image_view,page.x,page.y+y,crop_image->columns,
648 q=QueueCacheViewAuthenticPixels(crop_view,0,y,crop_image->columns,1,
650 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
655 indexes=GetCacheViewVirtualIndexQueue(image_view);
656 crop_indexes=GetCacheViewAuthenticIndexQueue(crop_view);
657 (void) CopyMagickMemory(q,p,(size_t) crop_image->columns*sizeof(*p));
658 if ((indexes != (IndexPacket *) NULL) &&
659 (crop_indexes != (IndexPacket *) NULL))
660 (void) CopyMagickMemory(crop_indexes,indexes,(size_t) crop_image->columns*
661 sizeof(*crop_indexes));
662 if (SyncCacheViewAuthenticPixels(crop_view,exception) == MagickFalse)
664 if (image->progress_monitor != (MagickProgressMonitor) NULL)
669 #if defined(MAGICKCORE_OPENMP_SUPPORT)
670 #pragma omp critical (MagickCore_CropImage)
672 proceed=SetImageProgress(image,CropImageTag,progress++,image->rows);
673 if (proceed == MagickFalse)
677 crop_view=DestroyCacheView(crop_view);
678 image_view=DestroyCacheView(image_view);
679 crop_image->type=image->type;
680 if (status == MagickFalse)
681 crop_image=DestroyImage(crop_image);
686 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
690 % E x c e r p t I m a g e %
694 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
696 % ExcerptImage() returns a excerpt of the image as defined by the geometry.
698 % The format of the ExcerptImage method is:
700 % Image *ExcerptImage(const Image *image,const RectangleInfo *geometry,
701 % ExceptionInfo *exception)
703 % A description of each parameter follows:
705 % o image: the image.
707 % o geometry: Define the region of the image to extend with members
708 % x, y, width, and height.
710 % o exception: return any errors or warnings in this structure.
713 MagickExport Image *ExcerptImage(const Image *image,
714 const RectangleInfo *geometry,ExceptionInfo *exception)
716 #define ExcerptImageTag "Excerpt/Image"
735 Allocate excerpt image.
737 assert(image != (const Image *) NULL);
738 assert(image->signature == MagickSignature);
739 if (image->debug != MagickFalse)
740 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
741 assert(geometry != (const RectangleInfo *) NULL);
742 assert(exception != (ExceptionInfo *) NULL);
743 assert(exception->signature == MagickSignature);
744 excerpt_image=CloneImage(image,geometry->width,geometry->height,MagickTrue,
746 if (excerpt_image == (Image *) NULL)
747 return((Image *) NULL);
753 image_view=AcquireCacheView(image);
754 excerpt_view=AcquireCacheView(excerpt_image);
755 #if defined(MAGICKCORE_OPENMP_SUPPORT)
756 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
758 for (y=0; y < (ssize_t) excerpt_image->rows; y++)
760 register const PixelPacket
764 *restrict excerpt_indexes,
770 if (status == MagickFalse)
772 p=GetCacheViewVirtualPixels(image_view,geometry->x,geometry->y+y,
773 geometry->width,1,exception);
774 q=GetCacheViewAuthenticPixels(excerpt_view,0,y,excerpt_image->columns,1,
776 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
781 (void) CopyMagickMemory(q,p,(size_t) excerpt_image->columns*sizeof(*q));
782 indexes=GetCacheViewAuthenticIndexQueue(image_view);
783 if (indexes != (IndexPacket *) NULL)
785 excerpt_indexes=GetCacheViewAuthenticIndexQueue(excerpt_view);
786 if (excerpt_indexes != (IndexPacket *) NULL)
787 (void) CopyMagickMemory(excerpt_indexes,indexes,(size_t)
788 excerpt_image->columns*sizeof(*excerpt_indexes));
790 if (SyncCacheViewAuthenticPixels(excerpt_view,exception) == MagickFalse)
792 if (image->progress_monitor != (MagickProgressMonitor) NULL)
797 #if defined(MAGICKCORE_OPENMP_SUPPORT)
798 #pragma omp critical (MagickCore_ExcerptImage)
800 proceed=SetImageProgress(image,ExcerptImageTag,progress++,image->rows);
801 if (proceed == MagickFalse)
805 excerpt_view=DestroyCacheView(excerpt_view);
806 image_view=DestroyCacheView(image_view);
807 excerpt_image->type=image->type;
808 if (status == MagickFalse)
809 excerpt_image=DestroyImage(excerpt_image);
810 return(excerpt_image);
814 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
818 % E x t e n t I m a g e %
822 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
824 % ExtentImage() extends the image as defined by the geometry, gravity, and
825 % image background color. Set the (x,y) offset of the geometry to move the
826 % original image relative to the extended image.
828 % The format of the ExtentImage method is:
830 % Image *ExtentImage(const Image *image,const RectangleInfo *geometry,
831 % ExceptionInfo *exception)
833 % A description of each parameter follows:
835 % o image: the image.
837 % o geometry: Define the region of the image to extend with members
838 % x, y, width, and height.
840 % o exception: return any errors or warnings in this structure.
843 MagickExport Image *ExtentImage(const Image *image,
844 const RectangleInfo *geometry,ExceptionInfo *exception)
850 Allocate extent image.
852 assert(image != (const Image *) NULL);
853 assert(image->signature == MagickSignature);
854 if (image->debug != MagickFalse)
855 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
856 assert(geometry != (const RectangleInfo *) NULL);
857 assert(exception != (ExceptionInfo *) NULL);
858 assert(exception->signature == MagickSignature);
859 extent_image=CloneImage(image,geometry->width,geometry->height,MagickTrue,
861 if (extent_image == (Image *) NULL)
862 return((Image *) NULL);
863 if (SetImageStorageClass(extent_image,DirectClass) == MagickFalse)
865 InheritException(exception,&extent_image->exception);
866 extent_image=DestroyImage(extent_image);
867 return((Image *) NULL);
869 if (extent_image->background_color.opacity != OpaqueOpacity)
870 extent_image->matte=MagickTrue;
871 (void) SetImageBackgroundColor(extent_image);
872 (void) CompositeImage(extent_image,image->compose,image,-geometry->x,
874 return(extent_image);
878 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
882 % F l i p I m a g e %
886 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
888 % FlipImage() creates a vertical mirror image by reflecting the pixels
889 % around the central x-axis.
891 % The format of the FlipImage method is:
893 % Image *FlipImage(const Image *image,ExceptionInfo *exception)
895 % A description of each parameter follows:
897 % o image: the image.
899 % o exception: return any errors or warnings in this structure.
902 MagickExport Image *FlipImage(const Image *image,ExceptionInfo *exception)
904 #define FlipImageTag "Flip/Image"
922 assert(image != (const Image *) NULL);
923 assert(image->signature == MagickSignature);
924 if (image->debug != MagickFalse)
925 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
926 assert(exception != (ExceptionInfo *) NULL);
927 assert(exception->signature == MagickSignature);
928 flip_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
929 if (flip_image == (Image *) NULL)
930 return((Image *) NULL);
936 image_view=AcquireCacheView(image);
937 flip_view=AcquireCacheView(flip_image);
938 #if defined(MAGICKCORE_OPENMP_SUPPORT)
939 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
941 for (y=0; y < (ssize_t) flip_image->rows; y++)
943 register const IndexPacket
946 register const PixelPacket
950 *restrict flip_indexes;
955 if (status == MagickFalse)
957 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
958 q=QueueCacheViewAuthenticPixels(flip_view,0,(ssize_t) (flip_image->rows-y-
959 1),flip_image->columns,1,exception);
960 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
965 (void) CopyMagickMemory(q,p,(size_t) image->columns*sizeof(*q));
966 indexes=GetCacheViewVirtualIndexQueue(image_view);
967 if (indexes != (const IndexPacket *) NULL)
969 flip_indexes=GetCacheViewAuthenticIndexQueue(flip_view);
970 if (flip_indexes != (IndexPacket *) NULL)
971 (void) CopyMagickMemory(flip_indexes,indexes,(size_t) image->columns*
972 sizeof(*flip_indexes));
974 if (SyncCacheViewAuthenticPixels(flip_view,exception) == MagickFalse)
976 if (image->progress_monitor != (MagickProgressMonitor) NULL)
981 #if defined(MAGICKCORE_OPENMP_SUPPORT)
982 #pragma omp critical (MagickCore_FlipImage)
984 proceed=SetImageProgress(image,FlipImageTag,progress++,image->rows);
985 if (proceed == MagickFalse)
989 flip_view=DestroyCacheView(flip_view);
990 image_view=DestroyCacheView(image_view);
991 flip_image->type=image->type;
992 if (status == MagickFalse)
993 flip_image=DestroyImage(flip_image);
998 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1002 % F l o p I m a g e %
1006 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1008 % FlopImage() creates a horizontal mirror image by reflecting the pixels
1009 % around the central y-axis.
1011 % The format of the FlopImage method is:
1013 % Image *FlopImage(const Image *image,ExceptionInfo *exception)
1015 % A description of each parameter follows:
1017 % o image: the image.
1019 % o exception: return any errors or warnings in this structure.
1022 MagickExport Image *FlopImage(const Image *image,ExceptionInfo *exception)
1024 #define FlopImageTag "Flop/Image"
1042 assert(image != (const Image *) NULL);
1043 assert(image->signature == MagickSignature);
1044 if (image->debug != MagickFalse)
1045 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1046 assert(exception != (ExceptionInfo *) NULL);
1047 assert(exception->signature == MagickSignature);
1048 flop_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
1049 if (flop_image == (Image *) NULL)
1050 return((Image *) NULL);
1056 image_view=AcquireCacheView(image);
1057 flop_view=AcquireCacheView(flop_image);
1058 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1059 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
1061 for (y=0; y < (ssize_t) flop_image->rows; y++)
1063 register const IndexPacket
1066 register const PixelPacket
1069 register IndexPacket
1070 *restrict flop_indexes;
1075 register PixelPacket
1078 if (status == MagickFalse)
1080 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1081 q=QueueCacheViewAuthenticPixels(flop_view,0,y,flop_image->columns,1,
1083 if ((p == (PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
1088 q+=flop_image->columns;
1089 indexes=GetCacheViewVirtualIndexQueue(image_view);
1090 flop_indexes=GetCacheViewAuthenticIndexQueue(flop_view);
1091 for (x=0; x < (ssize_t) flop_image->columns; x++)
1094 if ((indexes != (const IndexPacket *) NULL) &&
1095 (flop_indexes != (IndexPacket *) NULL))
1096 flop_indexes[flop_image->columns-x-1]=indexes[x];
1098 if (SyncCacheViewAuthenticPixels(flop_view,exception) == MagickFalse)
1100 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1105 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1106 #pragma omp critical (MagickCore_FlopImage)
1108 proceed=SetImageProgress(image,FlopImageTag,progress++,image->rows);
1109 if (proceed == MagickFalse)
1113 flop_view=DestroyCacheView(flop_view);
1114 image_view=DestroyCacheView(image_view);
1115 flop_image->type=image->type;
1116 if (status == MagickFalse)
1117 flop_image=DestroyImage(flop_image);
1122 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1126 % R o l l I m a g e %
1130 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1132 % RollImage() offsets an image as defined by x_offset and y_offset.
1134 % The format of the RollImage method is:
1136 % Image *RollImage(const Image *image,const ssize_t x_offset,
1137 % const ssize_t y_offset,ExceptionInfo *exception)
1139 % A description of each parameter follows:
1141 % o image: the image.
1143 % o x_offset: the number of columns to roll in the horizontal direction.
1145 % o y_offset: the number of rows to roll in the vertical direction.
1147 % o exception: return any errors or warnings in this structure.
1151 static inline MagickBooleanType CopyImageRegion(Image *destination,
1152 const Image *source,const size_t columns,const size_t rows,
1153 const ssize_t sx,const ssize_t sy,const ssize_t dx,const ssize_t dy,
1154 ExceptionInfo *exception)
1167 source_view=AcquireCacheView(source);
1168 destination_view=AcquireCacheView(destination);
1169 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1170 #pragma omp parallel for schedule(dynamic,4) shared(status)
1172 for (y=0; y < (ssize_t) rows; y++)
1177 register const IndexPacket
1180 register const PixelPacket
1183 register IndexPacket
1184 *restrict destination_indexes;
1186 register PixelPacket
1192 if (status == MagickFalse)
1194 p=GetCacheViewVirtualPixels(source_view,sx,sy+y,columns,1,exception);
1195 q=GetCacheViewAuthenticPixels(destination_view,dx,dy+y,columns,1,exception);
1196 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
1201 indexes=GetCacheViewVirtualIndexQueue(source_view);
1202 (void) CopyMagickMemory(q,p,(size_t) columns*sizeof(*p));
1203 if (indexes != (IndexPacket *) NULL)
1205 destination_indexes=GetCacheViewAuthenticIndexQueue(destination_view);
1206 if (destination_indexes != (IndexPacket *) NULL)
1207 (void) CopyMagickMemory(destination_indexes,indexes,(size_t)
1208 columns*sizeof(*indexes));
1210 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
1211 if (sync == MagickFalse)
1214 destination_view=DestroyCacheView(destination_view);
1215 source_view=DestroyCacheView(source_view);
1219 MagickExport Image *RollImage(const Image *image,const ssize_t x_offset,
1220 const ssize_t y_offset,ExceptionInfo *exception)
1222 #define RollImageTag "Roll/Image"
1234 Initialize roll image attributes.
1236 assert(image != (const Image *) NULL);
1237 assert(image->signature == MagickSignature);
1238 if (image->debug != MagickFalse)
1239 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1240 assert(exception != (ExceptionInfo *) NULL);
1241 assert(exception->signature == MagickSignature);
1242 roll_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
1243 if (roll_image == (Image *) NULL)
1244 return((Image *) NULL);
1247 while (offset.x < 0)
1248 offset.x+=(ssize_t) image->columns;
1249 while (offset.x >= (ssize_t) image->columns)
1250 offset.x-=(ssize_t) image->columns;
1251 while (offset.y < 0)
1252 offset.y+=(ssize_t) image->rows;
1253 while (offset.y >= (ssize_t) image->rows)
1254 offset.y-=(ssize_t) image->rows;
1258 status=CopyImageRegion(roll_image,image,(size_t) offset.x,
1259 (size_t) offset.y,(ssize_t) image->columns-offset.x,(ssize_t) image->rows-
1260 offset.y,0,0,exception);
1261 (void) SetImageProgress(image,RollImageTag,0,3);
1262 status|=CopyImageRegion(roll_image,image,image->columns-offset.x,
1263 (size_t) offset.y,0,(ssize_t) image->rows-offset.y,offset.x,0,
1265 (void) SetImageProgress(image,RollImageTag,1,3);
1266 status|=CopyImageRegion(roll_image,image,(size_t) offset.x,image->rows-
1267 offset.y,(ssize_t) image->columns-offset.x,0,0,offset.y,exception);
1268 (void) SetImageProgress(image,RollImageTag,2,3);
1269 status|=CopyImageRegion(roll_image,image,image->columns-offset.x,image->rows-
1270 offset.y,0,0,offset.x,offset.y,exception);
1271 (void) SetImageProgress(image,RollImageTag,3,3);
1272 roll_image->type=image->type;
1273 if (status == MagickFalse)
1274 roll_image=DestroyImage(roll_image);
1279 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1283 % S h a v e I m a g e %
1287 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1289 % ShaveImage() shaves pixels from the image edges. It allocates the memory
1290 % necessary for the new Image structure and returns a pointer to the new
1293 % The format of the ShaveImage method is:
1295 % Image *ShaveImage(const Image *image,const RectangleInfo *shave_info,
1296 % ExceptionInfo *exception)
1298 % A description of each parameter follows:
1300 % o shave_image: Method ShaveImage returns a pointer to the shaved
1301 % image. A null image is returned if there is a memory shortage or
1302 % if the image width or height is zero.
1304 % o image: the image.
1306 % o shave_info: Specifies a pointer to a RectangleInfo which defines the
1307 % region of the image to crop.
1309 % o exception: return any errors or warnings in this structure.
1312 MagickExport Image *ShaveImage(const Image *image,
1313 const RectangleInfo *shave_info,ExceptionInfo *exception)
1321 assert(image != (const Image *) NULL);
1322 assert(image->signature == MagickSignature);
1323 if (image->debug != MagickFalse)
1324 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1325 if (((2*shave_info->width) >= image->columns) ||
1326 ((2*shave_info->height) >= image->rows))
1327 ThrowImageException(OptionWarning,"GeometryDoesNotContainImage");
1328 SetGeometry(image,&geometry);
1329 geometry.width-=2*shave_info->width;
1330 geometry.height-=2*shave_info->height;
1331 geometry.x=(ssize_t) shave_info->width+image->page.x;
1332 geometry.y=(ssize_t) shave_info->height+image->page.y;
1333 shave_image=CropImage(image,&geometry,exception);
1334 if (shave_image == (Image *) NULL)
1335 return((Image *) NULL);
1336 shave_image->page.width-=2*shave_info->width;
1337 shave_image->page.height-=2*shave_info->height;
1338 shave_image->page.x-=(ssize_t) shave_info->width;
1339 shave_image->page.y-=(ssize_t) shave_info->height;
1340 return(shave_image);
1344 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1348 % S p l i c e I m a g e %
1352 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1354 % SpliceImage() splices a solid color into the image as defined by the
1357 % The format of the SpliceImage method is:
1359 % Image *SpliceImage(const Image *image,const RectangleInfo *geometry,
1360 % ExceptionInfo *exception)
1362 % A description of each parameter follows:
1364 % o image: the image.
1366 % o geometry: Define the region of the image to splice with members
1367 % x, y, width, and height.
1369 % o exception: return any errors or warnings in this structure.
1372 MagickExport Image *SpliceImage(const Image *image,
1373 const RectangleInfo *geometry,ExceptionInfo *exception)
1375 #define SpliceImageTag "Splice/Image"
1401 Allocate splice image.
1403 assert(image != (const Image *) NULL);
1404 assert(image->signature == MagickSignature);
1405 if (image->debug != MagickFalse)
1406 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1407 assert(geometry != (const RectangleInfo *) NULL);
1408 assert(exception != (ExceptionInfo *) NULL);
1409 assert(exception->signature == MagickSignature);
1410 splice_geometry=(*geometry);
1411 splice_image=CloneImage(image,image->columns+splice_geometry.width,
1412 image->rows+splice_geometry.height,MagickTrue,exception);
1413 if (splice_image == (Image *) NULL)
1414 return((Image *) NULL);
1415 if (SetImageStorageClass(splice_image,DirectClass) == MagickFalse)
1417 InheritException(exception,&splice_image->exception);
1418 splice_image=DestroyImage(splice_image);
1419 return((Image *) NULL);
1421 (void) SetImageBackgroundColor(splice_image);
1423 Respect image geometry.
1425 switch (image->gravity)
1428 case UndefinedGravity:
1429 case NorthWestGravity:
1433 splice_geometry.x+=(ssize_t) splice_geometry.width/2;
1436 case NorthEastGravity:
1438 splice_geometry.x+=(ssize_t) splice_geometry.width;
1443 splice_geometry.y+=(ssize_t) splice_geometry.width/2;
1449 splice_geometry.x+=(ssize_t) splice_geometry.width/2;
1450 splice_geometry.y+=(ssize_t) splice_geometry.height/2;
1455 splice_geometry.x+=(ssize_t) splice_geometry.width;
1456 splice_geometry.y+=(ssize_t) splice_geometry.height/2;
1459 case SouthWestGravity:
1461 splice_geometry.y+=(ssize_t) splice_geometry.height;
1466 splice_geometry.x+=(ssize_t) splice_geometry.width/2;
1467 splice_geometry.y+=(ssize_t) splice_geometry.height;
1470 case SouthEastGravity:
1472 splice_geometry.x+=(ssize_t) splice_geometry.width;
1473 splice_geometry.y+=(ssize_t) splice_geometry.height;
1483 image_view=AcquireCacheView(image);
1484 splice_view=AcquireCacheView(splice_image);
1485 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1486 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
1488 for (y=0; y < (ssize_t) splice_geometry.y; y++)
1490 register const PixelPacket
1493 register IndexPacket
1495 *restrict splice_indexes;
1500 register PixelPacket
1503 if (status == MagickFalse)
1505 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1506 q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1,
1508 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
1513 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1514 splice_indexes=GetCacheViewAuthenticIndexQueue(splice_view);
1515 for (x=0; x < splice_geometry.x; x++)
1517 SetRedPixelComponent(q,GetRedPixelComponent(p));
1518 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
1519 SetBluePixelComponent(q,GetBluePixelComponent(p));
1520 SetOpacityPixelComponent(q,OpaqueOpacity);
1521 if (image->matte != MagickFalse)
1522 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
1523 if (image->colorspace == CMYKColorspace)
1524 splice_indexes[x]=(*indexes++);
1528 for ( ; x < (ssize_t) (splice_geometry.x+splice_geometry.width); x++)
1530 for ( ; x < (ssize_t) splice_image->columns; x++)
1532 SetRedPixelComponent(q,GetRedPixelComponent(p));
1533 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
1534 SetBluePixelComponent(q,GetBluePixelComponent(p));
1535 SetOpacityPixelComponent(q,OpaqueOpacity);
1536 if (image->matte != MagickFalse)
1537 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
1538 if (image->colorspace == CMYKColorspace)
1539 splice_indexes[x]=(*indexes++);
1543 if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse)
1545 proceed=SetImageProgress(image,SpliceImageTag,(MagickOffsetType) y,
1546 splice_image->rows);
1547 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1552 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1553 #pragma omp critical (MagickCore_TransposeImage)
1555 proceed=SetImageProgress(image,SpliceImageTag,progress++,
1556 splice_image->rows);
1557 if (proceed == MagickFalse)
1561 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1562 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
1564 for (y=(ssize_t) (splice_geometry.y+splice_geometry.height);
1565 y < (ssize_t) splice_image->rows; y++)
1567 register const PixelPacket
1570 register IndexPacket
1572 *restrict splice_indexes;
1577 register PixelPacket
1580 if (status == MagickFalse)
1582 p=GetCacheViewVirtualPixels(image_view,0,y-(ssize_t) splice_geometry.height,
1583 image->columns,1,exception);
1584 q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1,
1586 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
1591 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1592 splice_indexes=GetCacheViewAuthenticIndexQueue(splice_view);
1593 for (x=0; x < splice_geometry.x; x++)
1595 SetRedPixelComponent(q,GetRedPixelComponent(p));
1596 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
1597 SetBluePixelComponent(q,GetBluePixelComponent(p));
1598 SetOpacityPixelComponent(q,OpaqueOpacity);
1599 if (image->matte != MagickFalse)
1600 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
1601 if (image->colorspace == CMYKColorspace)
1602 splice_indexes[x]=(*indexes++);
1606 for ( ; x < (ssize_t) (splice_geometry.x+splice_geometry.width); x++)
1608 for ( ; x < (ssize_t) splice_image->columns; x++)
1610 SetRedPixelComponent(q,GetRedPixelComponent(p));
1611 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
1612 SetBluePixelComponent(q,GetBluePixelComponent(p));
1613 SetOpacityPixelComponent(q,OpaqueOpacity);
1614 if (image->matte != MagickFalse)
1615 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
1616 if (image->colorspace == CMYKColorspace)
1617 splice_indexes[x]=(*indexes++);
1621 if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse)
1623 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1628 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1629 #pragma omp critical (MagickCore_TransposeImage)
1631 proceed=SetImageProgress(image,SpliceImageTag,progress++,
1632 splice_image->rows);
1633 if (proceed == MagickFalse)
1637 splice_view=DestroyCacheView(splice_view);
1638 image_view=DestroyCacheView(image_view);
1639 if (status == MagickFalse)
1640 splice_image=DestroyImage(splice_image);
1641 return(splice_image);
1645 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1649 % T r a n s f o r m I m a g e %
1653 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1655 % TransformImage() is a convenience method that behaves like ResizeImage() or
1656 % CropImage() but accepts scaling and/or cropping information as a region
1657 % geometry specification. If the operation fails, the original image handle
1660 % The format of the TransformImage method is:
1662 % MagickBooleanType TransformImage(Image **image,const char *crop_geometry,
1663 % const char *image_geometry)
1665 % A description of each parameter follows:
1667 % o image: the image The transformed image is returned as this parameter.
1669 % o crop_geometry: A crop geometry string. This geometry defines a
1670 % subregion of the image to crop.
1672 % o image_geometry: An image geometry string. This geometry defines the
1673 % final size of the image.
1676 static inline ssize_t MagickRound(MagickRealType x)
1679 Round the fraction to nearest integer.
1682 return((ssize_t) (x+0.5));
1683 return((ssize_t) (x-0.5));
1686 MagickExport MagickBooleanType TransformImage(Image **image,
1687 const char *crop_geometry,const char *image_geometry)
1708 assert(image != (Image **) NULL);
1709 assert((*image)->signature == MagickSignature);
1710 if ((*image)->debug != MagickFalse)
1711 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
1712 transform_image=(*image);
1713 if (crop_geometry != (const char *) NULL)
1722 Crop image to a user specified size.
1724 crop_image=NewImageList();
1725 flags=ParseGravityGeometry(transform_image,crop_geometry,&geometry,
1726 &(*image)->exception);
1727 if ((flags & AreaValue) != 0)
1737 Crop into NxM tiles (@ flag) - AT.
1739 if (geometry.width == 0)
1741 if (geometry.height == 0)
1743 width=transform_image->columns;
1744 height=transform_image->rows;
1745 if ((flags & AspectValue) == 0)
1747 width-=(geometry.x < 0 ? -1 : 1)*geometry.x;
1748 height-=(geometry.y < 0 ? -1 : 1)*geometry.y;
1752 width+=(geometry.x < 0 ? -1 : 1)*geometry.x;
1753 height+=(geometry.y < 0 ? -1 : 1)*geometry.y;
1755 delta.x=(double) width/geometry.width;
1756 delta.y=(double) height/geometry.height;
1757 next=NewImageList();
1758 for (offset.y=0; offset.y < (double) height; )
1760 if ((flags & AspectValue) == 0)
1762 crop.y=(ssize_t) MagickRound((MagickRealType) (offset.y-
1763 (geometry.y > 0 ? 0 : geometry.y)));
1765 crop.height=(size_t) MagickRound((MagickRealType)
1766 (offset.y+(geometry.y < 0 ? 0 : geometry.y)));
1770 crop.y=(ssize_t) MagickRound((MagickRealType) (offset.y-
1771 (geometry.y > 0 ? geometry.y : 0)));
1773 crop.height=(size_t) MagickRound((MagickRealType)
1774 (offset.y+(geometry.y < 0 ? geometry.y : 0)));
1776 crop.height-=crop.y;
1777 crop.y+=transform_image->page.y;
1778 for (offset.x=0; offset.x < (double) width; )
1780 if ((flags & AspectValue) == 0)
1782 crop.x=(ssize_t) MagickRound((MagickRealType) (offset.x-
1783 (geometry.x > 0 ? 0 : geometry.x)));
1785 crop.width=(size_t) MagickRound((MagickRealType)
1786 (offset.x+(geometry.x < 0 ? 0 : geometry.x)));
1790 crop.x=(ssize_t) MagickRound((MagickRealType) (offset.x-
1791 (geometry.x > 0 ? geometry.x : 0)));
1793 crop.width=(size_t) MagickRound((MagickRealType)
1794 (offset.x+(geometry.x < 0 ? geometry.x : 0)));
1797 crop.x+=transform_image->page.x;
1798 next=CropImage(transform_image,&crop,&(*image)->exception);
1799 if (next == (Image *) NULL)
1801 AppendImageToList(&crop_image,next);
1803 if (next == (Image *) NULL)
1808 if (((geometry.width == 0) && (geometry.height == 0)) ||
1809 ((flags & XValue) != 0) || ((flags & YValue) != 0))
1812 Crop a single region at +X+Y.
1814 crop_image=CropImage(transform_image,&geometry,
1815 &(*image)->exception);
1816 if ((crop_image != (Image *) NULL) && ((flags & AspectValue) != 0))
1818 crop_image->page.width=geometry.width;
1819 crop_image->page.height=geometry.height;
1820 crop_image->page.x-=geometry.x;
1821 crop_image->page.y-=geometry.y;
1825 if ((transform_image->columns > geometry.width) ||
1826 (transform_image->rows > geometry.height))
1831 MagickProgressMonitor
1841 Crop into tiles of fixed size WxH.
1843 if (transform_image->page.width == 0)
1844 transform_image->page.width=transform_image->columns;
1845 if (transform_image->page.height == 0)
1846 transform_image->page.height=transform_image->rows;
1847 width=geometry.width;
1849 width=transform_image->page.width;
1850 height=geometry.height;
1852 height=transform_image->page.height;
1853 next=NewImageList();
1857 for (y=0; y < (ssize_t) transform_image->page.height; y+=(ssize_t) height)
1858 for (x=0; x < (ssize_t) transform_image->page.width; x+=(ssize_t) width)
1860 for (y=0; y < (ssize_t) transform_image->page.height; y+=(ssize_t) height)
1862 for (x=0; x < (ssize_t) transform_image->page.width; x+=(ssize_t) width)
1864 progress_monitor=SetImageProgressMonitor(transform_image,
1865 (MagickProgressMonitor) NULL,transform_image->client_data);
1866 geometry.width=width;
1867 geometry.height=height;
1870 next=CropImage(transform_image,&geometry,&(*image)->exception);
1871 (void) SetImageProgressMonitor(transform_image,
1872 progress_monitor,transform_image->client_data);
1873 proceed=SetImageProgress(transform_image,CropImageTag,i++,
1875 if (proceed == MagickFalse)
1877 if (next == (Image *) NULL)
1879 (void) SetImageProgressMonitor(next,progress_monitor,
1881 if (crop_image == (Image *) NULL)
1885 next->previous=crop_image;
1886 crop_image->next=next;
1887 crop_image=crop_image->next;
1890 if (next == (Image *) NULL)
1892 if (proceed == MagickFalse)
1896 if (crop_image == (Image *) NULL)
1897 transform_image=CloneImage(*image,0,0,MagickTrue,&(*image)->exception);
1900 transform_image=DestroyImage(transform_image);
1901 transform_image=GetFirstImageInList(crop_image);
1903 *image=transform_image;
1905 if (image_geometry == (const char *) NULL)
1908 Scale image to a user specified size.
1910 flags=ParseRegionGeometry(transform_image,image_geometry,&geometry,
1911 &(*image)->exception);
1912 if ((transform_image->columns == geometry.width) &&
1913 (transform_image->rows == geometry.height))
1915 resize_image=ResizeImage(transform_image,geometry.width,geometry.height,
1916 transform_image->filter,transform_image->blur,&(*image)->exception);
1917 if (resize_image == (Image *) NULL)
1918 return(MagickFalse);
1919 transform_image=DestroyImage(transform_image);
1920 transform_image=resize_image;
1921 *image=transform_image;
1926 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1930 % T r a n s f o r m I m a g e s %
1933 % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1935 % TransformImages() calls TransformImage() on each image of a sequence.
1937 % The format of the TransformImage method is:
1939 % MagickBooleanType TransformImages(Image **image,
1940 % const char *crop_geometry,const char *image_geometry)
1942 % A description of each parameter follows:
1944 % o image: the image The transformed image is returned as this parameter.
1946 % o crop_geometry: A crop geometry string. This geometry defines a
1947 % subregion of the image to crop.
1949 % o image_geometry: An image geometry string. This geometry defines the
1950 % final size of the image.
1953 MagickExport MagickBooleanType TransformImages(Image **images,
1954 const char *crop_geometry,const char *image_geometry)
1967 assert(images != (Image **) NULL);
1968 assert((*images)->signature == MagickSignature);
1969 if ((*images)->debug != MagickFalse)
1970 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1971 (*images)->filename);
1972 image_list=ImageListToArray(*images,&(*images)->exception);
1973 if (image_list == (Image **) NULL)
1974 return(MagickFalse);
1976 transform_images=NewImageList();
1977 for (i=0; image_list[i] != (Image *) NULL; i++)
1979 image=image_list[i];
1980 status|=TransformImage(&image,crop_geometry,image_geometry);
1981 AppendImageToList(&transform_images,image);
1983 *images=transform_images;
1984 image_list=(Image **) RelinquishMagickMemory(image_list);
1985 return(status != 0 ? MagickTrue : MagickFalse);
1989 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1993 % T r a n s p o s e I m a g e %
1997 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1999 % TransposeImage() creates a horizontal mirror image by reflecting the pixels
2000 % around the central y-axis while rotating them by 90 degrees.
2002 % The format of the TransposeImage method is:
2004 % Image *TransposeImage(const Image *image,ExceptionInfo *exception)
2006 % A description of each parameter follows:
2008 % o image: the image.
2010 % o exception: return any errors or warnings in this structure.
2013 MagickExport Image *TransposeImage(const Image *image,ExceptionInfo *exception)
2015 #define TransposeImageTag "Transpose/Image"
2036 assert(image != (const Image *) NULL);
2037 assert(image->signature == MagickSignature);
2038 if (image->debug != MagickFalse)
2039 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2040 assert(exception != (ExceptionInfo *) NULL);
2041 assert(exception->signature == MagickSignature);
2042 transpose_image=CloneImage(image,image->rows,image->columns,MagickTrue,
2044 if (transpose_image == (Image *) NULL)
2045 return((Image *) NULL);
2051 image_view=AcquireCacheView(image);
2052 transpose_view=AcquireCacheView(transpose_image);
2053 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2054 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
2056 for (y=0; y < (ssize_t) image->rows; y++)
2058 register const PixelPacket
2061 register IndexPacket
2062 *restrict transpose_indexes,
2065 register PixelPacket
2068 if (status == MagickFalse)
2070 p=GetCacheViewVirtualPixels(image_view,0,(ssize_t) image->rows-y-1,
2071 image->columns,1,exception);
2072 q=QueueCacheViewAuthenticPixels(transpose_view,(ssize_t) (image->rows-y-1),
2073 0,1,transpose_image->rows,exception);
2074 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
2079 (void) CopyMagickMemory(q,p,(size_t) image->columns*sizeof(*q));
2080 indexes=GetCacheViewAuthenticIndexQueue(image_view);
2081 if (indexes != (IndexPacket *) NULL)
2083 transpose_indexes=GetCacheViewAuthenticIndexQueue(transpose_view);
2084 if (transpose_indexes != (IndexPacket *) NULL)
2085 (void) CopyMagickMemory(transpose_indexes,indexes,(size_t)
2086 image->columns*sizeof(*transpose_indexes));
2088 if (SyncCacheViewAuthenticPixels(transpose_view,exception) == MagickFalse)
2090 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2095 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2096 #pragma omp critical (MagickCore_TransposeImage)
2098 proceed=SetImageProgress(image,TransposeImageTag,progress++,
2100 if (proceed == MagickFalse)
2104 transpose_view=DestroyCacheView(transpose_view);
2105 image_view=DestroyCacheView(image_view);
2106 transpose_image->type=image->type;
2107 page=transpose_image->page;
2108 Swap(page.width,page.height);
2109 Swap(page.x,page.y);
2110 if (page.width != 0)
2111 page.x=(ssize_t) (page.width-transpose_image->columns-page.x);
2112 transpose_image->page=page;
2113 if (status == MagickFalse)
2114 transpose_image=DestroyImage(transpose_image);
2115 return(transpose_image);
2119 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2123 % T r a n s v e r s e I m a g e %
2127 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2129 % TransverseImage() creates a vertical mirror image by reflecting the pixels
2130 % around the central x-axis while rotating them by 270 degrees.
2132 % The format of the TransverseImage method is:
2134 % Image *TransverseImage(const Image *image,ExceptionInfo *exception)
2136 % A description of each parameter follows:
2138 % o image: the image.
2140 % o exception: return any errors or warnings in this structure.
2143 MagickExport Image *TransverseImage(const Image *image,ExceptionInfo *exception)
2145 #define TransverseImageTag "Transverse/Image"
2166 assert(image != (const Image *) NULL);
2167 assert(image->signature == MagickSignature);
2168 if (image->debug != MagickFalse)
2169 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2170 assert(exception != (ExceptionInfo *) NULL);
2171 assert(exception->signature == MagickSignature);
2172 transverse_image=CloneImage(image,image->rows,image->columns,MagickTrue,
2174 if (transverse_image == (Image *) NULL)
2175 return((Image *) NULL);
2181 image_view=AcquireCacheView(image);
2182 transverse_view=AcquireCacheView(transverse_image);
2183 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2184 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
2186 for (y=0; y < (ssize_t) image->rows; y++)
2191 register const PixelPacket
2194 register IndexPacket
2195 *restrict transverse_indexes,
2201 register PixelPacket
2204 if (status == MagickFalse)
2206 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2207 q=QueueCacheViewAuthenticPixels(transverse_view,(ssize_t) (image->rows-y-
2208 1),0,1,transverse_image->rows,exception);
2209 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
2215 for (x=0; x < (ssize_t) image->columns; x++)
2217 indexes=GetCacheViewAuthenticIndexQueue(image_view);
2218 if (indexes != (IndexPacket *) NULL)
2220 transverse_indexes=GetCacheViewAuthenticIndexQueue(transverse_view);
2221 if (transverse_indexes != (IndexPacket *) NULL)
2222 for (x=0; x < (ssize_t) image->columns; x++)
2223 transverse_indexes[image->columns-x-1]=indexes[x];
2225 sync=SyncCacheViewAuthenticPixels(transverse_view,exception);
2226 if (sync == MagickFalse)
2228 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2233 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2234 #pragma omp critical (MagickCore_TransverseImage)
2236 proceed=SetImageProgress(image,TransverseImageTag,progress++,
2238 if (proceed == MagickFalse)
2242 transverse_view=DestroyCacheView(transverse_view);
2243 image_view=DestroyCacheView(image_view);
2244 transverse_image->type=image->type;
2245 page=transverse_image->page;
2246 Swap(page.width,page.height);
2247 Swap(page.x,page.y);
2248 if (page.height != 0)
2249 page.y=(ssize_t) (page.height-transverse_image->rows-page.y);
2250 transverse_image->page=page;
2251 if (status == MagickFalse)
2252 transverse_image=DestroyImage(transverse_image);
2253 return(transverse_image);
2257 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2261 % T r i m I m a g e %
2265 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2267 % TrimImage() trims pixels from the image edges. It allocates the memory
2268 % necessary for the new Image structure and returns a pointer to the new
2271 % The format of the TrimImage method is:
2273 % Image *TrimImage(const Image *image,ExceptionInfo *exception)
2275 % A description of each parameter follows:
2277 % o image: the image.
2279 % o exception: return any errors or warnings in this structure.
2282 MagickExport Image *TrimImage(const Image *image,ExceptionInfo *exception)
2287 assert(image != (const Image *) NULL);
2288 assert(image->signature == MagickSignature);
2289 if (image->debug != MagickFalse)
2290 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2291 geometry=GetImageBoundingBox(image,exception);
2292 if ((geometry.width == 0) || (geometry.height == 0))
2297 crop_image=CloneImage(image,1,1,MagickTrue,exception);
2298 if (crop_image == (Image *) NULL)
2299 return((Image *) NULL);
2300 crop_image->background_color.opacity=(Quantum) TransparentOpacity;
2301 (void) SetImageBackgroundColor(crop_image);
2302 crop_image->page=image->page;
2303 crop_image->page.x=(-1);
2304 crop_image->page.y=(-1);
2307 geometry.x+=image->page.x;
2308 geometry.y+=image->page.y;
2309 return(CropImage(image,&geometry,exception));