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-2011 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/thread-private.h"
67 #include "magick/transform.h"
70 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
78 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
80 % ChopImage() removes a region of an image and collapses the image to occupy
81 % the removed portion.
83 % The format of the ChopImage method is:
85 % Image *ChopImage(const Image *image,const RectangleInfo *chop_info)
86 % ExceptionInfo *exception)
88 % A description of each parameter follows:
92 % o chop_info: Define the region of the image to chop.
94 % o exception: return any errors or warnings in this structure.
97 MagickExport Image *ChopImage(const Image *image,const RectangleInfo *chop_info,
98 ExceptionInfo *exception)
100 #define ChopImageTag "Chop/Image"
124 assert(image != (const Image *) NULL);
125 assert(image->signature == MagickSignature);
126 if (image->debug != MagickFalse)
127 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
128 assert(exception != (ExceptionInfo *) NULL);
129 assert(exception->signature == MagickSignature);
130 assert(chop_info != (RectangleInfo *) NULL);
131 if (((chop_info->x+(ssize_t) chop_info->width) < 0) ||
132 ((chop_info->y+(ssize_t) chop_info->height) < 0) ||
133 (chop_info->x > (ssize_t) image->columns) ||
134 (chop_info->y > (ssize_t) image->rows))
135 ThrowImageException(OptionWarning,"GeometryDoesNotContainImage");
137 if ((extent.x+(ssize_t) extent.width) > (ssize_t) image->columns)
138 extent.width=(size_t) ((ssize_t) image->columns-extent.x);
139 if ((extent.y+(ssize_t) extent.height) > (ssize_t) image->rows)
140 extent.height=(size_t) ((ssize_t) image->rows-extent.y);
143 extent.width-=(size_t) (-extent.x);
148 extent.height-=(size_t) (-extent.y);
151 chop_image=CloneImage(image,image->columns-extent.width,image->rows-
152 extent.height,MagickTrue,exception);
153 if (chop_image == (Image *) NULL)
154 return((Image *) NULL);
160 image_view=AcquireCacheView(image);
161 chop_view=AcquireCacheView(chop_image);
162 #if defined(MAGICKCORE_OPENMP_SUPPORT)
163 #pragma omp parallel for schedule(dynamic,4) shared(progress,status) omp_throttle(1)
165 for (y=0; y < (ssize_t) extent.y; y++)
167 register const PixelPacket
171 *restrict chop_indexes,
180 if (status == MagickFalse)
182 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
183 q=QueueCacheViewAuthenticPixels(chop_view,0,y,chop_image->columns,1,
185 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
190 indexes=GetCacheViewAuthenticIndexQueue(image_view);
191 chop_indexes=GetCacheViewAuthenticIndexQueue(chop_view);
192 for (x=0; x < (ssize_t) image->columns; x++)
194 if ((x < extent.x) || (x >= (ssize_t) (extent.x+extent.width)))
197 if (indexes != (IndexPacket *) NULL)
199 if (chop_indexes != (IndexPacket *) NULL)
200 *chop_indexes++=indexes[x];
206 if (SyncCacheViewAuthenticPixels(chop_view,exception) == MagickFalse)
208 if (image->progress_monitor != (MagickProgressMonitor) NULL)
213 #if defined(MAGICKCORE_OPENMP_SUPPORT)
214 #pragma omp critical (MagickCore_ChopImage)
216 proceed=SetImageProgress(image,ChopImageTag,progress++,image->rows);
217 if (proceed == MagickFalse)
224 #if defined(MAGICKCORE_OPENMP_SUPPORT)
225 #pragma omp parallel for schedule(dynamic,4) shared(progress,status) omp_throttle(1)
227 for (y=0; y < (ssize_t) (image->rows-(extent.y+extent.height)); y++)
229 register const PixelPacket
233 *restrict chop_indexes,
242 if (status == MagickFalse)
244 p=GetCacheViewVirtualPixels(image_view,0,extent.y+extent.height+y,
245 image->columns,1,exception);
246 q=QueueCacheViewAuthenticPixels(chop_view,0,extent.y+y,chop_image->columns,
248 if ((p == (PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
253 indexes=GetCacheViewAuthenticIndexQueue(image_view);
254 chop_indexes=GetCacheViewAuthenticIndexQueue(chop_view);
255 for (x=0; x < (ssize_t) image->columns; x++)
257 if ((x < extent.x) || (x >= (ssize_t) (extent.x+extent.width)))
260 if (indexes != (IndexPacket *) NULL)
262 if (chop_indexes != (IndexPacket *) NULL)
263 *chop_indexes++=indexes[x];
269 if (SyncCacheViewAuthenticPixels(chop_view,exception) == MagickFalse)
271 if (image->progress_monitor != (MagickProgressMonitor) NULL)
276 #if defined(MAGICKCORE_OPENMP_SUPPORT)
277 #pragma omp critical (MagickCore_ChopImage)
279 proceed=SetImageProgress(image,ChopImageTag,progress++,image->rows);
280 if (proceed == MagickFalse)
284 chop_view=DestroyCacheView(chop_view);
285 image_view=DestroyCacheView(image_view);
286 chop_image->type=image->type;
291 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
295 + C o n s o l i d a t e C M Y K I m a g e %
299 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
301 % ConsolidateCMYKImage() consolidates separate C, M, Y, and K planes into a
304 % The format of the ConsolidateCMYKImage method is:
306 % Image *ConsolidateCMYKImage(const Image *image,ExceptionInfo *exception)
308 % A description of each parameter follows:
310 % o image: the image sequence.
312 % o exception: return any errors or warnings in this structure.
315 MagickExport Image *ConsolidateCMYKImages(const Image *images,
316 ExceptionInfo *exception)
333 Consolidate separate C, M, Y, and K planes into a single image.
335 assert(images != (Image *) NULL);
336 assert(images->signature == MagickSignature);
337 if (images->debug != MagickFalse)
338 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
339 assert(exception != (ExceptionInfo *) NULL);
340 assert(exception->signature == MagickSignature);
341 cmyk_images=NewImageList();
342 for (i=0; i < (ssize_t) GetImageListLength(images); i+=4)
344 cmyk_image=CloneImage(images,images->columns,images->rows,MagickTrue,
346 if (cmyk_image == (Image *) NULL)
348 if (SetImageStorageClass(cmyk_image,DirectClass) == MagickFalse)
350 (void) SetImageColorspace(cmyk_image,CMYKColorspace);
351 image_view=AcquireCacheView(images);
352 cmyk_view=AcquireCacheView(cmyk_image);
353 for (y=0; y < (ssize_t) images->rows; y++)
355 register const PixelPacket
364 p=GetCacheViewVirtualPixels(image_view,0,y,images->columns,1,exception);
365 q=QueueCacheViewAuthenticPixels(cmyk_view,0,y,cmyk_image->columns,1,
367 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
369 for (x=0; x < (ssize_t) images->columns; x++)
371 q->red=(Quantum) (QuantumRange-PixelIntensityToQuantum(p));
375 if (SyncCacheViewAuthenticPixels(cmyk_view,exception) == MagickFalse)
378 cmyk_view=DestroyCacheView(cmyk_view);
379 image_view=DestroyCacheView(image_view);
380 images=GetNextImageInList(images);
381 if (images == (Image *) NULL)
383 image_view=AcquireCacheView(images);
384 cmyk_view=AcquireCacheView(cmyk_image);
385 for (y=0; y < (ssize_t) images->rows; y++)
387 register const PixelPacket
396 p=GetCacheViewVirtualPixels(image_view,0,y,images->columns,1,exception);
397 q=GetCacheViewAuthenticPixels(cmyk_view,0,y,cmyk_image->columns,1,
399 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
401 for (x=0; x < (ssize_t) images->columns; x++)
403 q->green=(Quantum) (QuantumRange-PixelIntensityToQuantum(p));
407 if (SyncCacheViewAuthenticPixels(cmyk_view,exception) == MagickFalse)
410 cmyk_view=DestroyCacheView(cmyk_view);
411 image_view=DestroyCacheView(image_view);
412 images=GetNextImageInList(images);
413 if (images == (Image *) NULL)
415 image_view=AcquireCacheView(images);
416 cmyk_view=AcquireCacheView(cmyk_image);
417 for (y=0; y < (ssize_t) images->rows; y++)
419 register const PixelPacket
428 p=GetCacheViewVirtualPixels(image_view,0,y,images->columns,1,exception);
429 q=GetCacheViewAuthenticPixels(cmyk_view,0,y,cmyk_image->columns,1,
431 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
433 for (x=0; x < (ssize_t) images->columns; x++)
435 q->blue=(Quantum) (QuantumRange-PixelIntensityToQuantum(p));
439 if (SyncCacheViewAuthenticPixels(cmyk_view,exception) == MagickFalse)
442 cmyk_view=DestroyCacheView(cmyk_view);
443 image_view=DestroyCacheView(image_view);
444 images=GetNextImageInList(images);
445 if (images == (Image *) NULL)
447 image_view=AcquireCacheView(images);
448 cmyk_view=AcquireCacheView(cmyk_image);
449 for (y=0; y < (ssize_t) images->rows; y++)
451 register const PixelPacket
463 p=GetCacheViewVirtualPixels(image_view,0,y,images->columns,1,exception);
464 q=GetCacheViewAuthenticPixels(cmyk_view,0,y,cmyk_image->columns,1,
466 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
468 indexes=GetCacheViewAuthenticIndexQueue(cmyk_view);
469 for (x=0; x < (ssize_t) images->columns; x++)
471 indexes[x]=(IndexPacket) (QuantumRange-PixelIntensityToQuantum(p));
474 if (SyncCacheViewAuthenticPixels(cmyk_view,exception) == MagickFalse)
477 cmyk_view=DestroyCacheView(cmyk_view);
478 image_view=DestroyCacheView(image_view);
479 AppendImageToList(&cmyk_images,cmyk_image);
480 images=GetNextImageInList(images);
481 if (images == (Image *) NULL)
488 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
492 % C r o p I m a g e %
496 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
498 % CropImage() extracts a region of the image starting at the offset defined
501 % The format of the CropImage method is:
503 % Image *CropImage(const Image *image,const RectangleInfo *geometry,
504 % ExceptionInfo *exception)
506 % A description of each parameter follows:
508 % o image: the image.
510 % o geometry: Define the region of the image to crop with members
511 % x, y, width, and height.
513 % o exception: return any errors or warnings in this structure.
516 MagickExport Image *CropImage(const Image *image,const RectangleInfo *geometry,
517 ExceptionInfo *exception)
519 #define CropImageTag "Crop/Image"
544 assert(image != (const Image *) NULL);
545 assert(image->signature == MagickSignature);
546 if (image->debug != MagickFalse)
547 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
548 assert(geometry != (const RectangleInfo *) NULL);
549 assert(exception != (ExceptionInfo *) NULL);
550 assert(exception->signature == MagickSignature);
551 bounding_box=image->page;
552 if ((bounding_box.width == 0) || (bounding_box.height == 0))
554 bounding_box.width=image->columns;
555 bounding_box.height=image->rows;
559 page.width=bounding_box.width;
560 if (page.height == 0)
561 page.height=bounding_box.height;
562 if (((bounding_box.x-page.x) >= (ssize_t) page.width) ||
563 ((bounding_box.y-page.y) >= (ssize_t) page.height) ||
564 ((page.x-bounding_box.x) > (ssize_t) image->columns) ||
565 ((page.y-bounding_box.y) > (ssize_t) image->rows))
568 Crop is not within virtual canvas, return 1 pixel transparent image.
570 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
571 "GeometryDoesNotContainImage","`%s'",image->filename);
572 crop_image=CloneImage(image,1,1,MagickTrue,exception);
573 if (crop_image == (Image *) NULL)
574 return((Image *) NULL);
575 crop_image->background_color.opacity=(Quantum) TransparentOpacity;
576 (void) SetImageBackgroundColor(crop_image);
577 crop_image->page=bounding_box;
578 crop_image->page.x=(-1);
579 crop_image->page.y=(-1);
580 if (crop_image->dispose == BackgroundDispose)
581 crop_image->dispose=NoneDispose;
584 if ((page.x < 0) && (bounding_box.x >= 0))
586 page.width+=page.x-bounding_box.x;
591 page.width-=bounding_box.x-page.x;
592 page.x-=bounding_box.x;
596 if ((page.y < 0) && (bounding_box.y >= 0))
598 page.height+=page.y-bounding_box.y;
603 page.height-=bounding_box.y-page.y;
604 page.y-=bounding_box.y;
608 if ((size_t) (page.x+page.width) > image->columns)
609 page.width=image->columns-page.x;
610 if ((geometry->width != 0) && (page.width > geometry->width))
611 page.width=geometry->width;
612 if ((size_t) (page.y+page.height) > image->rows)
613 page.height=image->rows-page.y;
614 if ((geometry->height != 0) && (page.height > geometry->height))
615 page.height=geometry->height;
616 bounding_box.x+=page.x;
617 bounding_box.y+=page.y;
618 if ((page.width == 0) || (page.height == 0))
620 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
621 "GeometryDoesNotContainImage","`%s'",image->filename);
622 return((Image *) NULL);
625 Initialize crop image attributes.
627 crop_image=CloneImage(image,page.width,page.height,MagickTrue,exception);
628 if (crop_image == (Image *) NULL)
629 return((Image *) NULL);
630 crop_image->page.width=image->page.width;
631 crop_image->page.height=image->page.height;
632 if (((ssize_t) (bounding_box.x+bounding_box.width) > (ssize_t) image->page.width) ||
633 ((ssize_t) (bounding_box.y+bounding_box.height) > (ssize_t) image->page.height))
635 crop_image->page.width=bounding_box.width;
636 crop_image->page.height=bounding_box.height;
638 crop_image->page.x=bounding_box.x;
639 crop_image->page.y=bounding_box.y;
645 image_view=AcquireCacheView(image);
646 crop_view=AcquireCacheView(crop_image);
647 #if defined(MAGICKCORE_OPENMP_SUPPORT)
648 #pragma omp parallel for schedule(dynamic,4) shared(progress,status) omp_throttle(1)
650 for (y=0; y < (ssize_t) crop_image->rows; y++)
652 register const IndexPacket
655 register const PixelPacket
659 *restrict crop_indexes;
664 if (status == MagickFalse)
666 p=GetCacheViewVirtualPixels(image_view,page.x,page.y+y,crop_image->columns,
668 q=QueueCacheViewAuthenticPixels(crop_view,0,y,crop_image->columns,1,
670 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
675 indexes=GetCacheViewVirtualIndexQueue(image_view);
676 crop_indexes=GetCacheViewAuthenticIndexQueue(crop_view);
677 (void) CopyMagickMemory(q,p,(size_t) crop_image->columns*sizeof(*p));
678 if ((indexes != (IndexPacket *) NULL) &&
679 (crop_indexes != (IndexPacket *) NULL))
680 (void) CopyMagickMemory(crop_indexes,indexes,(size_t) crop_image->columns*
681 sizeof(*crop_indexes));
682 if (SyncCacheViewAuthenticPixels(crop_view,exception) == MagickFalse)
684 if (image->progress_monitor != (MagickProgressMonitor) NULL)
689 #if defined(MAGICKCORE_OPENMP_SUPPORT)
690 #pragma omp critical (MagickCore_CropImage)
692 proceed=SetImageProgress(image,CropImageTag,progress++,image->rows);
693 if (proceed == MagickFalse)
697 crop_view=DestroyCacheView(crop_view);
698 image_view=DestroyCacheView(image_view);
699 crop_image->type=image->type;
700 if (status == MagickFalse)
701 crop_image=DestroyImage(crop_image);
706 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
710 % E x c e r p t I m a g e %
714 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
716 % ExcerptImage() returns a excerpt of the image as defined by the geometry.
718 % The format of the ExcerptImage method is:
720 % Image *ExcerptImage(const Image *image,const RectangleInfo *geometry,
721 % ExceptionInfo *exception)
723 % A description of each parameter follows:
725 % o image: the image.
727 % o geometry: Define the region of the image to extend with members
728 % x, y, width, and height.
730 % o exception: return any errors or warnings in this structure.
733 MagickExport Image *ExcerptImage(const Image *image,
734 const RectangleInfo *geometry,ExceptionInfo *exception)
736 #define ExcerptImageTag "Excerpt/Image"
755 Allocate excerpt image.
757 assert(image != (const Image *) NULL);
758 assert(image->signature == MagickSignature);
759 if (image->debug != MagickFalse)
760 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
761 assert(geometry != (const RectangleInfo *) NULL);
762 assert(exception != (ExceptionInfo *) NULL);
763 assert(exception->signature == MagickSignature);
764 excerpt_image=CloneImage(image,geometry->width,geometry->height,MagickTrue,
766 if (excerpt_image == (Image *) NULL)
767 return((Image *) NULL);
773 image_view=AcquireCacheView(image);
774 excerpt_view=AcquireCacheView(excerpt_image);
775 #if defined(MAGICKCORE_OPENMP_SUPPORT)
776 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
778 for (y=0; y < (ssize_t) excerpt_image->rows; y++)
780 register const PixelPacket
784 *restrict excerpt_indexes,
790 if (status == MagickFalse)
792 p=GetCacheViewVirtualPixels(image_view,geometry->x,geometry->y+y,
793 geometry->width,1,exception);
794 q=GetCacheViewAuthenticPixels(excerpt_view,0,y,excerpt_image->columns,1,
796 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
801 (void) CopyMagickMemory(q,p,(size_t) excerpt_image->columns*sizeof(*q));
802 indexes=GetCacheViewAuthenticIndexQueue(image_view);
803 if (indexes != (IndexPacket *) NULL)
805 excerpt_indexes=GetCacheViewAuthenticIndexQueue(excerpt_view);
806 if (excerpt_indexes != (IndexPacket *) NULL)
807 (void) CopyMagickMemory(excerpt_indexes,indexes,(size_t)
808 excerpt_image->columns*sizeof(*excerpt_indexes));
810 if (SyncCacheViewAuthenticPixels(excerpt_view,exception) == MagickFalse)
812 if (image->progress_monitor != (MagickProgressMonitor) NULL)
817 #if defined(MAGICKCORE_OPENMP_SUPPORT)
818 #pragma omp critical (MagickCore_ExcerptImage)
820 proceed=SetImageProgress(image,ExcerptImageTag,progress++,image->rows);
821 if (proceed == MagickFalse)
825 excerpt_view=DestroyCacheView(excerpt_view);
826 image_view=DestroyCacheView(image_view);
827 excerpt_image->type=image->type;
828 if (status == MagickFalse)
829 excerpt_image=DestroyImage(excerpt_image);
830 return(excerpt_image);
834 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
838 % E x t e n t I m a g e %
842 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
844 % ExtentImage() extends the image as defined by the geometry, gravity, and
845 % image background color. Set the (x,y) offset of the geometry to move the
846 % original image relative to the extended image.
848 % The format of the ExtentImage method is:
850 % Image *ExtentImage(const Image *image,const RectangleInfo *geometry,
851 % ExceptionInfo *exception)
853 % A description of each parameter follows:
855 % o image: the image.
857 % o geometry: Define the region of the image to extend with members
858 % x, y, width, and height.
860 % o exception: return any errors or warnings in this structure.
863 MagickExport Image *ExtentImage(const Image *image,
864 const RectangleInfo *geometry,ExceptionInfo *exception)
870 Allocate extent image.
872 assert(image != (const Image *) NULL);
873 assert(image->signature == MagickSignature);
874 if (image->debug != MagickFalse)
875 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
876 assert(geometry != (const RectangleInfo *) NULL);
877 assert(exception != (ExceptionInfo *) NULL);
878 assert(exception->signature == MagickSignature);
879 extent_image=CloneImage(image,geometry->width,geometry->height,MagickTrue,
881 if (extent_image == (Image *) NULL)
882 return((Image *) NULL);
883 if (SetImageStorageClass(extent_image,DirectClass) == MagickFalse)
885 InheritException(exception,&extent_image->exception);
886 extent_image=DestroyImage(extent_image);
887 return((Image *) NULL);
889 if (extent_image->background_color.opacity != OpaqueOpacity)
890 extent_image->matte=MagickTrue;
891 (void) SetImageBackgroundColor(extent_image);
892 (void) CompositeImage(extent_image,image->compose,image,-geometry->x,
894 return(extent_image);
898 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
902 % F l i p I m a g e %
906 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
908 % FlipImage() creates a vertical mirror image by reflecting the pixels
909 % around the central x-axis.
911 % The format of the FlipImage method is:
913 % Image *FlipImage(const Image *image,ExceptionInfo *exception)
915 % A description of each parameter follows:
917 % o image: the image.
919 % o exception: return any errors or warnings in this structure.
922 MagickExport Image *FlipImage(const Image *image,ExceptionInfo *exception)
924 #define FlipImageTag "Flip/Image"
945 assert(image != (const Image *) NULL);
946 assert(image->signature == MagickSignature);
947 if (image->debug != MagickFalse)
948 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
949 assert(exception != (ExceptionInfo *) NULL);
950 assert(exception->signature == MagickSignature);
951 flip_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
952 if (flip_image == (Image *) NULL)
953 return((Image *) NULL);
960 image_view=AcquireCacheView(image);
961 flip_view=AcquireCacheView(flip_image);
962 #if defined(MAGICKCORE_OPENMP_SUPPORT)
963 #pragma omp parallel for schedule(dynamic,4) shared(progress,status) omp_throttle(1)
965 for (y=0; y < (ssize_t) flip_image->rows; y++)
967 register const IndexPacket
970 register const PixelPacket
974 *restrict flip_indexes;
979 if (status == MagickFalse)
981 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
982 q=QueueCacheViewAuthenticPixels(flip_view,0,(ssize_t) (flip_image->rows-y-
983 1),flip_image->columns,1,exception);
984 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
989 (void) CopyMagickMemory(q,p,(size_t) image->columns*sizeof(*q));
990 indexes=GetCacheViewVirtualIndexQueue(image_view);
991 if (indexes != (const IndexPacket *) NULL)
993 flip_indexes=GetCacheViewAuthenticIndexQueue(flip_view);
994 if (flip_indexes != (IndexPacket *) NULL)
995 (void) CopyMagickMemory(flip_indexes,indexes,(size_t) image->columns*
996 sizeof(*flip_indexes));
998 if (SyncCacheViewAuthenticPixels(flip_view,exception) == MagickFalse)
1000 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1005 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1006 #pragma omp critical (MagickCore_FlipImage)
1008 proceed=SetImageProgress(image,FlipImageTag,progress++,image->rows);
1009 if (proceed == MagickFalse)
1013 flip_view=DestroyCacheView(flip_view);
1014 image_view=DestroyCacheView(image_view);
1015 flip_image->type=image->type;
1016 if (page.height != 0)
1017 page.y=(ssize_t) (page.height-flip_image->rows-page.y);
1018 flip_image->page=page;
1019 if (status == MagickFalse)
1020 flip_image=DestroyImage(flip_image);
1025 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1029 % F l o p I m a g e %
1033 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1035 % FlopImage() creates a horizontal mirror image by reflecting the pixels
1036 % around the central y-axis.
1038 % The format of the FlopImage method is:
1040 % Image *FlopImage(const Image *image,ExceptionInfo *exception)
1042 % A description of each parameter follows:
1044 % o image: the image.
1046 % o exception: return any errors or warnings in this structure.
1049 MagickExport Image *FlopImage(const Image *image,ExceptionInfo *exception)
1051 #define FlopImageTag "Flop/Image"
1072 assert(image != (const Image *) NULL);
1073 assert(image->signature == MagickSignature);
1074 if (image->debug != MagickFalse)
1075 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1076 assert(exception != (ExceptionInfo *) NULL);
1077 assert(exception->signature == MagickSignature);
1078 flop_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
1079 if (flop_image == (Image *) NULL)
1080 return((Image *) NULL);
1087 image_view=AcquireCacheView(image);
1088 flop_view=AcquireCacheView(flop_image);
1089 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1090 #pragma omp parallel for schedule(dynamic,4) shared(progress,status) omp_throttle(1)
1092 for (y=0; y < (ssize_t) flop_image->rows; y++)
1094 register const IndexPacket
1097 register const PixelPacket
1100 register IndexPacket
1101 *restrict flop_indexes;
1106 register PixelPacket
1109 if (status == MagickFalse)
1111 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1112 q=QueueCacheViewAuthenticPixels(flop_view,0,y,flop_image->columns,1,
1114 if ((p == (PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
1119 q+=flop_image->columns;
1120 indexes=GetCacheViewVirtualIndexQueue(image_view);
1121 flop_indexes=GetCacheViewAuthenticIndexQueue(flop_view);
1122 for (x=0; x < (ssize_t) flop_image->columns; x++)
1125 if ((indexes != (const IndexPacket *) NULL) &&
1126 (flop_indexes != (IndexPacket *) NULL))
1127 flop_indexes[flop_image->columns-x-1]=indexes[x];
1129 if (SyncCacheViewAuthenticPixels(flop_view,exception) == MagickFalse)
1131 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1136 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1137 #pragma omp critical (MagickCore_FlopImage)
1139 proceed=SetImageProgress(image,FlopImageTag,progress++,image->rows);
1140 if (proceed == MagickFalse)
1144 flop_view=DestroyCacheView(flop_view);
1145 image_view=DestroyCacheView(image_view);
1146 flop_image->type=image->type;
1147 if (page.width != 0)
1148 page.x=(ssize_t) (page.width-flop_image->columns-page.x);
1149 flop_image->page=page;
1150 if (status == MagickFalse)
1151 flop_image=DestroyImage(flop_image);
1156 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1160 % R o l l I m a g e %
1164 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1166 % RollImage() offsets an image as defined by x_offset and y_offset.
1168 % The format of the RollImage method is:
1170 % Image *RollImage(const Image *image,const ssize_t x_offset,
1171 % const ssize_t y_offset,ExceptionInfo *exception)
1173 % A description of each parameter follows:
1175 % o image: the image.
1177 % o x_offset: the number of columns to roll in the horizontal direction.
1179 % o y_offset: the number of rows to roll in the vertical direction.
1181 % o exception: return any errors or warnings in this structure.
1185 static inline MagickBooleanType CopyImageRegion(Image *destination,
1186 const Image *source,const size_t columns,const size_t rows,
1187 const ssize_t sx,const ssize_t sy,const ssize_t dx,const ssize_t dy,
1188 ExceptionInfo *exception)
1201 source_view=AcquireCacheView(source);
1202 destination_view=AcquireCacheView(destination);
1203 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1204 #pragma omp parallel for schedule(dynamic,4) shared(status)
1206 for (y=0; y < (ssize_t) rows; y++)
1211 register const IndexPacket
1214 register const PixelPacket
1217 register IndexPacket
1218 *restrict destination_indexes;
1220 register PixelPacket
1226 if (status == MagickFalse)
1228 p=GetCacheViewVirtualPixels(source_view,sx,sy+y,columns,1,exception);
1229 q=GetCacheViewAuthenticPixels(destination_view,dx,dy+y,columns,1,exception);
1230 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
1235 indexes=GetCacheViewVirtualIndexQueue(source_view);
1236 (void) CopyMagickMemory(q,p,(size_t) columns*sizeof(*p));
1237 if (indexes != (IndexPacket *) NULL)
1239 destination_indexes=GetCacheViewAuthenticIndexQueue(destination_view);
1240 if (destination_indexes != (IndexPacket *) NULL)
1241 (void) CopyMagickMemory(destination_indexes,indexes,(size_t)
1242 columns*sizeof(*indexes));
1244 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
1245 if (sync == MagickFalse)
1248 destination_view=DestroyCacheView(destination_view);
1249 source_view=DestroyCacheView(source_view);
1253 MagickExport Image *RollImage(const Image *image,const ssize_t x_offset,
1254 const ssize_t y_offset,ExceptionInfo *exception)
1256 #define RollImageTag "Roll/Image"
1268 Initialize roll image attributes.
1270 assert(image != (const Image *) NULL);
1271 assert(image->signature == MagickSignature);
1272 if (image->debug != MagickFalse)
1273 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1274 assert(exception != (ExceptionInfo *) NULL);
1275 assert(exception->signature == MagickSignature);
1276 roll_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
1277 if (roll_image == (Image *) NULL)
1278 return((Image *) NULL);
1281 while (offset.x < 0)
1282 offset.x+=(ssize_t) image->columns;
1283 while (offset.x >= (ssize_t) image->columns)
1284 offset.x-=(ssize_t) image->columns;
1285 while (offset.y < 0)
1286 offset.y+=(ssize_t) image->rows;
1287 while (offset.y >= (ssize_t) image->rows)
1288 offset.y-=(ssize_t) image->rows;
1292 status=CopyImageRegion(roll_image,image,(size_t) offset.x,
1293 (size_t) offset.y,(ssize_t) image->columns-offset.x,(ssize_t) image->rows-
1294 offset.y,0,0,exception);
1295 (void) SetImageProgress(image,RollImageTag,0,3);
1296 status|=CopyImageRegion(roll_image,image,image->columns-offset.x,
1297 (size_t) offset.y,0,(ssize_t) image->rows-offset.y,offset.x,0,
1299 (void) SetImageProgress(image,RollImageTag,1,3);
1300 status|=CopyImageRegion(roll_image,image,(size_t) offset.x,image->rows-
1301 offset.y,(ssize_t) image->columns-offset.x,0,0,offset.y,exception);
1302 (void) SetImageProgress(image,RollImageTag,2,3);
1303 status|=CopyImageRegion(roll_image,image,image->columns-offset.x,image->rows-
1304 offset.y,0,0,offset.x,offset.y,exception);
1305 (void) SetImageProgress(image,RollImageTag,3,3);
1306 roll_image->type=image->type;
1307 if (status == MagickFalse)
1308 roll_image=DestroyImage(roll_image);
1313 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1317 % S h a v e I m a g e %
1321 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1323 % ShaveImage() shaves pixels from the image edges. It allocates the memory
1324 % necessary for the new Image structure and returns a pointer to the new
1327 % The format of the ShaveImage method is:
1329 % Image *ShaveImage(const Image *image,const RectangleInfo *shave_info,
1330 % ExceptionInfo *exception)
1332 % A description of each parameter follows:
1334 % o shave_image: Method ShaveImage returns a pointer to the shaved
1335 % image. A null image is returned if there is a memory shortage or
1336 % if the image width or height is zero.
1338 % o image: the image.
1340 % o shave_info: Specifies a pointer to a RectangleInfo which defines the
1341 % region of the image to crop.
1343 % o exception: return any errors or warnings in this structure.
1346 MagickExport Image *ShaveImage(const Image *image,
1347 const RectangleInfo *shave_info,ExceptionInfo *exception)
1355 assert(image != (const Image *) NULL);
1356 assert(image->signature == MagickSignature);
1357 if (image->debug != MagickFalse)
1358 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1359 if (((2*shave_info->width) >= image->columns) ||
1360 ((2*shave_info->height) >= image->rows))
1361 ThrowImageException(OptionWarning,"GeometryDoesNotContainImage");
1362 SetGeometry(image,&geometry);
1363 geometry.width-=2*shave_info->width;
1364 geometry.height-=2*shave_info->height;
1365 geometry.x=(ssize_t) shave_info->width+image->page.x;
1366 geometry.y=(ssize_t) shave_info->height+image->page.y;
1367 shave_image=CropImage(image,&geometry,exception);
1368 if (shave_image == (Image *) NULL)
1369 return((Image *) NULL);
1370 shave_image->page.width-=2*shave_info->width;
1371 shave_image->page.height-=2*shave_info->height;
1372 shave_image->page.x-=(ssize_t) shave_info->width;
1373 shave_image->page.y-=(ssize_t) shave_info->height;
1374 return(shave_image);
1378 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1382 % S p l i c e I m a g e %
1386 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1388 % SpliceImage() splices a solid color into the image as defined by the
1391 % The format of the SpliceImage method is:
1393 % Image *SpliceImage(const Image *image,const RectangleInfo *geometry,
1394 % ExceptionInfo *exception)
1396 % A description of each parameter follows:
1398 % o image: the image.
1400 % o geometry: Define the region of the image to splice with members
1401 % x, y, width, and height.
1403 % o exception: return any errors or warnings in this structure.
1406 MagickExport Image *SpliceImage(const Image *image,
1407 const RectangleInfo *geometry,ExceptionInfo *exception)
1409 #define SpliceImageTag "Splice/Image"
1431 Allocate splice image.
1433 assert(image != (const Image *) NULL);
1434 assert(image->signature == MagickSignature);
1435 if (image->debug != MagickFalse)
1436 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1437 assert(geometry != (const RectangleInfo *) NULL);
1438 assert(exception != (ExceptionInfo *) NULL);
1439 assert(exception->signature == MagickSignature);
1440 splice_geometry=(*geometry);
1441 splice_image=CloneImage(image,image->columns+splice_geometry.width,
1442 image->rows+splice_geometry.height,MagickTrue,exception);
1443 if (splice_image == (Image *) NULL)
1444 return((Image *) NULL);
1445 if (SetImageStorageClass(splice_image,DirectClass) == MagickFalse)
1447 InheritException(exception,&splice_image->exception);
1448 splice_image=DestroyImage(splice_image);
1449 return((Image *) NULL);
1451 (void) SetImageBackgroundColor(splice_image);
1453 Respect image geometry.
1455 switch (image->gravity)
1458 case UndefinedGravity:
1459 case NorthWestGravity:
1463 splice_geometry.x+=(ssize_t) splice_geometry.width/2;
1466 case NorthEastGravity:
1468 splice_geometry.x+=(ssize_t) splice_geometry.width;
1473 splice_geometry.y+=(ssize_t) splice_geometry.width/2;
1479 splice_geometry.x+=(ssize_t) splice_geometry.width/2;
1480 splice_geometry.y+=(ssize_t) splice_geometry.height/2;
1485 splice_geometry.x+=(ssize_t) splice_geometry.width;
1486 splice_geometry.y+=(ssize_t) splice_geometry.height/2;
1489 case SouthWestGravity:
1491 splice_geometry.y+=(ssize_t) splice_geometry.height;
1496 splice_geometry.x+=(ssize_t) splice_geometry.width/2;
1497 splice_geometry.y+=(ssize_t) splice_geometry.height;
1500 case SouthEastGravity:
1502 splice_geometry.x+=(ssize_t) splice_geometry.width;
1503 splice_geometry.y+=(ssize_t) splice_geometry.height;
1512 image_view=AcquireCacheView(image);
1513 splice_view=AcquireCacheView(splice_image);
1514 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1515 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
1517 for (y=0; y < (ssize_t) splice_geometry.y; y++)
1519 register const PixelPacket
1522 register IndexPacket
1524 *restrict splice_indexes;
1529 register PixelPacket
1532 if (status == MagickFalse)
1534 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1535 q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1,
1537 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
1542 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1543 splice_indexes=GetCacheViewAuthenticIndexQueue(splice_view);
1544 for (x=0; x < splice_geometry.x; x++)
1546 SetRedPixelComponent(q,GetRedPixelComponent(p));
1547 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
1548 SetBluePixelComponent(q,GetBluePixelComponent(p));
1549 SetOpacityPixelComponent(q,OpaqueOpacity);
1550 if (image->matte != MagickFalse)
1551 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
1552 if (image->colorspace == CMYKColorspace)
1553 splice_indexes[x]=(*indexes++);
1557 for ( ; x < (ssize_t) (splice_geometry.x+splice_geometry.width); x++)
1559 for ( ; x < (ssize_t) splice_image->columns; x++)
1561 SetRedPixelComponent(q,GetRedPixelComponent(p));
1562 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
1563 SetBluePixelComponent(q,GetBluePixelComponent(p));
1564 SetOpacityPixelComponent(q,OpaqueOpacity);
1565 if (image->matte != MagickFalse)
1566 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
1567 if (image->colorspace == CMYKColorspace)
1568 splice_indexes[x]=(*indexes++);
1572 if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse)
1574 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1579 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1580 #pragma omp critical (MagickCore_TransposeImage)
1582 proceed=SetImageProgress(image,SpliceImageTag,progress++,
1583 splice_image->rows);
1584 if (proceed == MagickFalse)
1588 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1589 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
1591 for (y=(ssize_t) (splice_geometry.y+splice_geometry.height);
1592 y < (ssize_t) splice_image->rows; y++)
1594 register const PixelPacket
1597 register IndexPacket
1599 *restrict splice_indexes;
1604 register PixelPacket
1607 if (status == MagickFalse)
1609 p=GetCacheViewVirtualPixels(image_view,0,y-(ssize_t) splice_geometry.height,
1610 image->columns,1,exception);
1611 if ((y < 0) || (y >= (ssize_t) splice_image->rows))
1613 q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1,
1615 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
1620 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1621 splice_indexes=GetCacheViewAuthenticIndexQueue(splice_view);
1622 for (x=0; x < splice_geometry.x; x++)
1624 SetRedPixelComponent(q,GetRedPixelComponent(p));
1625 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
1626 SetBluePixelComponent(q,GetBluePixelComponent(p));
1627 SetOpacityPixelComponent(q,OpaqueOpacity);
1628 if (image->matte != MagickFalse)
1629 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
1630 if (image->colorspace == CMYKColorspace)
1631 splice_indexes[x]=(*indexes++);
1635 for ( ; x < (ssize_t) (splice_geometry.x+splice_geometry.width); x++)
1637 for ( ; x < (ssize_t) splice_image->columns; x++)
1639 SetRedPixelComponent(q,GetRedPixelComponent(p));
1640 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
1641 SetBluePixelComponent(q,GetBluePixelComponent(p));
1642 SetOpacityPixelComponent(q,OpaqueOpacity);
1643 if (image->matte != MagickFalse)
1644 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
1645 if (image->colorspace == CMYKColorspace)
1646 splice_indexes[x]=(*indexes++);
1650 if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse)
1652 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1657 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1658 #pragma omp critical (MagickCore_TransposeImage)
1660 proceed=SetImageProgress(image,SpliceImageTag,progress++,
1661 splice_image->rows);
1662 if (proceed == MagickFalse)
1666 splice_view=DestroyCacheView(splice_view);
1667 image_view=DestroyCacheView(image_view);
1668 if (status == MagickFalse)
1669 splice_image=DestroyImage(splice_image);
1670 return(splice_image);
1674 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1678 % T r a n s f o r m I m a g e %
1682 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1684 % TransformImage() is a convenience method that behaves like ResizeImage() or
1685 % CropImage() but accepts scaling and/or cropping information as a region
1686 % geometry specification. If the operation fails, the original image handle
1689 % The format of the TransformImage method is:
1691 % MagickBooleanType TransformImage(Image **image,const char *crop_geometry,
1692 % const char *image_geometry)
1694 % A description of each parameter follows:
1696 % o image: the image The transformed image is returned as this parameter.
1698 % o crop_geometry: A crop geometry string. This geometry defines a
1699 % subregion of the image to crop.
1701 % o image_geometry: An image geometry string. This geometry defines the
1702 % final size of the image.
1706 static inline ssize_t MagickRound(MagickRealType x)
1709 Round the fraction to nearest integer.
1712 return((ssize_t) (x+0.5));
1713 return((ssize_t) (x-0.5));
1716 MagickExport MagickBooleanType TransformImage(Image **image,
1717 const char *crop_geometry,const char *image_geometry)
1738 assert(image != (Image **) NULL);
1739 assert((*image)->signature == MagickSignature);
1740 if ((*image)->debug != MagickFalse)
1741 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
1742 transform_image=(*image);
1743 if (crop_geometry != (const char *) NULL)
1752 Crop image to a user specified size.
1754 crop_image=NewImageList();
1755 flags=ParseGravityGeometry(transform_image,crop_geometry,&geometry,
1756 &(*image)->exception);
1757 if ((flags & AreaValue) != 0)
1767 Crop into NxM tiles (@ flag) - AT.
1769 if (geometry.width == 0)
1771 if (geometry.height == 0)
1773 width=transform_image->columns;
1774 height=transform_image->rows;
1775 if ((flags & AspectValue) == 0)
1777 width-=(geometry.x < 0 ? -1 : 1)*geometry.x;
1778 height-=(geometry.y < 0 ? -1 : 1)*geometry.y;
1782 width+=(geometry.x < 0 ? -1 : 1)*geometry.x;
1783 height+=(geometry.y < 0 ? -1 : 1)*geometry.y;
1785 delta.x=(double) width/geometry.width;
1786 delta.y=(double) height/geometry.height;
1787 next=NewImageList();
1788 for (offset.y=0; offset.y < (double) height; )
1790 if ((flags & AspectValue) == 0)
1792 crop.y=(ssize_t) MagickRound((MagickRealType) (offset.y-
1793 (geometry.y > 0 ? 0 : geometry.y)));
1795 crop.height=(size_t) MagickRound((MagickRealType)
1796 (offset.y+(geometry.y < 0 ? 0 : geometry.y)));
1800 crop.y=(ssize_t) MagickRound((MagickRealType) (offset.y-
1801 (geometry.y > 0 ? geometry.y : 0)));
1803 crop.height=(size_t) MagickRound((MagickRealType)
1804 (offset.y+(geometry.y < 0 ? geometry.y : 0)));
1806 crop.height-=crop.y;
1807 crop.y+=transform_image->page.y;
1808 for (offset.x=0; offset.x < (double) width; )
1810 if ((flags & AspectValue) == 0)
1812 crop.x=(ssize_t) MagickRound((MagickRealType) (offset.x-
1813 (geometry.x > 0 ? 0 : geometry.x)));
1815 crop.width=(size_t) MagickRound((MagickRealType)
1816 (offset.x+(geometry.x < 0 ? 0 : geometry.x)));
1820 crop.x=(ssize_t) MagickRound((MagickRealType) (offset.x-
1821 (geometry.x > 0 ? geometry.x : 0)));
1823 crop.width=(size_t) MagickRound((MagickRealType)
1824 (offset.x+(geometry.x < 0 ? geometry.x : 0)));
1827 crop.x+=transform_image->page.x;
1828 next=CropImage(transform_image,&crop,&(*image)->exception);
1829 if (next == (Image *) NULL)
1831 AppendImageToList(&crop_image,next);
1833 if (next == (Image *) NULL)
1838 if (((geometry.width == 0) && (geometry.height == 0)) ||
1839 ((flags & XValue) != 0) || ((flags & YValue) != 0))
1842 Crop a single region at +X+Y.
1844 crop_image=CropImage(transform_image,&geometry,
1845 &(*image)->exception);
1846 if ((crop_image != (Image *) NULL) && ((flags & AspectValue) != 0))
1848 crop_image->page.width=geometry.width;
1849 crop_image->page.height=geometry.height;
1850 crop_image->page.x-=geometry.x;
1851 crop_image->page.y-=geometry.y;
1855 if ((transform_image->columns > geometry.width) ||
1856 (transform_image->rows > geometry.height))
1861 MagickProgressMonitor
1874 Crop into tiles of fixed size WxH.
1876 if (transform_image->page.width == 0)
1877 transform_image->page.width=transform_image->columns;
1878 if (transform_image->page.height == 0)
1879 transform_image->page.height=transform_image->rows;
1880 width=geometry.width;
1882 width=transform_image->page.width;
1883 height=geometry.height;
1885 height=transform_image->page.height;
1886 next=NewImageList();
1890 page=transform_image->page;
1891 for (y=0; y < (ssize_t) page.height; y+=(ssize_t) height)
1892 for (x=0; x < (ssize_t) page.width; x+=(ssize_t) width)
1894 for (y=0; y < (ssize_t) page.height; y+=(ssize_t) height)
1896 for (x=0; x < (ssize_t) page.width; x+=(ssize_t) width)
1898 progress_monitor=SetImageProgressMonitor(transform_image,
1899 (MagickProgressMonitor) NULL,transform_image->client_data);
1900 geometry.width=width;
1901 geometry.height=height;
1904 next=CropImage(transform_image,&geometry,&(*image)->exception);
1905 (void) SetImageProgressMonitor(transform_image,
1906 progress_monitor,transform_image->client_data);
1907 proceed=SetImageProgress(transform_image,CropImageTag,i++,
1909 if (proceed == MagickFalse)
1911 if (next == (Image *) NULL)
1913 (void) SetImageProgressMonitor(next,progress_monitor,
1915 if (crop_image == (Image *) NULL)
1919 next->previous=crop_image;
1920 crop_image->next=next;
1921 crop_image=crop_image->next;
1924 if (next == (Image *) NULL)
1926 if (proceed == MagickFalse)
1930 if (crop_image == (Image *) NULL)
1931 transform_image=CloneImage(*image,0,0,MagickTrue,&(*image)->exception);
1934 transform_image=DestroyImage(transform_image);
1935 transform_image=GetFirstImageInList(crop_image);
1937 *image=transform_image;
1939 if (image_geometry == (const char *) NULL)
1942 Scale image to a user specified size.
1944 flags=ParseRegionGeometry(transform_image,image_geometry,&geometry,
1945 &(*image)->exception);
1946 if ((transform_image->columns == geometry.width) &&
1947 (transform_image->rows == geometry.height))
1949 resize_image=ResizeImage(transform_image,geometry.width,geometry.height,
1950 transform_image->filter,transform_image->blur,&(*image)->exception);
1951 if (resize_image == (Image *) NULL)
1952 return(MagickFalse);
1953 transform_image=DestroyImage(transform_image);
1954 transform_image=resize_image;
1955 *image=transform_image;
1960 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1964 % T r a n s f o r m I m a g e s %
1968 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1970 % TransformImages() calls TransformImage() on each image of a sequence.
1972 % The format of the TransformImage method is:
1974 % MagickBooleanType TransformImages(Image **image,
1975 % const char *crop_geometry,const char *image_geometry)
1977 % A description of each parameter follows:
1979 % o image: the image The transformed image is returned as this parameter.
1981 % o crop_geometry: A crop geometry string. This geometry defines a
1982 % subregion of the image to crop.
1984 % o image_geometry: An image geometry string. This geometry defines the
1985 % final size of the image.
1988 MagickExport MagickBooleanType TransformImages(Image **images,
1989 const char *crop_geometry,const char *image_geometry)
2002 assert(images != (Image **) NULL);
2003 assert((*images)->signature == MagickSignature);
2004 if ((*images)->debug != MagickFalse)
2005 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2006 (*images)->filename);
2007 image_list=ImageListToArray(*images,&(*images)->exception);
2008 if (image_list == (Image **) NULL)
2009 return(MagickFalse);
2011 transform_images=NewImageList();
2012 for (i=0; image_list[i] != (Image *) NULL; i++)
2014 image=image_list[i];
2015 status|=TransformImage(&image,crop_geometry,image_geometry);
2016 AppendImageToList(&transform_images,image);
2018 *images=transform_images;
2019 image_list=(Image **) RelinquishMagickMemory(image_list);
2020 return(status != 0 ? MagickTrue : MagickFalse);
2024 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2028 % T r a n s p o s e I m a g e %
2032 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2034 % TransposeImage() creates a horizontal mirror image by reflecting the pixels
2035 % around the central y-axis while rotating them by 90 degrees.
2037 % The format of the TransposeImage method is:
2039 % Image *TransposeImage(const Image *image,ExceptionInfo *exception)
2041 % A description of each parameter follows:
2043 % o image: the image.
2045 % o exception: return any errors or warnings in this structure.
2048 MagickExport Image *TransposeImage(const Image *image,ExceptionInfo *exception)
2050 #define TransposeImageTag "Transpose/Image"
2071 assert(image != (const Image *) NULL);
2072 assert(image->signature == MagickSignature);
2073 if (image->debug != MagickFalse)
2074 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2075 assert(exception != (ExceptionInfo *) NULL);
2076 assert(exception->signature == MagickSignature);
2077 transpose_image=CloneImage(image,image->rows,image->columns,MagickTrue,
2079 if (transpose_image == (Image *) NULL)
2080 return((Image *) NULL);
2086 image_view=AcquireCacheView(image);
2087 transpose_view=AcquireCacheView(transpose_image);
2088 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2089 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
2091 for (y=0; y < (ssize_t) image->rows; y++)
2093 register const PixelPacket
2096 register IndexPacket
2097 *restrict transpose_indexes,
2100 register PixelPacket
2103 if (status == MagickFalse)
2105 p=GetCacheViewVirtualPixels(image_view,0,(ssize_t) image->rows-y-1,
2106 image->columns,1,exception);
2107 q=QueueCacheViewAuthenticPixels(transpose_view,(ssize_t) (image->rows-y-1),
2108 0,1,transpose_image->rows,exception);
2109 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
2114 (void) CopyMagickMemory(q,p,(size_t) image->columns*sizeof(*q));
2115 indexes=GetCacheViewAuthenticIndexQueue(image_view);
2116 if (indexes != (IndexPacket *) NULL)
2118 transpose_indexes=GetCacheViewAuthenticIndexQueue(transpose_view);
2119 if (transpose_indexes != (IndexPacket *) NULL)
2120 (void) CopyMagickMemory(transpose_indexes,indexes,(size_t)
2121 image->columns*sizeof(*transpose_indexes));
2123 if (SyncCacheViewAuthenticPixels(transpose_view,exception) == MagickFalse)
2125 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2130 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2131 #pragma omp critical (MagickCore_TransposeImage)
2133 proceed=SetImageProgress(image,TransposeImageTag,progress++,
2135 if (proceed == MagickFalse)
2139 transpose_view=DestroyCacheView(transpose_view);
2140 image_view=DestroyCacheView(image_view);
2141 transpose_image->type=image->type;
2142 page=transpose_image->page;
2143 Swap(page.width,page.height);
2144 Swap(page.x,page.y);
2145 transpose_image->page=page;
2146 if (status == MagickFalse)
2147 transpose_image=DestroyImage(transpose_image);
2148 return(transpose_image);
2152 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2156 % T r a n s v e r s e I m a g e %
2160 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2162 % TransverseImage() creates a vertical mirror image by reflecting the pixels
2163 % around the central x-axis while rotating them by 270 degrees.
2165 % The format of the TransverseImage method is:
2167 % Image *TransverseImage(const Image *image,ExceptionInfo *exception)
2169 % A description of each parameter follows:
2171 % o image: the image.
2173 % o exception: return any errors or warnings in this structure.
2176 MagickExport Image *TransverseImage(const Image *image,ExceptionInfo *exception)
2178 #define TransverseImageTag "Transverse/Image"
2199 assert(image != (const Image *) NULL);
2200 assert(image->signature == MagickSignature);
2201 if (image->debug != MagickFalse)
2202 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2203 assert(exception != (ExceptionInfo *) NULL);
2204 assert(exception->signature == MagickSignature);
2205 transverse_image=CloneImage(image,image->rows,image->columns,MagickTrue,
2207 if (transverse_image == (Image *) NULL)
2208 return((Image *) NULL);
2214 image_view=AcquireCacheView(image);
2215 transverse_view=AcquireCacheView(transverse_image);
2216 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2217 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
2219 for (y=0; y < (ssize_t) image->rows; y++)
2224 register const PixelPacket
2227 register IndexPacket
2228 *restrict transverse_indexes,
2234 register PixelPacket
2237 if (status == MagickFalse)
2239 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2240 q=QueueCacheViewAuthenticPixels(transverse_view,(ssize_t) (image->rows-y-
2241 1),0,1,transverse_image->rows,exception);
2242 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
2248 for (x=0; x < (ssize_t) image->columns; x++)
2250 indexes=GetCacheViewAuthenticIndexQueue(image_view);
2251 if (indexes != (IndexPacket *) NULL)
2253 transverse_indexes=GetCacheViewAuthenticIndexQueue(transverse_view);
2254 if (transverse_indexes != (IndexPacket *) NULL)
2255 for (x=0; x < (ssize_t) image->columns; x++)
2256 transverse_indexes[image->columns-x-1]=indexes[x];
2258 sync=SyncCacheViewAuthenticPixels(transverse_view,exception);
2259 if (sync == MagickFalse)
2261 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2266 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2267 #pragma omp critical (MagickCore_TransverseImage)
2269 proceed=SetImageProgress(image,TransverseImageTag,progress++,
2271 if (proceed == MagickFalse)
2275 transverse_view=DestroyCacheView(transverse_view);
2276 image_view=DestroyCacheView(image_view);
2277 transverse_image->type=image->type;
2278 page=transverse_image->page;
2279 Swap(page.width,page.height);
2280 Swap(page.x,page.y);
2281 if (page.width != 0)
2282 page.x=(ssize_t) (page.width-transverse_image->columns-page.x);
2283 if (page.height != 0)
2284 page.y=(ssize_t) (page.height-transverse_image->rows-page.y);
2285 transverse_image->page=page;
2286 if (status == MagickFalse)
2287 transverse_image=DestroyImage(transverse_image);
2288 return(transverse_image);
2292 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2296 % T r i m I m a g e %
2300 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2302 % TrimImage() trims pixels from the image edges. It allocates the memory
2303 % necessary for the new Image structure and returns a pointer to the new
2306 % The format of the TrimImage method is:
2308 % Image *TrimImage(const Image *image,ExceptionInfo *exception)
2310 % A description of each parameter follows:
2312 % o image: the image.
2314 % o exception: return any errors or warnings in this structure.
2317 MagickExport Image *TrimImage(const Image *image,ExceptionInfo *exception)
2322 assert(image != (const Image *) NULL);
2323 assert(image->signature == MagickSignature);
2324 if (image->debug != MagickFalse)
2325 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2326 geometry=GetImageBoundingBox(image,exception);
2327 if ((geometry.width == 0) || (geometry.height == 0))
2332 crop_image=CloneImage(image,1,1,MagickTrue,exception);
2333 if (crop_image == (Image *) NULL)
2334 return((Image *) NULL);
2335 crop_image->background_color.opacity=(Quantum) TransparentOpacity;
2336 (void) SetImageBackgroundColor(crop_image);
2337 crop_image->page=image->page;
2338 crop_image->page.x=(-1);
2339 crop_image->page.y=(-1);
2342 geometry.x+=image->page.x;
2343 geometry.y+=image->page.y;
2344 return(CropImage(image,&geometry,exception));