2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % TTTTT RRRR AAA N N SSSSS FFFFF OOO RRRR M M %
7 % T R R A A NN N SS F O O R R MM MM %
8 % T RRRR AAAAA N N N SSS FFF O O RRRR M M M %
9 % T R R A A N NN SS F O O R R M M %
10 % T R R A A N N SSSSS F OOO R R M M %
13 % MagickCore Image Transform Methods %
20 % Copyright 1999-2010 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
42 #include "magick/studio.h"
43 #include "magick/attribute.h"
44 #include "magick/cache.h"
45 #include "magick/cache-view.h"
46 #include "magick/color.h"
47 #include "magick/color-private.h"
48 #include "magick/colorspace-private.h"
49 #include "magick/composite.h"
50 #include "magick/draw.h"
51 #include "magick/effect.h"
52 #include "magick/exception.h"
53 #include "magick/exception-private.h"
54 #include "magick/geometry.h"
55 #include "magick/image.h"
56 #include "magick/memory_.h"
57 #include "magick/layer.h"
58 #include "magick/list.h"
59 #include "magick/monitor.h"
60 #include "magick/monitor-private.h"
61 #include "magick/pixel-private.h"
62 #include "magick/resource_.h"
63 #include "magick/resize.h"
64 #include "magick/statistic.h"
65 #include "magick/string_.h"
66 #include "magick/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"
126 assert(image != (const Image *) NULL);
127 assert(image->signature == MagickSignature);
128 if (image->debug != MagickFalse)
129 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
130 assert(exception != (ExceptionInfo *) NULL);
131 assert(exception->signature == MagickSignature);
132 assert(chop_info != (RectangleInfo *) NULL);
133 if (((chop_info->x+(ssize_t) chop_info->width) < 0) ||
134 ((chop_info->y+(ssize_t) chop_info->height) < 0) ||
135 (chop_info->x > (ssize_t) image->columns) ||
136 (chop_info->y > (ssize_t) image->rows))
137 ThrowImageException(OptionWarning,"GeometryDoesNotContainImage");
139 if ((extent.x+(ssize_t) extent.width) > (ssize_t) image->columns)
140 extent.width=(size_t) ((ssize_t) image->columns-extent.x);
141 if ((extent.y+(ssize_t) extent.height) > (ssize_t) image->rows)
142 extent.height=(size_t) ((ssize_t) image->rows-extent.y);
145 extent.width-=(size_t) (-extent.x);
150 extent.height-=(size_t) (-extent.y);
153 chop_image=CloneImage(image,image->columns-extent.width,image->rows-
154 extent.height,MagickTrue,exception);
155 if (chop_image == (Image *) NULL)
156 return((Image *) NULL);
163 image_view=AcquireCacheView(image);
164 chop_view=AcquireCacheView(chop_image);
165 #if defined(MAGICKCORE_OPENMP_SUPPORT)
166 #pragma omp parallel for schedule(dynamic,4) shared(status) omp_throttle(1)
168 for (y=0; y < (ssize_t) extent.y; y++)
170 register const PixelPacket
174 *restrict chop_indexes,
183 if (status == MagickFalse)
185 p=GetCacheViewVirtualPixels(image_view,0,i++,image->columns,1,exception);
186 q=QueueCacheViewAuthenticPixels(chop_view,0,j++,chop_image->columns,1,
188 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
193 indexes=GetCacheViewAuthenticIndexQueue(image_view);
194 chop_indexes=GetCacheViewAuthenticIndexQueue(chop_view);
195 for (x=0; x < (ssize_t) image->columns; x++)
197 if ((x < extent.x) || (x >= (ssize_t) (extent.x+extent.width)))
200 if (indexes != (IndexPacket *) NULL)
202 if (chop_indexes != (IndexPacket *) NULL)
203 *chop_indexes++=indexes[x];
209 if (SyncCacheViewAuthenticPixels(chop_view,exception) == MagickFalse)
211 proceed=SetImageProgress(image,ChopImageTag,(MagickOffsetType) y,
213 if (proceed == MagickFalse)
219 i+=(ssize_t) extent.height;
220 #if defined(MAGICKCORE_OPENMP_SUPPORT)
221 #pragma omp parallel for schedule(dynamic,4) shared(status) omp_throttle(1)
223 for (y=0; y < (ssize_t) (image->rows-(extent.y+extent.height)); y++)
225 register const PixelPacket
229 *restrict chop_indexes,
238 if (status == MagickFalse)
240 p=GetCacheViewVirtualPixels(image_view,0,i++,image->columns,1,exception);
241 q=QueueCacheViewAuthenticPixels(chop_view,0,j++,chop_image->columns,1,
243 if ((p == (PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
248 indexes=GetCacheViewAuthenticIndexQueue(image_view);
249 chop_indexes=GetCacheViewAuthenticIndexQueue(chop_view);
250 for (x=0; x < (ssize_t) image->columns; x++)
252 if ((x < extent.x) || (x >= (ssize_t) (extent.x+extent.width)))
255 if (indexes != (IndexPacket *) NULL)
257 if (chop_indexes != (IndexPacket *) NULL)
258 *chop_indexes++=indexes[x];
264 if (SyncCacheViewAuthenticPixels(chop_view,exception) == MagickFalse)
266 proceed=SetImageProgress(image,ChopImageTag,(MagickOffsetType) y,
268 if (proceed == MagickFalse)
271 chop_view=DestroyCacheView(chop_view);
272 image_view=DestroyCacheView(image_view);
273 chop_image->type=image->type;
278 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
282 + C o n s o l i d a t e C M Y K I m a g e %
286 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
288 % ConsolidateCMYKImage() consolidates separate C, M, Y, and K planes into a
291 % The format of the ConsolidateCMYKImage method is:
293 % Image *ConsolidateCMYKImage(const Image *image,ExceptionInfo *exception)
295 % A description of each parameter follows:
297 % o image: the image sequence.
299 % o exception: return any errors or warnings in this structure.
302 MagickExport Image *ConsolidateCMYKImages(const Image *images,
303 ExceptionInfo *exception)
320 Consolidate separate C, M, Y, and K planes into a single image.
322 assert(images != (Image *) NULL);
323 assert(images->signature == MagickSignature);
324 if (images->debug != MagickFalse)
325 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
326 assert(exception != (ExceptionInfo *) NULL);
327 assert(exception->signature == MagickSignature);
328 cmyk_images=NewImageList();
329 for (i=0; i < (ssize_t) GetImageListLength(images); i+=4)
331 cmyk_image=CloneImage(images,images->columns,images->rows,MagickTrue,
333 if (cmyk_image == (Image *) NULL)
335 if (SetImageStorageClass(cmyk_image,DirectClass) == MagickFalse)
337 (void) SetImageColorspace(cmyk_image,CMYKColorspace);
338 image_view=AcquireCacheView(images);
339 cmyk_view=AcquireCacheView(cmyk_image);
340 for (y=0; y < (ssize_t) images->rows; y++)
342 register const PixelPacket
351 p=GetCacheViewVirtualPixels(image_view,0,y,images->columns,1,exception);
352 q=QueueCacheViewAuthenticPixels(cmyk_view,0,y,cmyk_image->columns,1,
354 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
356 for (x=0; x < (ssize_t) images->columns; x++)
358 q->red=(Quantum) (QuantumRange-PixelIntensityToQuantum(p));
362 if (SyncCacheViewAuthenticPixels(cmyk_view,exception) == MagickFalse)
365 cmyk_view=DestroyCacheView(cmyk_view);
366 image_view=DestroyCacheView(image_view);
367 images=GetNextImageInList(images);
368 if (images == (Image *) NULL)
370 image_view=AcquireCacheView(images);
371 cmyk_view=AcquireCacheView(cmyk_image);
372 for (y=0; y < (ssize_t) images->rows; y++)
374 register const PixelPacket
383 p=GetCacheViewVirtualPixels(image_view,0,y,images->columns,1,exception);
384 q=GetCacheViewAuthenticPixels(cmyk_view,0,y,cmyk_image->columns,1,
386 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
388 for (x=0; x < (ssize_t) images->columns; x++)
390 q->green=(Quantum) (QuantumRange-PixelIntensityToQuantum(p));
394 if (SyncCacheViewAuthenticPixels(cmyk_view,exception) == MagickFalse)
397 cmyk_view=DestroyCacheView(cmyk_view);
398 image_view=DestroyCacheView(image_view);
399 images=GetNextImageInList(images);
400 if (images == (Image *) NULL)
402 image_view=AcquireCacheView(images);
403 cmyk_view=AcquireCacheView(cmyk_image);
404 for (y=0; y < (ssize_t) images->rows; y++)
406 register const PixelPacket
415 p=GetCacheViewVirtualPixels(image_view,0,y,images->columns,1,exception);
416 q=GetCacheViewAuthenticPixels(cmyk_view,0,y,cmyk_image->columns,1,
418 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
420 for (x=0; x < (ssize_t) images->columns; x++)
422 q->blue=(Quantum) (QuantumRange-PixelIntensityToQuantum(p));
426 if (SyncCacheViewAuthenticPixels(cmyk_view,exception) == MagickFalse)
429 cmyk_view=DestroyCacheView(cmyk_view);
430 image_view=DestroyCacheView(image_view);
431 images=GetNextImageInList(images);
432 if (images == (Image *) NULL)
434 image_view=AcquireCacheView(images);
435 cmyk_view=AcquireCacheView(cmyk_image);
436 for (y=0; y < (ssize_t) images->rows; y++)
438 register const PixelPacket
450 p=GetCacheViewVirtualPixels(image_view,0,y,images->columns,1,exception);
451 q=GetCacheViewAuthenticPixels(cmyk_view,0,y,cmyk_image->columns,1,
453 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
455 indexes=GetCacheViewAuthenticIndexQueue(cmyk_view);
456 for (x=0; x < (ssize_t) images->columns; x++)
458 indexes[x]=(IndexPacket) (QuantumRange-PixelIntensityToQuantum(p));
461 if (SyncCacheViewAuthenticPixels(cmyk_view,exception) == MagickFalse)
464 cmyk_view=DestroyCacheView(cmyk_view);
465 image_view=DestroyCacheView(image_view);
466 AppendImageToList(&cmyk_images,cmyk_image);
467 images=GetNextImageInList(images);
468 if (images == (Image *) NULL)
475 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
479 % C r o p I m a g e %
483 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
485 % CropImage() extracts a region of the image starting at the offset defined
488 % The format of the CropImage method is:
490 % Image *CropImage(const Image *image,const RectangleInfo *geometry,
491 % ExceptionInfo *exception)
493 % A description of each parameter follows:
495 % o image: the image.
497 % o geometry: Define the region of the image to crop with members
498 % x, y, width, and height.
500 % o exception: return any errors or warnings in this structure.
503 MagickExport Image *CropImage(const Image *image,const RectangleInfo *geometry,
504 ExceptionInfo *exception)
506 #define CropImageTag "Crop/Image"
531 assert(image != (const Image *) NULL);
532 assert(image->signature == MagickSignature);
533 if (image->debug != MagickFalse)
534 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
535 assert(geometry != (const RectangleInfo *) NULL);
536 assert(exception != (ExceptionInfo *) NULL);
537 assert(exception->signature == MagickSignature);
538 bounding_box=image->page;
539 if ((bounding_box.width == 0) || (bounding_box.height == 0))
541 bounding_box.width=image->columns;
542 bounding_box.height=image->rows;
546 page.width=bounding_box.width;
547 if (page.height == 0)
548 page.height=bounding_box.height;
549 if (((bounding_box.x-page.x) >= (ssize_t) page.width) ||
550 ((bounding_box.y-page.y) >= (ssize_t) page.height) ||
551 ((page.x-bounding_box.x) > (ssize_t) image->columns) ||
552 ((page.y-bounding_box.y) > (ssize_t) image->rows))
555 Crop is not within virtual canvas, return 1 pixel transparent image.
557 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
558 "GeometryDoesNotContainImage","`%s'",image->filename);
559 crop_image=CloneImage(image,1,1,MagickTrue,exception);
560 if (crop_image == (Image *) NULL)
561 return((Image *) NULL);
562 crop_image->background_color.opacity=(Quantum) TransparentOpacity;
563 (void) SetImageBackgroundColor(crop_image);
564 crop_image->page=bounding_box;
565 crop_image->page.x=(-1);
566 crop_image->page.y=(-1);
567 if (crop_image->dispose == BackgroundDispose)
568 crop_image->dispose=NoneDispose;
571 if ((page.x < 0) && (bounding_box.x >= 0))
573 page.width+=page.x-bounding_box.x;
578 page.width-=bounding_box.x-page.x;
579 page.x-=bounding_box.x;
583 if ((page.y < 0) && (bounding_box.y >= 0))
585 page.height+=page.y-bounding_box.y;
590 page.height-=bounding_box.y-page.y;
591 page.y-=bounding_box.y;
595 if ((size_t) (page.x+page.width) > image->columns)
596 page.width=image->columns-page.x;
597 if ((geometry->width != 0) && (page.width > geometry->width))
598 page.width=geometry->width;
599 if ((size_t) (page.y+page.height) > image->rows)
600 page.height=image->rows-page.y;
601 if ((geometry->height != 0) && (page.height > geometry->height))
602 page.height=geometry->height;
603 bounding_box.x+=page.x;
604 bounding_box.y+=page.y;
605 if ((page.width == 0) || (page.height == 0))
607 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
608 "GeometryDoesNotContainImage","`%s'",image->filename);
609 return((Image *) NULL);
612 Initialize crop image attributes.
614 crop_image=CloneImage(image,page.width,page.height,MagickTrue,exception);
615 if (crop_image == (Image *) NULL)
616 return((Image *) NULL);
617 crop_image->page.width=image->page.width;
618 crop_image->page.height=image->page.height;
619 if (((ssize_t) (bounding_box.x+bounding_box.width) > (ssize_t) image->page.width) ||
620 ((ssize_t) (bounding_box.y+bounding_box.height) > (ssize_t) image->page.height))
622 crop_image->page.width=bounding_box.width;
623 crop_image->page.height=bounding_box.height;
625 crop_image->page.x=bounding_box.x;
626 crop_image->page.y=bounding_box.y;
632 image_view=AcquireCacheView(image);
633 crop_view=AcquireCacheView(crop_image);
634 #if defined(MAGICKCORE_OPENMP_SUPPORT)
635 #pragma omp parallel for schedule(dynamic,4) shared(progress,status) omp_throttle(1)
637 for (y=0; y < (ssize_t) crop_image->rows; y++)
639 register const IndexPacket
642 register const PixelPacket
646 *restrict crop_indexes;
651 if (status == MagickFalse)
653 p=GetCacheViewVirtualPixels(image_view,page.x,page.y+y,crop_image->columns,
655 q=QueueCacheViewAuthenticPixels(crop_view,0,y,crop_image->columns,1,
657 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
662 indexes=GetCacheViewVirtualIndexQueue(image_view);
663 crop_indexes=GetCacheViewAuthenticIndexQueue(crop_view);
664 (void) CopyMagickMemory(q,p,(size_t) crop_image->columns*sizeof(*p));
665 if ((indexes != (IndexPacket *) NULL) &&
666 (crop_indexes != (IndexPacket *) NULL))
667 (void) CopyMagickMemory(crop_indexes,indexes,(size_t) crop_image->columns*
668 sizeof(*crop_indexes));
669 if (SyncCacheViewAuthenticPixels(crop_view,exception) == MagickFalse)
671 if (image->progress_monitor != (MagickProgressMonitor) NULL)
676 #if defined(MAGICKCORE_OPENMP_SUPPORT)
677 #pragma omp critical (MagickCore_CropImage)
679 proceed=SetImageProgress(image,CropImageTag,progress++,image->rows);
680 if (proceed == MagickFalse)
684 crop_view=DestroyCacheView(crop_view);
685 image_view=DestroyCacheView(image_view);
686 crop_image->type=image->type;
687 if (status == MagickFalse)
688 crop_image=DestroyImage(crop_image);
693 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
697 % E x c e r p t I m a g e %
701 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
703 % ExcerptImage() returns a excerpt of the image as defined by the geometry.
705 % The format of the ExcerptImage method is:
707 % Image *ExcerptImage(const Image *image,const RectangleInfo *geometry,
708 % ExceptionInfo *exception)
710 % A description of each parameter follows:
712 % o image: the image.
714 % o geometry: Define the region of the image to extend with members
715 % x, y, width, and height.
717 % o exception: return any errors or warnings in this structure.
720 MagickExport Image *ExcerptImage(const Image *image,
721 const RectangleInfo *geometry,ExceptionInfo *exception)
723 #define ExcerptImageTag "Excerpt/Image"
742 Allocate excerpt image.
744 assert(image != (const Image *) NULL);
745 assert(image->signature == MagickSignature);
746 if (image->debug != MagickFalse)
747 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
748 assert(geometry != (const RectangleInfo *) NULL);
749 assert(exception != (ExceptionInfo *) NULL);
750 assert(exception->signature == MagickSignature);
751 excerpt_image=CloneImage(image,geometry->width,geometry->height,MagickTrue,
753 if (excerpt_image == (Image *) NULL)
754 return((Image *) NULL);
760 image_view=AcquireCacheView(image);
761 excerpt_view=AcquireCacheView(excerpt_image);
762 #if defined(MAGICKCORE_OPENMP_SUPPORT)
763 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
765 for (y=0; y < (ssize_t) excerpt_image->rows; y++)
767 register const PixelPacket
771 *restrict excerpt_indexes,
777 if (status == MagickFalse)
779 p=GetCacheViewVirtualPixels(image_view,geometry->x,geometry->y+y,
780 geometry->width,1,exception);
781 q=GetCacheViewAuthenticPixels(excerpt_view,0,y,excerpt_image->columns,1,
783 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
788 (void) CopyMagickMemory(q,p,(size_t) excerpt_image->columns*sizeof(*q));
789 indexes=GetCacheViewAuthenticIndexQueue(image_view);
790 if (indexes != (IndexPacket *) NULL)
792 excerpt_indexes=GetCacheViewAuthenticIndexQueue(excerpt_view);
793 if (excerpt_indexes != (IndexPacket *) NULL)
794 (void) CopyMagickMemory(excerpt_indexes,indexes,(size_t)
795 excerpt_image->columns*sizeof(*excerpt_indexes));
797 if (SyncCacheViewAuthenticPixels(excerpt_view,exception) == MagickFalse)
799 if (image->progress_monitor != (MagickProgressMonitor) NULL)
804 #if defined(MAGICKCORE_OPENMP_SUPPORT)
805 #pragma omp critical (MagickCore_ExcerptImage)
807 proceed=SetImageProgress(image,ExcerptImageTag,progress++,image->rows);
808 if (proceed == MagickFalse)
812 excerpt_view=DestroyCacheView(excerpt_view);
813 image_view=DestroyCacheView(image_view);
814 excerpt_image->type=image->type;
815 if (status == MagickFalse)
816 excerpt_image=DestroyImage(excerpt_image);
817 return(excerpt_image);
821 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
825 % E x t e n t I m a g e %
829 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
831 % ExtentImage() extends the image as defined by the geometry, gravity, and
832 % image background color. Set the (x,y) offset of the geometry to move the
833 % original image relative to the extended image.
835 % The format of the ExtentImage method is:
837 % Image *ExtentImage(const Image *image,const RectangleInfo *geometry,
838 % ExceptionInfo *exception)
840 % A description of each parameter follows:
842 % o image: the image.
844 % o geometry: Define the region of the image to extend with members
845 % x, y, width, and height.
847 % o exception: return any errors or warnings in this structure.
850 MagickExport Image *ExtentImage(const Image *image,
851 const RectangleInfo *geometry,ExceptionInfo *exception)
857 Allocate extent image.
859 assert(image != (const Image *) NULL);
860 assert(image->signature == MagickSignature);
861 if (image->debug != MagickFalse)
862 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
863 assert(geometry != (const RectangleInfo *) NULL);
864 assert(exception != (ExceptionInfo *) NULL);
865 assert(exception->signature == MagickSignature);
866 extent_image=CloneImage(image,geometry->width,geometry->height,MagickTrue,
868 if (extent_image == (Image *) NULL)
869 return((Image *) NULL);
870 if (SetImageStorageClass(extent_image,DirectClass) == MagickFalse)
872 InheritException(exception,&extent_image->exception);
873 extent_image=DestroyImage(extent_image);
874 return((Image *) NULL);
876 if (extent_image->background_color.opacity != OpaqueOpacity)
877 extent_image->matte=MagickTrue;
878 (void) SetImageBackgroundColor(extent_image);
879 (void) CompositeImage(extent_image,image->compose,image,-geometry->x,
881 return(extent_image);
885 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
889 % F l i p I m a g e %
893 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
895 % FlipImage() creates a vertical mirror image by reflecting the pixels
896 % around the central x-axis.
898 % The format of the FlipImage method is:
900 % Image *FlipImage(const Image *image,ExceptionInfo *exception)
902 % A description of each parameter follows:
904 % o image: the image.
906 % o exception: return any errors or warnings in this structure.
909 MagickExport Image *FlipImage(const Image *image,ExceptionInfo *exception)
911 #define FlipImageTag "Flip/Image"
929 assert(image != (const Image *) NULL);
930 assert(image->signature == MagickSignature);
931 if (image->debug != MagickFalse)
932 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
933 assert(exception != (ExceptionInfo *) NULL);
934 assert(exception->signature == MagickSignature);
935 flip_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
936 if (flip_image == (Image *) NULL)
937 return((Image *) NULL);
943 image_view=AcquireCacheView(image);
944 flip_view=AcquireCacheView(flip_image);
945 #if defined(MAGICKCORE_OPENMP_SUPPORT)
946 #pragma omp parallel for schedule(dynamic,4) shared(progress,status) omp_throttle(1)
948 for (y=0; y < (ssize_t) flip_image->rows; y++)
950 register const IndexPacket
953 register const PixelPacket
957 *restrict flip_indexes;
962 if (status == MagickFalse)
964 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
965 q=QueueCacheViewAuthenticPixels(flip_view,0,(ssize_t) (flip_image->rows-y-
966 1),flip_image->columns,1,exception);
967 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
972 (void) CopyMagickMemory(q,p,(size_t) image->columns*sizeof(*q));
973 indexes=GetCacheViewVirtualIndexQueue(image_view);
974 if (indexes != (const IndexPacket *) NULL)
976 flip_indexes=GetCacheViewAuthenticIndexQueue(flip_view);
977 if (flip_indexes != (IndexPacket *) NULL)
978 (void) CopyMagickMemory(flip_indexes,indexes,(size_t) image->columns*
979 sizeof(*flip_indexes));
981 if (SyncCacheViewAuthenticPixels(flip_view,exception) == MagickFalse)
983 if (image->progress_monitor != (MagickProgressMonitor) NULL)
988 #if defined(MAGICKCORE_OPENMP_SUPPORT)
989 #pragma omp critical (MagickCore_FlipImage)
991 proceed=SetImageProgress(image,FlipImageTag,progress++,image->rows);
992 if (proceed == MagickFalse)
996 flip_view=DestroyCacheView(flip_view);
997 image_view=DestroyCacheView(image_view);
998 flip_image->type=image->type;
999 if (status == MagickFalse)
1000 flip_image=DestroyImage(flip_image);
1005 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1009 % F l o p I m a g e %
1013 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1015 % FlopImage() creates a horizontal mirror image by reflecting the pixels
1016 % around the central y-axis.
1018 % The format of the FlopImage method is:
1020 % Image *FlopImage(const Image *image,ExceptionInfo *exception)
1022 % A description of each parameter follows:
1024 % o image: the image.
1026 % o exception: return any errors or warnings in this structure.
1029 MagickExport Image *FlopImage(const Image *image,ExceptionInfo *exception)
1031 #define FlopImageTag "Flop/Image"
1049 assert(image != (const Image *) NULL);
1050 assert(image->signature == MagickSignature);
1051 if (image->debug != MagickFalse)
1052 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1053 assert(exception != (ExceptionInfo *) NULL);
1054 assert(exception->signature == MagickSignature);
1055 flop_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
1056 if (flop_image == (Image *) NULL)
1057 return((Image *) NULL);
1063 image_view=AcquireCacheView(image);
1064 flop_view=AcquireCacheView(flop_image);
1065 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1066 #pragma omp parallel for schedule(dynamic,4) shared(progress,status) omp_throttle(1)
1068 for (y=0; y < (ssize_t) flop_image->rows; y++)
1070 register const IndexPacket
1073 register const PixelPacket
1076 register IndexPacket
1077 *restrict flop_indexes;
1082 register PixelPacket
1085 if (status == MagickFalse)
1087 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1088 q=QueueCacheViewAuthenticPixels(flop_view,0,y,flop_image->columns,1,
1090 if ((p == (PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
1095 q+=flop_image->columns;
1096 indexes=GetCacheViewVirtualIndexQueue(image_view);
1097 flop_indexes=GetCacheViewAuthenticIndexQueue(flop_view);
1098 for (x=0; x < (ssize_t) flop_image->columns; x++)
1101 if ((indexes != (const IndexPacket *) NULL) &&
1102 (flop_indexes != (IndexPacket *) NULL))
1103 flop_indexes[flop_image->columns-x-1]=indexes[x];
1105 if (SyncCacheViewAuthenticPixels(flop_view,exception) == MagickFalse)
1107 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1112 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1113 #pragma omp critical (MagickCore_FlopImage)
1115 proceed=SetImageProgress(image,FlopImageTag,progress++,image->rows);
1116 if (proceed == MagickFalse)
1120 flop_view=DestroyCacheView(flop_view);
1121 image_view=DestroyCacheView(image_view);
1122 flop_image->type=image->type;
1123 if (status == MagickFalse)
1124 flop_image=DestroyImage(flop_image);
1129 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1133 % R o l l I m a g e %
1137 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1139 % RollImage() offsets an image as defined by x_offset and y_offset.
1141 % The format of the RollImage method is:
1143 % Image *RollImage(const Image *image,const ssize_t x_offset,
1144 % const ssize_t y_offset,ExceptionInfo *exception)
1146 % A description of each parameter follows:
1148 % o image: the image.
1150 % o x_offset: the number of columns to roll in the horizontal direction.
1152 % o y_offset: the number of rows to roll in the vertical direction.
1154 % o exception: return any errors or warnings in this structure.
1158 static inline MagickBooleanType CopyImageRegion(Image *destination,
1159 const Image *source,const size_t columns,const size_t rows,
1160 const ssize_t sx,const ssize_t sy,const ssize_t dx,const ssize_t dy,
1161 ExceptionInfo *exception)
1174 source_view=AcquireCacheView(source);
1175 destination_view=AcquireCacheView(destination);
1176 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1177 #pragma omp parallel for schedule(dynamic,4) shared(status)
1179 for (y=0; y < (ssize_t) rows; y++)
1184 register const IndexPacket
1187 register const PixelPacket
1190 register IndexPacket
1191 *restrict destination_indexes;
1193 register PixelPacket
1199 if (status == MagickFalse)
1201 p=GetCacheViewVirtualPixels(source_view,sx,sy+y,columns,1,exception);
1202 q=GetCacheViewAuthenticPixels(destination_view,dx,dy+y,columns,1,exception);
1203 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
1208 indexes=GetCacheViewVirtualIndexQueue(source_view);
1209 (void) CopyMagickMemory(q,p,(size_t) columns*sizeof(*p));
1210 if (indexes != (IndexPacket *) NULL)
1212 destination_indexes=GetCacheViewAuthenticIndexQueue(destination_view);
1213 if (destination_indexes != (IndexPacket *) NULL)
1214 (void) CopyMagickMemory(destination_indexes,indexes,(size_t)
1215 columns*sizeof(*indexes));
1217 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
1218 if (sync == MagickFalse)
1221 destination_view=DestroyCacheView(destination_view);
1222 source_view=DestroyCacheView(source_view);
1226 MagickExport Image *RollImage(const Image *image,const ssize_t x_offset,
1227 const ssize_t y_offset,ExceptionInfo *exception)
1229 #define RollImageTag "Roll/Image"
1241 Initialize roll image attributes.
1243 assert(image != (const Image *) NULL);
1244 assert(image->signature == MagickSignature);
1245 if (image->debug != MagickFalse)
1246 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1247 assert(exception != (ExceptionInfo *) NULL);
1248 assert(exception->signature == MagickSignature);
1249 roll_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
1250 if (roll_image == (Image *) NULL)
1251 return((Image *) NULL);
1254 while (offset.x < 0)
1255 offset.x+=(ssize_t) image->columns;
1256 while (offset.x >= (ssize_t) image->columns)
1257 offset.x-=(ssize_t) image->columns;
1258 while (offset.y < 0)
1259 offset.y+=(ssize_t) image->rows;
1260 while (offset.y >= (ssize_t) image->rows)
1261 offset.y-=(ssize_t) image->rows;
1265 status=CopyImageRegion(roll_image,image,(size_t) offset.x,
1266 (size_t) offset.y,(ssize_t) image->columns-offset.x,(ssize_t) image->rows-
1267 offset.y,0,0,exception);
1268 (void) SetImageProgress(image,RollImageTag,0,3);
1269 status|=CopyImageRegion(roll_image,image,image->columns-offset.x,
1270 (size_t) offset.y,0,(ssize_t) image->rows-offset.y,offset.x,0,
1272 (void) SetImageProgress(image,RollImageTag,1,3);
1273 status|=CopyImageRegion(roll_image,image,(size_t) offset.x,image->rows-
1274 offset.y,(ssize_t) image->columns-offset.x,0,0,offset.y,exception);
1275 (void) SetImageProgress(image,RollImageTag,2,3);
1276 status|=CopyImageRegion(roll_image,image,image->columns-offset.x,image->rows-
1277 offset.y,0,0,offset.x,offset.y,exception);
1278 (void) SetImageProgress(image,RollImageTag,3,3);
1279 roll_image->type=image->type;
1280 if (status == MagickFalse)
1281 roll_image=DestroyImage(roll_image);
1286 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1290 % S h a v e I m a g e %
1294 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1296 % ShaveImage() shaves pixels from the image edges. It allocates the memory
1297 % necessary for the new Image structure and returns a pointer to the new
1300 % The format of the ShaveImage method is:
1302 % Image *ShaveImage(const Image *image,const RectangleInfo *shave_info,
1303 % ExceptionInfo *exception)
1305 % A description of each parameter follows:
1307 % o shave_image: Method ShaveImage returns a pointer to the shaved
1308 % image. A null image is returned if there is a memory shortage or
1309 % if the image width or height is zero.
1311 % o image: the image.
1313 % o shave_info: Specifies a pointer to a RectangleInfo which defines the
1314 % region of the image to crop.
1316 % o exception: return any errors or warnings in this structure.
1319 MagickExport Image *ShaveImage(const Image *image,
1320 const RectangleInfo *shave_info,ExceptionInfo *exception)
1328 assert(image != (const Image *) NULL);
1329 assert(image->signature == MagickSignature);
1330 if (image->debug != MagickFalse)
1331 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1332 if (((2*shave_info->width) >= image->columns) ||
1333 ((2*shave_info->height) >= image->rows))
1334 ThrowImageException(OptionWarning,"GeometryDoesNotContainImage");
1335 SetGeometry(image,&geometry);
1336 geometry.width-=2*shave_info->width;
1337 geometry.height-=2*shave_info->height;
1338 geometry.x=(ssize_t) shave_info->width+image->page.x;
1339 geometry.y=(ssize_t) shave_info->height+image->page.y;
1340 shave_image=CropImage(image,&geometry,exception);
1341 if (shave_image == (Image *) NULL)
1342 return((Image *) NULL);
1343 shave_image->page.width-=2*shave_info->width;
1344 shave_image->page.height-=2*shave_info->height;
1345 shave_image->page.x-=(ssize_t) shave_info->width;
1346 shave_image->page.y-=(ssize_t) shave_info->height;
1347 return(shave_image);
1351 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1355 % S p l i c e I m a g e %
1359 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1361 % SpliceImage() splices a solid color into the image as defined by the
1364 % The format of the SpliceImage method is:
1366 % Image *SpliceImage(const Image *image,const RectangleInfo *geometry,
1367 % ExceptionInfo *exception)
1369 % A description of each parameter follows:
1371 % o image: the image.
1373 % o geometry: Define the region of the image to splice with members
1374 % x, y, width, and height.
1376 % o exception: return any errors or warnings in this structure.
1379 MagickExport Image *SpliceImage(const Image *image,
1380 const RectangleInfo *geometry,ExceptionInfo *exception)
1382 #define SpliceImageTag "Splice/Image"
1408 Allocate splice image.
1410 assert(image != (const Image *) NULL);
1411 assert(image->signature == MagickSignature);
1412 if (image->debug != MagickFalse)
1413 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1414 assert(geometry != (const RectangleInfo *) NULL);
1415 assert(exception != (ExceptionInfo *) NULL);
1416 assert(exception->signature == MagickSignature);
1417 splice_geometry=(*geometry);
1418 splice_image=CloneImage(image,image->columns+splice_geometry.width,
1419 image->rows+splice_geometry.height,MagickTrue,exception);
1420 if (splice_image == (Image *) NULL)
1421 return((Image *) NULL);
1422 if (SetImageStorageClass(splice_image,DirectClass) == MagickFalse)
1424 InheritException(exception,&splice_image->exception);
1425 splice_image=DestroyImage(splice_image);
1426 return((Image *) NULL);
1428 (void) SetImageBackgroundColor(splice_image);
1430 Respect image geometry.
1432 switch (image->gravity)
1435 case UndefinedGravity:
1436 case NorthWestGravity:
1440 splice_geometry.x+=(ssize_t) splice_geometry.width/2;
1443 case NorthEastGravity:
1445 splice_geometry.x+=(ssize_t) splice_geometry.width;
1450 splice_geometry.y+=(ssize_t) splice_geometry.width/2;
1456 splice_geometry.x+=(ssize_t) splice_geometry.width/2;
1457 splice_geometry.y+=(ssize_t) splice_geometry.height/2;
1462 splice_geometry.x+=(ssize_t) splice_geometry.width;
1463 splice_geometry.y+=(ssize_t) splice_geometry.height/2;
1466 case SouthWestGravity:
1468 splice_geometry.y+=(ssize_t) splice_geometry.height;
1473 splice_geometry.x+=(ssize_t) splice_geometry.width/2;
1474 splice_geometry.y+=(ssize_t) splice_geometry.height;
1477 case SouthEastGravity:
1479 splice_geometry.x+=(ssize_t) splice_geometry.width;
1480 splice_geometry.y+=(ssize_t) splice_geometry.height;
1490 image_view=AcquireCacheView(image);
1491 splice_view=AcquireCacheView(splice_image);
1492 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1493 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
1495 for (y=0; y < (ssize_t) splice_geometry.y; y++)
1497 register const PixelPacket
1500 register IndexPacket
1502 *restrict splice_indexes;
1507 register PixelPacket
1510 if (status == MagickFalse)
1512 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1513 q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1,
1515 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
1520 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1521 splice_indexes=GetCacheViewAuthenticIndexQueue(splice_view);
1522 for (x=0; x < splice_geometry.x; x++)
1524 SetRedPixelComponent(q,GetRedPixelComponent(p));
1525 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
1526 SetBluePixelComponent(q,GetBluePixelComponent(p));
1527 SetOpacityPixelComponent(q,OpaqueOpacity);
1528 if (image->matte != MagickFalse)
1529 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
1530 if (image->colorspace == CMYKColorspace)
1531 splice_indexes[x]=(*indexes++);
1535 for ( ; x < (ssize_t) (splice_geometry.x+splice_geometry.width); x++)
1537 for ( ; x < (ssize_t) splice_image->columns; x++)
1539 SetRedPixelComponent(q,GetRedPixelComponent(p));
1540 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
1541 SetBluePixelComponent(q,GetBluePixelComponent(p));
1542 SetOpacityPixelComponent(q,OpaqueOpacity);
1543 if (image->matte != MagickFalse)
1544 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
1545 if (image->colorspace == CMYKColorspace)
1546 splice_indexes[x]=(*indexes++);
1550 if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse)
1552 proceed=SetImageProgress(image,SpliceImageTag,(MagickOffsetType) y,
1553 splice_image->rows);
1554 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1559 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1560 #pragma omp critical (MagickCore_TransposeImage)
1562 proceed=SetImageProgress(image,SpliceImageTag,progress++,
1563 splice_image->rows);
1564 if (proceed == MagickFalse)
1568 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1569 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
1571 for (y=(ssize_t) (splice_geometry.y+splice_geometry.height);
1572 y < (ssize_t) splice_image->rows; y++)
1574 register const PixelPacket
1577 register IndexPacket
1579 *restrict splice_indexes;
1584 register PixelPacket
1587 if (status == MagickFalse)
1589 p=GetCacheViewVirtualPixels(image_view,0,y-(ssize_t) splice_geometry.height,
1590 image->columns,1,exception);
1591 q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1,
1593 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
1598 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1599 splice_indexes=GetCacheViewAuthenticIndexQueue(splice_view);
1600 for (x=0; x < splice_geometry.x; x++)
1602 SetRedPixelComponent(q,GetRedPixelComponent(p));
1603 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
1604 SetBluePixelComponent(q,GetBluePixelComponent(p));
1605 SetOpacityPixelComponent(q,OpaqueOpacity);
1606 if (image->matte != MagickFalse)
1607 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
1608 if (image->colorspace == CMYKColorspace)
1609 splice_indexes[x]=(*indexes++);
1613 for ( ; x < (ssize_t) (splice_geometry.x+splice_geometry.width); x++)
1615 for ( ; x < (ssize_t) splice_image->columns; x++)
1617 SetRedPixelComponent(q,GetRedPixelComponent(p));
1618 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
1619 SetBluePixelComponent(q,GetBluePixelComponent(p));
1620 SetOpacityPixelComponent(q,OpaqueOpacity);
1621 if (image->matte != MagickFalse)
1622 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
1623 if (image->colorspace == CMYKColorspace)
1624 splice_indexes[x]=(*indexes++);
1628 if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse)
1630 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1635 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1636 #pragma omp critical (MagickCore_TransposeImage)
1638 proceed=SetImageProgress(image,SpliceImageTag,progress++,
1639 splice_image->rows);
1640 if (proceed == MagickFalse)
1644 splice_view=DestroyCacheView(splice_view);
1645 image_view=DestroyCacheView(image_view);
1646 if (status == MagickFalse)
1647 splice_image=DestroyImage(splice_image);
1648 return(splice_image);
1652 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1656 % T r a n s f o r m I m a g e %
1660 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1662 % TransformImage() is a convenience method that behaves like ResizeImage() or
1663 % CropImage() but accepts scaling and/or cropping information as a region
1664 % geometry specification. If the operation fails, the original image handle
1667 % The format of the TransformImage method is:
1669 % MagickBooleanType TransformImage(Image **image,const char *crop_geometry,
1670 % const char *image_geometry)
1672 % A description of each parameter follows:
1674 % o image: the image The transformed image is returned as this parameter.
1676 % o crop_geometry: A crop geometry string. This geometry defines a
1677 % subregion of the image to crop.
1679 % o image_geometry: An image geometry string. This geometry defines the
1680 % final size of the image.
1683 static inline ssize_t MagickRound(MagickRealType x)
1686 Round the fraction to nearest integer.
1689 return((ssize_t) (x+0.5));
1690 return((ssize_t) (x-0.5));
1693 MagickExport MagickBooleanType TransformImage(Image **image,
1694 const char *crop_geometry,const char *image_geometry)
1715 assert(image != (Image **) NULL);
1716 assert((*image)->signature == MagickSignature);
1717 if ((*image)->debug != MagickFalse)
1718 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
1719 transform_image=(*image);
1720 if (crop_geometry != (const char *) NULL)
1729 Crop image to a user specified size.
1731 crop_image=NewImageList();
1732 flags=ParseGravityGeometry(transform_image,crop_geometry,&geometry,
1733 &(*image)->exception);
1734 if ((flags & AreaValue) != 0)
1744 Crop into NxM tiles (@ flag) - AT.
1746 if (geometry.width == 0)
1748 if (geometry.height == 0)
1750 width=transform_image->columns;
1751 height=transform_image->rows;
1752 if ((flags & AspectValue) == 0)
1754 width-=(geometry.x < 0 ? -1 : 1)*geometry.x;
1755 height-=(geometry.y < 0 ? -1 : 1)*geometry.y;
1759 width+=(geometry.x < 0 ? -1 : 1)*geometry.x;
1760 height+=(geometry.y < 0 ? -1 : 1)*geometry.y;
1762 delta.x=(double) width/geometry.width;
1763 delta.y=(double) height/geometry.height;
1764 next=NewImageList();
1765 for (offset.y=0; offset.y < (double) height; )
1767 if ((flags & AspectValue) == 0)
1769 crop.y=(ssize_t) MagickRound((MagickRealType) (offset.y-
1770 (geometry.y > 0 ? 0 : geometry.y)));
1772 crop.height=(size_t) MagickRound((MagickRealType)
1773 (offset.y+(geometry.y < 0 ? 0 : geometry.y)));
1777 crop.y=(ssize_t) MagickRound((MagickRealType) (offset.y-
1778 (geometry.y > 0 ? geometry.y : 0)));
1780 crop.height=(size_t) MagickRound((MagickRealType)
1781 (offset.y+(geometry.y < 0 ? geometry.y : 0)));
1783 crop.height-=crop.y;
1784 crop.y+=transform_image->page.y;
1785 for (offset.x=0; offset.x < (double) width; )
1787 if ((flags & AspectValue) == 0)
1789 crop.x=(ssize_t) MagickRound((MagickRealType) (offset.x-
1790 (geometry.x > 0 ? 0 : geometry.x)));
1792 crop.width=(size_t) MagickRound((MagickRealType)
1793 (offset.x+(geometry.x < 0 ? 0 : geometry.x)));
1797 crop.x=(ssize_t) MagickRound((MagickRealType) (offset.x-
1798 (geometry.x > 0 ? geometry.x : 0)));
1800 crop.width=(size_t) MagickRound((MagickRealType)
1801 (offset.x+(geometry.x < 0 ? geometry.x : 0)));
1804 crop.x+=transform_image->page.x;
1805 next=CropImage(transform_image,&crop,&(*image)->exception);
1806 if (next == (Image *) NULL)
1808 AppendImageToList(&crop_image,next);
1810 if (next == (Image *) NULL)
1815 if (((geometry.width == 0) && (geometry.height == 0)) ||
1816 ((flags & XValue) != 0) || ((flags & YValue) != 0))
1819 Crop a single region at +X+Y.
1821 crop_image=CropImage(transform_image,&geometry,
1822 &(*image)->exception);
1823 if ((crop_image != (Image *) NULL) && ((flags & AspectValue) != 0))
1825 crop_image->page.width=geometry.width;
1826 crop_image->page.height=geometry.height;
1827 crop_image->page.x-=geometry.x;
1828 crop_image->page.y-=geometry.y;
1832 if ((transform_image->columns > geometry.width) ||
1833 (transform_image->rows > geometry.height))
1838 MagickProgressMonitor
1848 Crop into tiles of fixed size WxH.
1850 if (transform_image->page.width == 0)
1851 transform_image->page.width=transform_image->columns;
1852 if (transform_image->page.height == 0)
1853 transform_image->page.height=transform_image->rows;
1854 width=geometry.width;
1856 width=transform_image->page.width;
1857 height=geometry.height;
1859 height=transform_image->page.height;
1860 next=NewImageList();
1864 for (y=0; y < (ssize_t) transform_image->page.height; y+=(ssize_t) height)
1865 for (x=0; x < (ssize_t) transform_image->page.width; x+=(ssize_t) width)
1867 for (y=0; y < (ssize_t) transform_image->page.height; y+=(ssize_t) height)
1869 for (x=0; x < (ssize_t) transform_image->page.width; x+=(ssize_t) width)
1871 progress_monitor=SetImageProgressMonitor(transform_image,
1872 (MagickProgressMonitor) NULL,transform_image->client_data);
1873 geometry.width=width;
1874 geometry.height=height;
1877 next=CropImage(transform_image,&geometry,&(*image)->exception);
1878 (void) SetImageProgressMonitor(transform_image,
1879 progress_monitor,transform_image->client_data);
1880 proceed=SetImageProgress(transform_image,CropImageTag,i++,
1882 if (proceed == MagickFalse)
1884 if (next == (Image *) NULL)
1886 (void) SetImageProgressMonitor(next,progress_monitor,
1888 if (crop_image == (Image *) NULL)
1892 next->previous=crop_image;
1893 crop_image->next=next;
1894 crop_image=crop_image->next;
1897 if (next == (Image *) NULL)
1899 if (proceed == MagickFalse)
1903 if (crop_image == (Image *) NULL)
1904 transform_image=CloneImage(*image,0,0,MagickTrue,&(*image)->exception);
1907 transform_image=DestroyImage(transform_image);
1908 transform_image=GetFirstImageInList(crop_image);
1910 *image=transform_image;
1912 if (image_geometry == (const char *) NULL)
1915 Scale image to a user specified size.
1917 flags=ParseRegionGeometry(transform_image,image_geometry,&geometry,
1918 &(*image)->exception);
1919 if ((transform_image->columns == geometry.width) &&
1920 (transform_image->rows == geometry.height))
1922 resize_image=ResizeImage(transform_image,geometry.width,geometry.height,
1923 transform_image->filter,transform_image->blur,&(*image)->exception);
1924 if (resize_image == (Image *) NULL)
1925 return(MagickFalse);
1926 transform_image=DestroyImage(transform_image);
1927 transform_image=resize_image;
1928 *image=transform_image;
1933 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1937 % T r a n s f o r m I m a g e s %
1940 % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1942 % TransformImages() calls TransformImage() on each image of a sequence.
1944 % The format of the TransformImage method is:
1946 % MagickBooleanType TransformImages(Image **image,
1947 % const char *crop_geometry,const char *image_geometry)
1949 % A description of each parameter follows:
1951 % o image: the image The transformed image is returned as this parameter.
1953 % o crop_geometry: A crop geometry string. This geometry defines a
1954 % subregion of the image to crop.
1956 % o image_geometry: An image geometry string. This geometry defines the
1957 % final size of the image.
1960 MagickExport MagickBooleanType TransformImages(Image **images,
1961 const char *crop_geometry,const char *image_geometry)
1974 assert(images != (Image **) NULL);
1975 assert((*images)->signature == MagickSignature);
1976 if ((*images)->debug != MagickFalse)
1977 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1978 (*images)->filename);
1979 image_list=ImageListToArray(*images,&(*images)->exception);
1980 if (image_list == (Image **) NULL)
1981 return(MagickFalse);
1983 transform_images=NewImageList();
1984 for (i=0; image_list[i] != (Image *) NULL; i++)
1986 image=image_list[i];
1987 status|=TransformImage(&image,crop_geometry,image_geometry);
1988 AppendImageToList(&transform_images,image);
1990 *images=transform_images;
1991 image_list=(Image **) RelinquishMagickMemory(image_list);
1992 return(status != 0 ? MagickTrue : MagickFalse);
1996 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2000 % T r a n s p o s e I m a g e %
2004 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2006 % TransposeImage() creates a horizontal mirror image by reflecting the pixels
2007 % around the central y-axis while rotating them by 90 degrees.
2009 % The format of the TransposeImage method is:
2011 % Image *TransposeImage(const Image *image,ExceptionInfo *exception)
2013 % A description of each parameter follows:
2015 % o image: the image.
2017 % o exception: return any errors or warnings in this structure.
2020 MagickExport Image *TransposeImage(const Image *image,ExceptionInfo *exception)
2022 #define TransposeImageTag "Transpose/Image"
2043 assert(image != (const Image *) NULL);
2044 assert(image->signature == MagickSignature);
2045 if (image->debug != MagickFalse)
2046 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2047 assert(exception != (ExceptionInfo *) NULL);
2048 assert(exception->signature == MagickSignature);
2049 transpose_image=CloneImage(image,image->rows,image->columns,MagickTrue,
2051 if (transpose_image == (Image *) NULL)
2052 return((Image *) NULL);
2058 image_view=AcquireCacheView(image);
2059 transpose_view=AcquireCacheView(transpose_image);
2060 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2061 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
2063 for (y=0; y < (ssize_t) image->rows; y++)
2065 register const PixelPacket
2068 register IndexPacket
2069 *restrict transpose_indexes,
2072 register PixelPacket
2075 if (status == MagickFalse)
2077 p=GetCacheViewVirtualPixels(image_view,0,(ssize_t) image->rows-y-1,
2078 image->columns,1,exception);
2079 q=QueueCacheViewAuthenticPixels(transpose_view,(ssize_t) (image->rows-y-1),
2080 0,1,transpose_image->rows,exception);
2081 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
2086 (void) CopyMagickMemory(q,p,(size_t) image->columns*sizeof(*q));
2087 indexes=GetCacheViewAuthenticIndexQueue(image_view);
2088 if (indexes != (IndexPacket *) NULL)
2090 transpose_indexes=GetCacheViewAuthenticIndexQueue(transpose_view);
2091 if (transpose_indexes != (IndexPacket *) NULL)
2092 (void) CopyMagickMemory(transpose_indexes,indexes,(size_t)
2093 image->columns*sizeof(*transpose_indexes));
2095 if (SyncCacheViewAuthenticPixels(transpose_view,exception) == MagickFalse)
2097 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2102 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2103 #pragma omp critical (MagickCore_TransposeImage)
2105 proceed=SetImageProgress(image,TransposeImageTag,progress++,
2107 if (proceed == MagickFalse)
2111 transpose_view=DestroyCacheView(transpose_view);
2112 image_view=DestroyCacheView(image_view);
2113 transpose_image->type=image->type;
2114 page=transpose_image->page;
2115 Swap(page.width,page.height);
2116 Swap(page.x,page.y);
2117 if (page.width != 0)
2118 page.x=(ssize_t) (page.width-transpose_image->columns-page.x);
2119 transpose_image->page=page;
2120 if (status == MagickFalse)
2121 transpose_image=DestroyImage(transpose_image);
2122 return(transpose_image);
2126 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2130 % T r a n s v e r s e I m a g e %
2134 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2136 % TransverseImage() creates a vertical mirror image by reflecting the pixels
2137 % around the central x-axis while rotating them by 270 degrees.
2139 % The format of the TransverseImage method is:
2141 % Image *TransverseImage(const Image *image,ExceptionInfo *exception)
2143 % A description of each parameter follows:
2145 % o image: the image.
2147 % o exception: return any errors or warnings in this structure.
2150 MagickExport Image *TransverseImage(const Image *image,ExceptionInfo *exception)
2152 #define TransverseImageTag "Transverse/Image"
2173 assert(image != (const Image *) NULL);
2174 assert(image->signature == MagickSignature);
2175 if (image->debug != MagickFalse)
2176 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2177 assert(exception != (ExceptionInfo *) NULL);
2178 assert(exception->signature == MagickSignature);
2179 transverse_image=CloneImage(image,image->rows,image->columns,MagickTrue,
2181 if (transverse_image == (Image *) NULL)
2182 return((Image *) NULL);
2188 image_view=AcquireCacheView(image);
2189 transverse_view=AcquireCacheView(transverse_image);
2190 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2191 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
2193 for (y=0; y < (ssize_t) image->rows; y++)
2198 register const PixelPacket
2201 register IndexPacket
2202 *restrict transverse_indexes,
2208 register PixelPacket
2211 if (status == MagickFalse)
2213 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2214 q=QueueCacheViewAuthenticPixels(transverse_view,(ssize_t) (image->rows-y-
2215 1),0,1,transverse_image->rows,exception);
2216 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
2222 for (x=0; x < (ssize_t) image->columns; x++)
2224 indexes=GetCacheViewAuthenticIndexQueue(image_view);
2225 if (indexes != (IndexPacket *) NULL)
2227 transverse_indexes=GetCacheViewAuthenticIndexQueue(transverse_view);
2228 if (transverse_indexes != (IndexPacket *) NULL)
2229 for (x=0; x < (ssize_t) image->columns; x++)
2230 transverse_indexes[image->columns-x-1]=indexes[x];
2232 sync=SyncCacheViewAuthenticPixels(transverse_view,exception);
2233 if (sync == MagickFalse)
2235 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2240 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2241 #pragma omp critical (MagickCore_TransverseImage)
2243 proceed=SetImageProgress(image,TransverseImageTag,progress++,
2245 if (proceed == MagickFalse)
2249 transverse_view=DestroyCacheView(transverse_view);
2250 image_view=DestroyCacheView(image_view);
2251 transverse_image->type=image->type;
2252 page=transverse_image->page;
2253 Swap(page.width,page.height);
2254 Swap(page.x,page.y);
2255 if (page.height != 0)
2256 page.y=(ssize_t) (page.height-transverse_image->rows-page.y);
2257 transverse_image->page=page;
2258 if (status == MagickFalse)
2259 transverse_image=DestroyImage(transverse_image);
2260 return(transverse_image);
2264 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2268 % T r i m I m a g e %
2272 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2274 % TrimImage() trims pixels from the image edges. It allocates the memory
2275 % necessary for the new Image structure and returns a pointer to the new
2278 % The format of the TrimImage method is:
2280 % Image *TrimImage(const Image *image,ExceptionInfo *exception)
2282 % A description of each parameter follows:
2284 % o image: the image.
2286 % o exception: return any errors or warnings in this structure.
2289 MagickExport Image *TrimImage(const Image *image,ExceptionInfo *exception)
2294 assert(image != (const Image *) NULL);
2295 assert(image->signature == MagickSignature);
2296 if (image->debug != MagickFalse)
2297 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2298 geometry=GetImageBoundingBox(image,exception);
2299 if ((geometry.width == 0) || (geometry.height == 0))
2304 crop_image=CloneImage(image,1,1,MagickTrue,exception);
2305 if (crop_image == (Image *) NULL)
2306 return((Image *) NULL);
2307 crop_image->background_color.opacity=(Quantum) TransparentOpacity;
2308 (void) SetImageBackgroundColor(crop_image);
2309 crop_image->page=image->page;
2310 crop_image->page.x=(-1);
2311 crop_image->page.y=(-1);
2314 geometry.x+=image->page.x;
2315 geometry.y+=image->page.y;
2316 return(CropImage(image,&geometry,exception));