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++=GetIndexPixelComponent(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++=GetIndexPixelComponent(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 SetRedPixelComponent(q,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 SetIndexPixelComponent(indexes+x,QuantumRange-
472 PixelIntensityToQuantum(p));
475 if (SyncCacheViewAuthenticPixels(cmyk_view,exception) == MagickFalse)
478 cmyk_view=DestroyCacheView(cmyk_view);
479 image_view=DestroyCacheView(image_view);
480 AppendImageToList(&cmyk_images,cmyk_image);
481 images=GetNextImageInList(images);
482 if (images == (Image *) NULL)
489 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
493 % C r o p I m a g e %
497 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
499 % CropImage() extracts a region of the image starting at the offset defined
500 % by geometry. Region must be fully defined, and no special handling of
501 % geometry flags is performed.
503 % The format of the CropImage method is:
505 % Image *CropImage(const Image *image,const RectangleInfo *geometry,
506 % ExceptionInfo *exception)
508 % A description of each parameter follows:
510 % o image: the image.
512 % o geometry: Define the region of the image to crop with members
513 % x, y, width, and height.
515 % o exception: return any errors or warnings in this structure.
518 MagickExport Image *CropImage(const Image *image,const RectangleInfo *geometry,
519 ExceptionInfo *exception)
521 #define CropImageTag "Crop/Image"
546 assert(image != (const Image *) NULL);
547 assert(image->signature == MagickSignature);
548 if (image->debug != MagickFalse)
549 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
550 assert(geometry != (const RectangleInfo *) NULL);
551 assert(exception != (ExceptionInfo *) NULL);
552 assert(exception->signature == MagickSignature);
553 bounding_box=image->page;
554 if ((bounding_box.width == 0) || (bounding_box.height == 0))
556 bounding_box.width=image->columns;
557 bounding_box.height=image->rows;
561 page.width=bounding_box.width;
562 if (page.height == 0)
563 page.height=bounding_box.height;
564 if (((bounding_box.x-page.x) >= (ssize_t) page.width) ||
565 ((bounding_box.y-page.y) >= (ssize_t) page.height) ||
566 ((page.x-bounding_box.x) > (ssize_t) image->columns) ||
567 ((page.y-bounding_box.y) > (ssize_t) image->rows))
570 Crop is not within virtual canvas, return 1 pixel transparent image.
572 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
573 "GeometryDoesNotContainImage","`%s'",image->filename);
574 crop_image=CloneImage(image,1,1,MagickTrue,exception);
575 if (crop_image == (Image *) NULL)
576 return((Image *) NULL);
577 crop_image->background_color.opacity=(Quantum) TransparentOpacity;
578 (void) SetImageBackgroundColor(crop_image);
579 crop_image->page=bounding_box;
580 crop_image->page.x=(-1);
581 crop_image->page.y=(-1);
582 if (crop_image->dispose == BackgroundDispose)
583 crop_image->dispose=NoneDispose;
586 if ((page.x < 0) && (bounding_box.x >= 0))
588 page.width+=page.x-bounding_box.x;
593 page.width-=bounding_box.x-page.x;
594 page.x-=bounding_box.x;
598 if ((page.y < 0) && (bounding_box.y >= 0))
600 page.height+=page.y-bounding_box.y;
605 page.height-=bounding_box.y-page.y;
606 page.y-=bounding_box.y;
610 if ((size_t) (page.x+page.width) > image->columns)
611 page.width=image->columns-page.x;
612 if ((geometry->width != 0) && (page.width > geometry->width))
613 page.width=geometry->width;
614 if ((size_t) (page.y+page.height) > image->rows)
615 page.height=image->rows-page.y;
616 if ((geometry->height != 0) && (page.height > geometry->height))
617 page.height=geometry->height;
618 bounding_box.x+=page.x;
619 bounding_box.y+=page.y;
620 if ((page.width == 0) || (page.height == 0))
622 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
623 "GeometryDoesNotContainImage","`%s'",image->filename);
624 return((Image *) NULL);
627 Initialize crop image attributes.
629 crop_image=CloneImage(image,page.width,page.height,MagickTrue,exception);
630 if (crop_image == (Image *) NULL)
631 return((Image *) NULL);
632 crop_image->page.width=image->page.width;
633 crop_image->page.height=image->page.height;
634 if (((ssize_t) (bounding_box.x+bounding_box.width) > (ssize_t) image->page.width) ||
635 ((ssize_t) (bounding_box.y+bounding_box.height) > (ssize_t) image->page.height))
637 crop_image->page.width=bounding_box.width;
638 crop_image->page.height=bounding_box.height;
640 crop_image->page.x=bounding_box.x;
641 crop_image->page.y=bounding_box.y;
647 image_view=AcquireCacheView(image);
648 crop_view=AcquireCacheView(crop_image);
649 #if defined(MAGICKCORE_OPENMP_SUPPORT)
650 #pragma omp parallel for schedule(dynamic,4) shared(progress,status) omp_throttle(1)
652 for (y=0; y < (ssize_t) crop_image->rows; y++)
654 register const IndexPacket
657 register const PixelPacket
661 *restrict crop_indexes;
666 if (status == MagickFalse)
668 p=GetCacheViewVirtualPixels(image_view,page.x,page.y+y,crop_image->columns,
670 q=QueueCacheViewAuthenticPixels(crop_view,0,y,crop_image->columns,1,
672 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
677 indexes=GetCacheViewVirtualIndexQueue(image_view);
678 crop_indexes=GetCacheViewAuthenticIndexQueue(crop_view);
679 (void) CopyMagickMemory(q,p,(size_t) crop_image->columns*sizeof(*p));
680 if ((indexes != (IndexPacket *) NULL) &&
681 (crop_indexes != (IndexPacket *) NULL))
682 (void) CopyMagickMemory(crop_indexes,indexes,(size_t) crop_image->columns*
683 sizeof(*crop_indexes));
684 if (SyncCacheViewAuthenticPixels(crop_view,exception) == MagickFalse)
686 if (image->progress_monitor != (MagickProgressMonitor) NULL)
691 #if defined(MAGICKCORE_OPENMP_SUPPORT)
692 #pragma omp critical (MagickCore_CropImage)
694 proceed=SetImageProgress(image,CropImageTag,progress++,image->rows);
695 if (proceed == MagickFalse)
699 crop_view=DestroyCacheView(crop_view);
700 image_view=DestroyCacheView(image_view);
701 crop_image->type=image->type;
702 if (status == MagickFalse)
703 crop_image=DestroyImage(crop_image);
708 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
712 % C r o p I m a g e T o T i l e s %
716 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
718 % CropImageToTiles() will crop a single image, into a posible list of tiles.
719 % This may include a single sub-region of the image. This basically applies
720 % all the normal geometry flags for Crop.
722 % Image *CropImageToTiles(const Image *image,const RectangleInfo
723 % *crop_geometry, ExceptionInfo *exception)
725 % A description of each parameter follows:
727 % o image: the image The transformed image is returned as this parameter.
729 % o crop_geometry: A crop geometry string.
731 % o exception: return any errors or warnings in this structure.
734 static inline ssize_t MagickRound(MagickRealType x)
737 Round the fraction to nearest integer.
740 return((ssize_t) (x+0.5));
741 return((ssize_t) (x-0.5));
744 MagickExport Image *CropImageToTiles(const Image *image,
745 const char *crop_geometry, ExceptionInfo *exception)
757 assert(image != (Image *) NULL);
758 assert(image->signature == MagickSignature);
759 if (image->debug != MagickFalse)
760 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
762 crop_image=NewImageList();
764 flags=ParseGravityGeometry(image,crop_geometry,&geometry,exception);
766 if ((flags & AreaValue) != 0)
772 MagickProgressMonitor
793 Crop into NxM tiles (@ flag)
795 width=image->columns;
797 if (geometry.width == 0)
799 if (geometry.height == 0)
801 if ((flags & AspectValue) == 0)
803 width-=(geometry.x < 0 ? -1 : 1)*geometry.x;
804 height-=(geometry.y < 0 ? -1 : 1)*geometry.y;
808 width+=(geometry.x < 0 ? -1 : 1)*geometry.x;
809 height+=(geometry.y < 0 ? -1 : 1)*geometry.y;
811 delta.x=(double) width/geometry.width;
812 delta.y=(double) height/geometry.height;
813 /*proceed=MagickTrue;
815 number_images=geometry.width*geometry.height;*/
816 for (offset.y=0; offset.y < (double) height; )
818 if ((flags & AspectValue) == 0)
820 crop.y=(ssize_t) MagickRound((MagickRealType)
821 (offset.y-(geometry.y > 0 ? 0 : geometry.y)));
822 offset.y+=delta.y; /* increment now to find width */
823 crop.height=(size_t) MagickRound((MagickRealType)
824 (offset.y+(geometry.y < 0 ? 0 : geometry.y)));
828 crop.y=(ssize_t) MagickRound((MagickRealType)
829 (offset.y-(geometry.y > 0 ? geometry.y : 0)));
830 offset.y+=delta.y; /* increment now to find width */
831 crop.height=(size_t) MagickRound((MagickRealType)
832 (offset.y+(geometry.y < 0 ? geometry.y : 0)));
835 crop.y+=image->page.y;
836 for (offset.x=0; offset.x < (double) width; )
838 /*progress_monitor=SetImageProgressMonitor(image,
839 (MagickProgressMonitor) NULL,image->client_data);*/
840 if ((flags & AspectValue) == 0)
842 crop.x=(ssize_t) MagickRound((MagickRealType)
843 (offset.x-(geometry.x > 0 ? 0 : geometry.x)));
844 offset.x+=+delta.x; /* increment now to find height*/
845 crop.width=(size_t) MagickRound((MagickRealType)
846 (offset.x+(geometry.x < 0 ? 0 : geometry.x)));
850 crop.x=(ssize_t) MagickRound((MagickRealType) (offset.x-
851 (geometry.x > 0 ? geometry.x : 0)));
852 offset.x+=+delta.x; /* increment now to find height */
853 crop.width=(size_t) MagickRound((MagickRealType)
854 (offset.x+(geometry.x < 0 ? geometry.x : 0)));
857 crop.x+=image->page.x;
858 next=CropImage(image,&crop,exception);
859 /*(void) SetImageProgressMonitor(image,progress_monitor,
861 proceed=SetImageProgress(image,CropImageTag,i++,number_images);
862 if (proceed == MagickFalse)
865 if (next == (Image *) NULL)
867 /*(void) SetImageProgressMonitor(next,progress_monitor,
868 next->client_data);*/
869 AppendImageToList(&crop_image,next);
871 if (next == (Image *) NULL)
873 /*if (proceed == MagickFalse)
879 if (((geometry.width == 0) && (geometry.height == 0)) ||
880 ((flags & XValue) != 0) || ((flags & YValue) != 0))
883 Crop a single region at +X+Y.
885 crop_image=CropImage(image,&geometry,exception);
886 if ((crop_image != (Image *) NULL) && ((flags & AspectValue) != 0))
888 crop_image->page.width=geometry.width;
889 crop_image->page.height=geometry.height;
890 crop_image->page.x-=geometry.x;
891 crop_image->page.y-=geometry.y;
896 if ((image->columns > geometry.width) ||
897 (image->rows > geometry.height))
903 MagickProgressMonitor
924 Crop into tiles of fixed size WxH.
928 page.width=image->columns;
929 if (page.height == 0)
930 page.height=image->rows;
931 width=geometry.width;
934 height=geometry.height;
938 /*proceed=MagickTrue;
941 for (y=0; y < (ssize_t) page.height; y+=(ssize_t) height)
942 for (x=0; x < (ssize_t) page.width; x+=(ssize_t) width)
945 for (y=0; y < (ssize_t) page.height; y+=(ssize_t) height)
947 for (x=0; x < (ssize_t) page.width; x+=(ssize_t) width)
949 /*progress_monitor=SetImageProgressMonitor(image,
950 (MagickProgressMonitor) NULL,image->client_data);*/
951 geometry.width=width;
952 geometry.height=height;
955 next=CropImage(image,&geometry,exception);
956 /*(void) SetImageProgressMonitor(image,progress_monitor,
958 proceed=SetImageProgress(image,CropImageTag,i++,number_images);
959 if (proceed == MagickFalse)
962 if (next == (Image *) NULL)
964 /*(void) SetImageProgressMonitor(next,progress_monitor,
965 next->client_data);*/
966 AppendImageToList(&crop_image,next);
968 if (next == (Image *) NULL)
970 /*if (proceed == MagickFalse)
977 Action of crop results in no change in image!
978 This is not an error so return a clone of the image!
980 return(CloneImage(image,0,0,MagickTrue,exception));
984 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
988 % E x c e r p t I m a g e %
992 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
994 % ExcerptImage() returns a excerpt of the image as defined by the geometry.
996 % The format of the ExcerptImage method is:
998 % Image *ExcerptImage(const Image *image,const RectangleInfo *geometry,
999 % ExceptionInfo *exception)
1001 % A description of each parameter follows:
1003 % o image: the image.
1005 % o geometry: Define the region of the image to extend with members
1006 % x, y, width, and height.
1008 % o exception: return any errors or warnings in this structure.
1011 MagickExport Image *ExcerptImage(const Image *image,
1012 const RectangleInfo *geometry,ExceptionInfo *exception)
1014 #define ExcerptImageTag "Excerpt/Image"
1033 Allocate excerpt image.
1035 assert(image != (const Image *) NULL);
1036 assert(image->signature == MagickSignature);
1037 if (image->debug != MagickFalse)
1038 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1039 assert(geometry != (const RectangleInfo *) NULL);
1040 assert(exception != (ExceptionInfo *) NULL);
1041 assert(exception->signature == MagickSignature);
1042 excerpt_image=CloneImage(image,geometry->width,geometry->height,MagickTrue,
1044 if (excerpt_image == (Image *) NULL)
1045 return((Image *) NULL);
1051 image_view=AcquireCacheView(image);
1052 excerpt_view=AcquireCacheView(excerpt_image);
1053 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1054 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
1056 for (y=0; y < (ssize_t) excerpt_image->rows; y++)
1058 register const PixelPacket
1061 register IndexPacket
1062 *restrict excerpt_indexes,
1065 register PixelPacket
1068 if (status == MagickFalse)
1070 p=GetCacheViewVirtualPixels(image_view,geometry->x,geometry->y+y,
1071 geometry->width,1,exception);
1072 q=GetCacheViewAuthenticPixels(excerpt_view,0,y,excerpt_image->columns,1,
1074 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
1079 (void) CopyMagickMemory(q,p,(size_t) excerpt_image->columns*sizeof(*q));
1080 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1081 if (indexes != (IndexPacket *) NULL)
1083 excerpt_indexes=GetCacheViewAuthenticIndexQueue(excerpt_view);
1084 if (excerpt_indexes != (IndexPacket *) NULL)
1085 (void) CopyMagickMemory(excerpt_indexes,indexes,(size_t)
1086 excerpt_image->columns*sizeof(*excerpt_indexes));
1088 if (SyncCacheViewAuthenticPixels(excerpt_view,exception) == MagickFalse)
1090 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1095 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1096 #pragma omp critical (MagickCore_ExcerptImage)
1098 proceed=SetImageProgress(image,ExcerptImageTag,progress++,image->rows);
1099 if (proceed == MagickFalse)
1103 excerpt_view=DestroyCacheView(excerpt_view);
1104 image_view=DestroyCacheView(image_view);
1105 excerpt_image->type=image->type;
1106 if (status == MagickFalse)
1107 excerpt_image=DestroyImage(excerpt_image);
1108 return(excerpt_image);
1112 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1116 % E x t e n t I m a g e %
1120 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1122 % ExtentImage() extends the image as defined by the geometry, gravity, and
1123 % image background color. Set the (x,y) offset of the geometry to move the
1124 % original image relative to the extended image.
1126 % The format of the ExtentImage method is:
1128 % Image *ExtentImage(const Image *image,const RectangleInfo *geometry,
1129 % ExceptionInfo *exception)
1131 % A description of each parameter follows:
1133 % o image: the image.
1135 % o geometry: Define the region of the image to extend with members
1136 % x, y, width, and height.
1138 % o exception: return any errors or warnings in this structure.
1141 MagickExport Image *ExtentImage(const Image *image,
1142 const RectangleInfo *geometry,ExceptionInfo *exception)
1148 Allocate extent image.
1150 assert(image != (const Image *) NULL);
1151 assert(image->signature == MagickSignature);
1152 if (image->debug != MagickFalse)
1153 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1154 assert(geometry != (const RectangleInfo *) NULL);
1155 assert(exception != (ExceptionInfo *) NULL);
1156 assert(exception->signature == MagickSignature);
1157 extent_image=CloneImage(image,geometry->width,geometry->height,MagickTrue,
1159 if (extent_image == (Image *) NULL)
1160 return((Image *) NULL);
1161 if (SetImageStorageClass(extent_image,DirectClass) == MagickFalse)
1163 InheritException(exception,&extent_image->exception);
1164 extent_image=DestroyImage(extent_image);
1165 return((Image *) NULL);
1167 if (extent_image->background_color.opacity != OpaqueOpacity)
1168 extent_image->matte=MagickTrue;
1169 (void) SetImageBackgroundColor(extent_image);
1170 (void) CompositeImage(extent_image,image->compose,image,-geometry->x,
1172 return(extent_image);
1176 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1180 % F l i p I m a g e %
1184 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1186 % FlipImage() creates a vertical mirror image by reflecting the pixels
1187 % around the central x-axis.
1189 % The format of the FlipImage method is:
1191 % Image *FlipImage(const Image *image,ExceptionInfo *exception)
1193 % A description of each parameter follows:
1195 % o image: the image.
1197 % o exception: return any errors or warnings in this structure.
1200 MagickExport Image *FlipImage(const Image *image,ExceptionInfo *exception)
1202 #define FlipImageTag "Flip/Image"
1223 assert(image != (const Image *) NULL);
1224 assert(image->signature == MagickSignature);
1225 if (image->debug != MagickFalse)
1226 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1227 assert(exception != (ExceptionInfo *) NULL);
1228 assert(exception->signature == MagickSignature);
1229 flip_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
1230 if (flip_image == (Image *) NULL)
1231 return((Image *) NULL);
1238 image_view=AcquireCacheView(image);
1239 flip_view=AcquireCacheView(flip_image);
1240 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1241 #pragma omp parallel for schedule(dynamic,4) shared(progress,status) omp_throttle(1)
1243 for (y=0; y < (ssize_t) flip_image->rows; y++)
1245 register const IndexPacket
1248 register const PixelPacket
1251 register IndexPacket
1252 *restrict flip_indexes;
1254 register PixelPacket
1257 if (status == MagickFalse)
1259 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1260 q=QueueCacheViewAuthenticPixels(flip_view,0,(ssize_t) (flip_image->rows-y-
1261 1),flip_image->columns,1,exception);
1262 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
1267 (void) CopyMagickMemory(q,p,(size_t) image->columns*sizeof(*q));
1268 indexes=GetCacheViewVirtualIndexQueue(image_view);
1269 if (indexes != (const IndexPacket *) NULL)
1271 flip_indexes=GetCacheViewAuthenticIndexQueue(flip_view);
1272 if (flip_indexes != (IndexPacket *) NULL)
1273 (void) CopyMagickMemory(flip_indexes,indexes,(size_t) image->columns*
1274 sizeof(*flip_indexes));
1276 if (SyncCacheViewAuthenticPixels(flip_view,exception) == MagickFalse)
1278 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1283 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1284 #pragma omp critical (MagickCore_FlipImage)
1286 proceed=SetImageProgress(image,FlipImageTag,progress++,image->rows);
1287 if (proceed == MagickFalse)
1291 flip_view=DestroyCacheView(flip_view);
1292 image_view=DestroyCacheView(image_view);
1293 flip_image->type=image->type;
1294 if (page.height != 0)
1295 page.y=(ssize_t) (page.height-flip_image->rows-page.y);
1296 flip_image->page=page;
1297 if (status == MagickFalse)
1298 flip_image=DestroyImage(flip_image);
1303 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1307 % F l o p I m a g e %
1311 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1313 % FlopImage() creates a horizontal mirror image by reflecting the pixels
1314 % around the central y-axis.
1316 % The format of the FlopImage method is:
1318 % Image *FlopImage(const Image *image,ExceptionInfo *exception)
1320 % A description of each parameter follows:
1322 % o image: the image.
1324 % o exception: return any errors or warnings in this structure.
1327 MagickExport Image *FlopImage(const Image *image,ExceptionInfo *exception)
1329 #define FlopImageTag "Flop/Image"
1350 assert(image != (const Image *) NULL);
1351 assert(image->signature == MagickSignature);
1352 if (image->debug != MagickFalse)
1353 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1354 assert(exception != (ExceptionInfo *) NULL);
1355 assert(exception->signature == MagickSignature);
1356 flop_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
1357 if (flop_image == (Image *) NULL)
1358 return((Image *) NULL);
1365 image_view=AcquireCacheView(image);
1366 flop_view=AcquireCacheView(flop_image);
1367 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1368 #pragma omp parallel for schedule(dynamic,4) shared(progress,status) omp_throttle(1)
1370 for (y=0; y < (ssize_t) flop_image->rows; y++)
1372 register const IndexPacket
1375 register const PixelPacket
1378 register IndexPacket
1379 *restrict flop_indexes;
1384 register PixelPacket
1387 if (status == MagickFalse)
1389 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1390 q=QueueCacheViewAuthenticPixels(flop_view,0,y,flop_image->columns,1,
1392 if ((p == (PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
1397 q+=flop_image->columns;
1398 indexes=GetCacheViewVirtualIndexQueue(image_view);
1399 flop_indexes=GetCacheViewAuthenticIndexQueue(flop_view);
1400 for (x=0; x < (ssize_t) flop_image->columns; x++)
1403 if ((indexes != (const IndexPacket *) NULL) &&
1404 (flop_indexes != (IndexPacket *) NULL))
1405 SetIndexPixelComponent(flop_indexes+flop_image->columns-x-1,
1406 GetIndexPixelComponent( indexes+x));
1408 if (SyncCacheViewAuthenticPixels(flop_view,exception) == MagickFalse)
1410 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1415 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1416 #pragma omp critical (MagickCore_FlopImage)
1418 proceed=SetImageProgress(image,FlopImageTag,progress++,image->rows);
1419 if (proceed == MagickFalse)
1423 flop_view=DestroyCacheView(flop_view);
1424 image_view=DestroyCacheView(image_view);
1425 flop_image->type=image->type;
1426 if (page.width != 0)
1427 page.x=(ssize_t) (page.width-flop_image->columns-page.x);
1428 flop_image->page=page;
1429 if (status == MagickFalse)
1430 flop_image=DestroyImage(flop_image);
1435 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1439 % R o l l I m a g e %
1443 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1445 % RollImage() offsets an image as defined by x_offset and y_offset.
1447 % The format of the RollImage method is:
1449 % Image *RollImage(const Image *image,const ssize_t x_offset,
1450 % const ssize_t y_offset,ExceptionInfo *exception)
1452 % A description of each parameter follows:
1454 % o image: the image.
1456 % o x_offset: the number of columns to roll in the horizontal direction.
1458 % o y_offset: the number of rows to roll in the vertical direction.
1460 % o exception: return any errors or warnings in this structure.
1464 static inline MagickBooleanType CopyImageRegion(Image *destination,
1465 const Image *source,const size_t columns,const size_t rows,
1466 const ssize_t sx,const ssize_t sy,const ssize_t dx,const ssize_t dy,
1467 ExceptionInfo *exception)
1480 source_view=AcquireCacheView(source);
1481 destination_view=AcquireCacheView(destination);
1482 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1483 #pragma omp parallel for schedule(dynamic,4) shared(status)
1485 for (y=0; y < (ssize_t) rows; y++)
1490 register const IndexPacket
1493 register const PixelPacket
1496 register IndexPacket
1497 *restrict destination_indexes;
1499 register PixelPacket
1505 if (status == MagickFalse)
1507 p=GetCacheViewVirtualPixels(source_view,sx,sy+y,columns,1,exception);
1508 q=GetCacheViewAuthenticPixels(destination_view,dx,dy+y,columns,1,exception);
1509 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
1514 indexes=GetCacheViewVirtualIndexQueue(source_view);
1515 (void) CopyMagickMemory(q,p,(size_t) columns*sizeof(*p));
1516 if (indexes != (IndexPacket *) NULL)
1518 destination_indexes=GetCacheViewAuthenticIndexQueue(destination_view);
1519 if (destination_indexes != (IndexPacket *) NULL)
1520 (void) CopyMagickMemory(destination_indexes,indexes,(size_t)
1521 columns*sizeof(*indexes));
1523 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
1524 if (sync == MagickFalse)
1527 destination_view=DestroyCacheView(destination_view);
1528 source_view=DestroyCacheView(source_view);
1532 MagickExport Image *RollImage(const Image *image,const ssize_t x_offset,
1533 const ssize_t y_offset,ExceptionInfo *exception)
1535 #define RollImageTag "Roll/Image"
1547 Initialize roll image attributes.
1549 assert(image != (const Image *) NULL);
1550 assert(image->signature == MagickSignature);
1551 if (image->debug != MagickFalse)
1552 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1553 assert(exception != (ExceptionInfo *) NULL);
1554 assert(exception->signature == MagickSignature);
1555 roll_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
1556 if (roll_image == (Image *) NULL)
1557 return((Image *) NULL);
1560 while (offset.x < 0)
1561 offset.x+=(ssize_t) image->columns;
1562 while (offset.x >= (ssize_t) image->columns)
1563 offset.x-=(ssize_t) image->columns;
1564 while (offset.y < 0)
1565 offset.y+=(ssize_t) image->rows;
1566 while (offset.y >= (ssize_t) image->rows)
1567 offset.y-=(ssize_t) image->rows;
1571 status=CopyImageRegion(roll_image,image,(size_t) offset.x,
1572 (size_t) offset.y,(ssize_t) image->columns-offset.x,(ssize_t) image->rows-
1573 offset.y,0,0,exception);
1574 (void) SetImageProgress(image,RollImageTag,0,3);
1575 status|=CopyImageRegion(roll_image,image,image->columns-offset.x,
1576 (size_t) offset.y,0,(ssize_t) image->rows-offset.y,offset.x,0,
1578 (void) SetImageProgress(image,RollImageTag,1,3);
1579 status|=CopyImageRegion(roll_image,image,(size_t) offset.x,image->rows-
1580 offset.y,(ssize_t) image->columns-offset.x,0,0,offset.y,exception);
1581 (void) SetImageProgress(image,RollImageTag,2,3);
1582 status|=CopyImageRegion(roll_image,image,image->columns-offset.x,image->rows-
1583 offset.y,0,0,offset.x,offset.y,exception);
1584 (void) SetImageProgress(image,RollImageTag,3,3);
1585 roll_image->type=image->type;
1586 if (status == MagickFalse)
1587 roll_image=DestroyImage(roll_image);
1592 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1596 % S h a v e I m a g e %
1600 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1602 % ShaveImage() shaves pixels from the image edges. It allocates the memory
1603 % necessary for the new Image structure and returns a pointer to the new
1606 % The format of the ShaveImage method is:
1608 % Image *ShaveImage(const Image *image,const RectangleInfo *shave_info,
1609 % ExceptionInfo *exception)
1611 % A description of each parameter follows:
1613 % o shave_image: Method ShaveImage returns a pointer to the shaved
1614 % image. A null image is returned if there is a memory shortage or
1615 % if the image width or height is zero.
1617 % o image: the image.
1619 % o shave_info: Specifies a pointer to a RectangleInfo which defines the
1620 % region of the image to crop.
1622 % o exception: return any errors or warnings in this structure.
1625 MagickExport Image *ShaveImage(const Image *image,
1626 const RectangleInfo *shave_info,ExceptionInfo *exception)
1634 assert(image != (const Image *) NULL);
1635 assert(image->signature == MagickSignature);
1636 if (image->debug != MagickFalse)
1637 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1638 if (((2*shave_info->width) >= image->columns) ||
1639 ((2*shave_info->height) >= image->rows))
1640 ThrowImageException(OptionWarning,"GeometryDoesNotContainImage");
1641 SetGeometry(image,&geometry);
1642 geometry.width-=2*shave_info->width;
1643 geometry.height-=2*shave_info->height;
1644 geometry.x=(ssize_t) shave_info->width+image->page.x;
1645 geometry.y=(ssize_t) shave_info->height+image->page.y;
1646 shave_image=CropImage(image,&geometry,exception);
1647 if (shave_image == (Image *) NULL)
1648 return((Image *) NULL);
1649 shave_image->page.width-=2*shave_info->width;
1650 shave_image->page.height-=2*shave_info->height;
1651 shave_image->page.x-=(ssize_t) shave_info->width;
1652 shave_image->page.y-=(ssize_t) shave_info->height;
1653 return(shave_image);
1657 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1661 % S p l i c e I m a g e %
1665 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1667 % SpliceImage() splices a solid color into the image as defined by the
1670 % The format of the SpliceImage method is:
1672 % Image *SpliceImage(const Image *image,const RectangleInfo *geometry,
1673 % ExceptionInfo *exception)
1675 % A description of each parameter follows:
1677 % o image: the image.
1679 % o geometry: Define the region of the image to splice with members
1680 % x, y, width, and height.
1682 % o exception: return any errors or warnings in this structure.
1685 MagickExport Image *SpliceImage(const Image *image,
1686 const RectangleInfo *geometry,ExceptionInfo *exception)
1688 #define SpliceImageTag "Splice/Image"
1710 Allocate splice image.
1712 assert(image != (const Image *) NULL);
1713 assert(image->signature == MagickSignature);
1714 if (image->debug != MagickFalse)
1715 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1716 assert(geometry != (const RectangleInfo *) NULL);
1717 assert(exception != (ExceptionInfo *) NULL);
1718 assert(exception->signature == MagickSignature);
1719 splice_geometry=(*geometry);
1720 splice_image=CloneImage(image,image->columns+splice_geometry.width,
1721 image->rows+splice_geometry.height,MagickTrue,exception);
1722 if (splice_image == (Image *) NULL)
1723 return((Image *) NULL);
1724 if (SetImageStorageClass(splice_image,DirectClass) == MagickFalse)
1726 InheritException(exception,&splice_image->exception);
1727 splice_image=DestroyImage(splice_image);
1728 return((Image *) NULL);
1730 (void) SetImageBackgroundColor(splice_image);
1732 Respect image geometry.
1734 switch (image->gravity)
1737 case UndefinedGravity:
1738 case NorthWestGravity:
1742 splice_geometry.x+=(ssize_t) splice_geometry.width/2;
1745 case NorthEastGravity:
1747 splice_geometry.x+=(ssize_t) splice_geometry.width;
1752 splice_geometry.y+=(ssize_t) splice_geometry.width/2;
1758 splice_geometry.x+=(ssize_t) splice_geometry.width/2;
1759 splice_geometry.y+=(ssize_t) splice_geometry.height/2;
1764 splice_geometry.x+=(ssize_t) splice_geometry.width;
1765 splice_geometry.y+=(ssize_t) splice_geometry.height/2;
1768 case SouthWestGravity:
1770 splice_geometry.y+=(ssize_t) splice_geometry.height;
1775 splice_geometry.x+=(ssize_t) splice_geometry.width/2;
1776 splice_geometry.y+=(ssize_t) splice_geometry.height;
1779 case SouthEastGravity:
1781 splice_geometry.x+=(ssize_t) splice_geometry.width;
1782 splice_geometry.y+=(ssize_t) splice_geometry.height;
1791 image_view=AcquireCacheView(image);
1792 splice_view=AcquireCacheView(splice_image);
1793 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1794 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
1796 for (y=0; y < (ssize_t) splice_geometry.y; y++)
1798 register const PixelPacket
1801 register IndexPacket
1803 *restrict splice_indexes;
1808 register PixelPacket
1811 if (status == MagickFalse)
1813 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1814 q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1,
1816 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
1821 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1822 splice_indexes=GetCacheViewAuthenticIndexQueue(splice_view);
1823 for (x=0; x < splice_geometry.x; x++)
1825 SetRedPixelComponent(q,GetRedPixelComponent(p));
1826 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
1827 SetBluePixelComponent(q,GetBluePixelComponent(p));
1828 SetOpacityPixelComponent(q,OpaqueOpacity);
1829 if (image->matte != MagickFalse)
1830 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
1831 if (image->colorspace == CMYKColorspace)
1832 SetIndexPixelComponent(splice_indexes+x,
1833 GetIndexPixelComponent(indexes));
1838 for ( ; x < (ssize_t) (splice_geometry.x+splice_geometry.width); x++)
1840 for ( ; x < (ssize_t) splice_image->columns; x++)
1842 SetRedPixelComponent(q,GetRedPixelComponent(p));
1843 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
1844 SetBluePixelComponent(q,GetBluePixelComponent(p));
1845 SetOpacityPixelComponent(q,OpaqueOpacity);
1846 if (image->matte != MagickFalse)
1847 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
1848 if (image->colorspace == CMYKColorspace)
1849 SetIndexPixelComponent(splice_indexes+x,
1850 GetIndexPixelComponent(indexes));
1855 if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse)
1857 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1862 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1863 #pragma omp critical (MagickCore_TransposeImage)
1865 proceed=SetImageProgress(image,SpliceImageTag,progress++,
1866 splice_image->rows);
1867 if (proceed == MagickFalse)
1871 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1872 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
1874 for (y=(ssize_t) (splice_geometry.y+splice_geometry.height);
1875 y < (ssize_t) splice_image->rows; y++)
1877 register const PixelPacket
1880 register IndexPacket
1882 *restrict splice_indexes;
1887 register PixelPacket
1890 if (status == MagickFalse)
1892 p=GetCacheViewVirtualPixels(image_view,0,y-(ssize_t) splice_geometry.height,
1893 image->columns,1,exception);
1894 if ((y < 0) || (y >= (ssize_t) splice_image->rows))
1896 q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1,
1898 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
1903 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1904 splice_indexes=GetCacheViewAuthenticIndexQueue(splice_view);
1905 for (x=0; x < splice_geometry.x; x++)
1907 SetRedPixelComponent(q,GetRedPixelComponent(p));
1908 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
1909 SetBluePixelComponent(q,GetBluePixelComponent(p));
1910 SetOpacityPixelComponent(q,OpaqueOpacity);
1911 if (image->matte != MagickFalse)
1912 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
1913 if (image->colorspace == CMYKColorspace)
1914 SetIndexPixelComponent(splice_indexes+x,
1915 GetIndexPixelComponent(indexes));
1920 for ( ; x < (ssize_t) (splice_geometry.x+splice_geometry.width); x++)
1922 for ( ; x < (ssize_t) splice_image->columns; x++)
1924 SetRedPixelComponent(q,GetRedPixelComponent(p));
1925 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
1926 SetBluePixelComponent(q,GetBluePixelComponent(p));
1927 SetOpacityPixelComponent(q,OpaqueOpacity);
1928 if (image->matte != MagickFalse)
1929 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
1930 if (image->colorspace == CMYKColorspace)
1931 SetIndexPixelComponent(splice_indexes+x,
1932 GetIndexPixelComponent(indexes));
1937 if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse)
1939 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1944 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1945 #pragma omp critical (MagickCore_TransposeImage)
1947 proceed=SetImageProgress(image,SpliceImageTag,progress++,
1948 splice_image->rows);
1949 if (proceed == MagickFalse)
1953 splice_view=DestroyCacheView(splice_view);
1954 image_view=DestroyCacheView(image_view);
1955 if (status == MagickFalse)
1956 splice_image=DestroyImage(splice_image);
1957 return(splice_image);
1961 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1965 % T r a n s f o r m I m a g e %
1969 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1971 % TransformImage() is a convenience method that behaves like ResizeImage() or
1972 % CropImage() but accepts scaling and/or cropping information as a region
1973 % geometry specification. If the operation fails, the original image handle
1976 % This should only be used for single images.
1978 % The format of the TransformImage method is:
1980 % MagickBooleanType TransformImage(Image **image,const char *crop_geometry,
1981 % const char *image_geometry)
1983 % A description of each parameter follows:
1985 % o image: the image The transformed image is returned as this parameter.
1987 % o crop_geometry: A crop geometry string. This geometry defines a
1988 % subregion of the image to crop.
1990 % o image_geometry: An image geometry string. This geometry defines the
1991 % final size of the image.
1995 DANGER: This function destroys what it assumes to be a single image list.
1996 If the input image is part of a larger list, all other images in that list
1997 will be simply 'lost', not destroyed.
1999 Also if the crop generates a list of images only the first image is resized.
2000 And finally if the crop succeeds and the resize failed, you will get a
2001 cropped image, as well as a 'false' or 'failed' report.
2003 This function and should probably be depreciated in favor of direct calls
2004 to CropImageToTiles() or ResizeImage(), as appropriate.
2007 MagickExport MagickBooleanType TransformImage(Image **image,
2008 const char *crop_geometry,const char *image_geometry)
2020 assert(image != (Image **) NULL);
2021 assert((*image)->signature == MagickSignature);
2022 if ((*image)->debug != MagickFalse)
2023 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
2024 transform_image=(*image);
2025 if (crop_geometry != (const char *) NULL)
2031 Crop image to a user specified size.
2033 crop_image=CropImageToTiles(*image,crop_geometry,&(*image)->exception);
2034 if (crop_image == (Image *) NULL)
2035 transform_image=CloneImage(*image,0,0,MagickTrue,&(*image)->exception);
2038 transform_image=DestroyImage(transform_image);
2039 transform_image=GetFirstImageInList(crop_image);
2041 *image=transform_image;
2043 if (image_geometry == (const char *) NULL)
2047 Scale image to a user specified size.
2049 flags=ParseRegionGeometry(transform_image,image_geometry,&geometry,
2050 &(*image)->exception);
2052 if ((transform_image->columns == geometry.width) &&
2053 (transform_image->rows == geometry.height))
2055 resize_image=ResizeImage(transform_image,geometry.width,geometry.height,
2056 transform_image->filter,transform_image->blur,&(*image)->exception);
2057 if (resize_image == (Image *) NULL)
2058 return(MagickFalse);
2059 transform_image=DestroyImage(transform_image);
2060 transform_image=resize_image;
2061 *image=transform_image;
2066 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2070 % T r a n s f o r m I m a g e s %
2074 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2076 % TransformImages() calls TransformImage() on each image of a sequence.
2078 % The format of the TransformImage method is:
2080 % MagickBooleanType TransformImages(Image **image,
2081 % const char *crop_geometry,const char *image_geometry)
2083 % A description of each parameter follows:
2085 % o image: the image The transformed image is returned as this parameter.
2087 % o crop_geometry: A crop geometry string. This geometry defines a
2088 % subregion of the image to crop.
2090 % o image_geometry: An image geometry string. This geometry defines the
2091 % final size of the image.
2094 MagickExport MagickBooleanType TransformImages(Image **images,
2095 const char *crop_geometry,const char *image_geometry)
2108 assert(images != (Image **) NULL);
2109 assert((*images)->signature == MagickSignature);
2110 if ((*images)->debug != MagickFalse)
2111 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2112 (*images)->filename);
2113 image_list=ImageListToArray(*images,&(*images)->exception);
2114 if (image_list == (Image **) NULL)
2115 return(MagickFalse);
2117 transform_images=NewImageList();
2118 for (i=0; image_list[i] != (Image *) NULL; i++)
2120 image=image_list[i];
2121 status|=TransformImage(&image,crop_geometry,image_geometry);
2122 AppendImageToList(&transform_images,image);
2124 *images=transform_images;
2125 image_list=(Image **) RelinquishMagickMemory(image_list);
2126 return(status != 0 ? MagickTrue : MagickFalse);
2130 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2134 % T r a n s p o s e I m a g e %
2138 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2140 % TransposeImage() creates a horizontal mirror image by reflecting the pixels
2141 % around the central y-axis while rotating them by 90 degrees.
2143 % The format of the TransposeImage method is:
2145 % Image *TransposeImage(const Image *image,ExceptionInfo *exception)
2147 % A description of each parameter follows:
2149 % o image: the image.
2151 % o exception: return any errors or warnings in this structure.
2154 MagickExport Image *TransposeImage(const Image *image,ExceptionInfo *exception)
2156 #define TransposeImageTag "Transpose/Image"
2177 assert(image != (const Image *) NULL);
2178 assert(image->signature == MagickSignature);
2179 if (image->debug != MagickFalse)
2180 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2181 assert(exception != (ExceptionInfo *) NULL);
2182 assert(exception->signature == MagickSignature);
2183 transpose_image=CloneImage(image,image->rows,image->columns,MagickTrue,
2185 if (transpose_image == (Image *) NULL)
2186 return((Image *) NULL);
2192 image_view=AcquireCacheView(image);
2193 transpose_view=AcquireCacheView(transpose_image);
2194 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2195 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
2197 for (y=0; y < (ssize_t) image->rows; y++)
2199 register const PixelPacket
2202 register IndexPacket
2203 *restrict transpose_indexes,
2206 register PixelPacket
2209 if (status == MagickFalse)
2211 p=GetCacheViewVirtualPixels(image_view,0,(ssize_t) image->rows-y-1,
2212 image->columns,1,exception);
2213 q=QueueCacheViewAuthenticPixels(transpose_view,(ssize_t) (image->rows-y-1),
2214 0,1,transpose_image->rows,exception);
2215 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
2220 (void) CopyMagickMemory(q,p,(size_t) image->columns*sizeof(*q));
2221 indexes=GetCacheViewAuthenticIndexQueue(image_view);
2222 if (indexes != (IndexPacket *) NULL)
2224 transpose_indexes=GetCacheViewAuthenticIndexQueue(transpose_view);
2225 if (transpose_indexes != (IndexPacket *) NULL)
2226 (void) CopyMagickMemory(transpose_indexes,indexes,(size_t)
2227 image->columns*sizeof(*transpose_indexes));
2229 if (SyncCacheViewAuthenticPixels(transpose_view,exception) == MagickFalse)
2231 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2236 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2237 #pragma omp critical (MagickCore_TransposeImage)
2239 proceed=SetImageProgress(image,TransposeImageTag,progress++,
2241 if (proceed == MagickFalse)
2245 transpose_view=DestroyCacheView(transpose_view);
2246 image_view=DestroyCacheView(image_view);
2247 transpose_image->type=image->type;
2248 page=transpose_image->page;
2249 Swap(page.width,page.height);
2250 Swap(page.x,page.y);
2251 transpose_image->page=page;
2252 if (status == MagickFalse)
2253 transpose_image=DestroyImage(transpose_image);
2254 return(transpose_image);
2258 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2262 % T r a n s v e r s e I m a g e %
2266 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2268 % TransverseImage() creates a vertical mirror image by reflecting the pixels
2269 % around the central x-axis while rotating them by 270 degrees.
2271 % The format of the TransverseImage method is:
2273 % Image *TransverseImage(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 *TransverseImage(const Image *image,ExceptionInfo *exception)
2284 #define TransverseImageTag "Transverse/Image"
2305 assert(image != (const Image *) NULL);
2306 assert(image->signature == MagickSignature);
2307 if (image->debug != MagickFalse)
2308 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2309 assert(exception != (ExceptionInfo *) NULL);
2310 assert(exception->signature == MagickSignature);
2311 transverse_image=CloneImage(image,image->rows,image->columns,MagickTrue,
2313 if (transverse_image == (Image *) NULL)
2314 return((Image *) NULL);
2320 image_view=AcquireCacheView(image);
2321 transverse_view=AcquireCacheView(transverse_image);
2322 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2323 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
2325 for (y=0; y < (ssize_t) image->rows; y++)
2330 register const PixelPacket
2333 register IndexPacket
2334 *restrict transverse_indexes,
2340 register PixelPacket
2343 if (status == MagickFalse)
2345 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2346 q=QueueCacheViewAuthenticPixels(transverse_view,(ssize_t) (image->rows-y-
2347 1),0,1,transverse_image->rows,exception);
2348 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
2354 for (x=0; x < (ssize_t) image->columns; x++)
2356 indexes=GetCacheViewAuthenticIndexQueue(image_view);
2357 if (indexes != (IndexPacket *) NULL)
2359 transverse_indexes=GetCacheViewAuthenticIndexQueue(transverse_view);
2360 if (transverse_indexes != (IndexPacket *) NULL)
2361 for (x=0; x < (ssize_t) image->columns; x++)
2362 SetIndexPixelComponent(transverse_indexes+image->columns-x-1,
2363 GetIndexPixelComponent(indexes+x));
2365 sync=SyncCacheViewAuthenticPixels(transverse_view,exception);
2366 if (sync == MagickFalse)
2368 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2373 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2374 #pragma omp critical (MagickCore_TransverseImage)
2376 proceed=SetImageProgress(image,TransverseImageTag,progress++,
2378 if (proceed == MagickFalse)
2382 transverse_view=DestroyCacheView(transverse_view);
2383 image_view=DestroyCacheView(image_view);
2384 transverse_image->type=image->type;
2385 page=transverse_image->page;
2386 Swap(page.width,page.height);
2387 Swap(page.x,page.y);
2388 if (page.width != 0)
2389 page.x=(ssize_t) (page.width-transverse_image->columns-page.x);
2390 if (page.height != 0)
2391 page.y=(ssize_t) (page.height-transverse_image->rows-page.y);
2392 transverse_image->page=page;
2393 if (status == MagickFalse)
2394 transverse_image=DestroyImage(transverse_image);
2395 return(transverse_image);
2399 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2403 % T r i m I m a g e %
2407 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2409 % TrimImage() trims pixels from the image edges. It allocates the memory
2410 % necessary for the new Image structure and returns a pointer to the new
2413 % The format of the TrimImage method is:
2415 % Image *TrimImage(const Image *image,ExceptionInfo *exception)
2417 % A description of each parameter follows:
2419 % o image: the image.
2421 % o exception: return any errors or warnings in this structure.
2424 MagickExport Image *TrimImage(const Image *image,ExceptionInfo *exception)
2429 assert(image != (const Image *) NULL);
2430 assert(image->signature == MagickSignature);
2431 if (image->debug != MagickFalse)
2432 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2433 geometry=GetImageBoundingBox(image,exception);
2434 if ((geometry.width == 0) || (geometry.height == 0))
2439 crop_image=CloneImage(image,1,1,MagickTrue,exception);
2440 if (crop_image == (Image *) NULL)
2441 return((Image *) NULL);
2442 crop_image->background_color.opacity=(Quantum) TransparentOpacity;
2443 (void) SetImageBackgroundColor(crop_image);
2444 crop_image->page=image->page;
2445 crop_image->page.x=(-1);
2446 crop_image->page.y=(-1);
2449 geometry.x+=image->page.x;
2450 geometry.y+=image->page.y;
2451 return(CropImage(image,&geometry,exception));