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/effect.h"
51 #include "magick/exception.h"
52 #include "magick/exception-private.h"
53 #include "magick/geometry.h"
54 #include "magick/image.h"
55 #include "magick/memory_.h"
56 #include "magick/layer.h"
57 #include "magick/list.h"
58 #include "magick/monitor.h"
59 #include "magick/monitor-private.h"
60 #include "magick/pixel-private.h"
61 #include "magick/resource_.h"
62 #include "magick/resize.h"
63 #include "magick/statistic.h"
64 #include "magick/string_.h"
65 #include "magick/transform.h"
68 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
76 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
78 % Chop() removes a region of an image and collapses the image to occupy the
81 % The format of the ChopImage method is:
83 % Image *ChopImage(const Image *image,const RectangleInfo *chop_info)
84 % ExceptionInfo *exception)
86 % A description of each parameter follows:
90 % o chop_info: Define the region of the image to chop.
92 % o exception: return any errors or warnings in this structure.
95 MagickExport Image *ChopImage(const Image *image,const RectangleInfo *chop_info,
96 ExceptionInfo *exception)
98 #define ChopImageTag "Chop/Image"
123 assert(image != (const Image *) NULL);
124 assert(image->signature == MagickSignature);
125 if (image->debug != MagickFalse)
126 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
127 assert(exception != (ExceptionInfo *) NULL);
128 assert(exception->signature == MagickSignature);
129 assert(chop_info != (RectangleInfo *) NULL);
130 if (((chop_info->x+(long) chop_info->width) < 0) ||
131 ((chop_info->y+(long) chop_info->height) < 0) ||
132 (chop_info->x > (long) image->columns) ||
133 (chop_info->y > (long) image->rows))
134 ThrowImageException(OptionWarning,"GeometryDoesNotContainImage");
136 if ((extent.x+(long) extent.width) > (long) image->columns)
137 extent.width=(unsigned long) ((long) image->columns-extent.x);
138 if ((extent.y+(long) extent.height) > (long) image->rows)
139 extent.height=(unsigned long) ((long) image->rows-extent.y);
142 extent.width-=(unsigned long) (-extent.x);
147 extent.height-=(unsigned long) (-extent.y);
150 chop_image=CloneImage(image,image->columns-extent.width,image->rows-
151 extent.height,MagickTrue,exception);
152 if (chop_image == (Image *) NULL)
153 return((Image *) NULL);
159 image_view=AcquireCacheView(image);
160 chop_view=AcquireCacheView(chop_image);
161 for (y=0; y < (long) extent.y; y++)
163 register const PixelPacket
167 *restrict chop_indexes,
176 p=GetCacheViewVirtualPixels(image_view,0,i++,image->columns,1,exception);
177 q=QueueCacheViewAuthenticPixels(chop_view,0,j++,chop_image->columns,1,
179 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
181 indexes=GetCacheViewAuthenticIndexQueue(image_view);
182 chop_indexes=GetCacheViewAuthenticIndexQueue(chop_view);
183 for (x=0; x < (long) image->columns; x++)
185 if ((x < extent.x) || (x >= (long) (extent.x+extent.width)))
188 if (indexes != (IndexPacket *) NULL)
190 if (chop_indexes != (IndexPacket *) NULL)
191 *chop_indexes++=indexes[x];
197 if (SyncCacheViewAuthenticPixels(chop_view,exception) == MagickFalse)
199 proceed=SetImageProgress(image,ChopImageTag,y,chop_image->rows);
200 if (proceed == MagickFalse)
207 for (y=0; y < (long) (image->rows-(extent.y+extent.height)); y++)
209 register const PixelPacket
213 *restrict chop_indexes,
222 p=GetCacheViewVirtualPixels(image_view,0,i++,image->columns,1,exception);
223 q=QueueCacheViewAuthenticPixels(chop_view,0,j++,chop_image->columns,1,
225 if ((p == (PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
227 indexes=GetCacheViewAuthenticIndexQueue(image_view);
228 chop_indexes=GetCacheViewAuthenticIndexQueue(chop_view);
229 for (x=0; x < (long) image->columns; x++)
231 if ((x < extent.x) || (x >= (long) (extent.x+extent.width)))
234 if (indexes != (IndexPacket *) NULL)
236 if (chop_indexes != (IndexPacket *) NULL)
237 *chop_indexes++=indexes[x];
243 if (SyncCacheViewAuthenticPixels(chop_view,exception) == MagickFalse)
245 proceed=SetImageProgress(image,ChopImageTag,y,chop_image->rows);
246 if (proceed == MagickFalse)
249 chop_view=DestroyCacheView(chop_view);
250 image_view=DestroyCacheView(image_view);
251 chop_image->type=image->type;
256 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
260 + C o n s o l i d a t e C M Y K I m a g e %
264 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
266 % ConsolidateCMYKImage() consolidates separate C, M, Y, and K planes into a
269 % The format of the ConsolidateCMYKImage method is:
271 % Image *ConsolidateCMYKImage(const Image *image,ExceptionInfo *exception)
273 % A description of each parameter follows:
275 % o image: the image sequence.
277 % o exception: return any errors or warnings in this structure.
280 MagickExport Image *ConsolidateCMYKImages(const Image *images,
281 ExceptionInfo *exception)
294 Consolidate separate C, M, Y, and K planes into a single image.
296 assert(images != (Image *) NULL);
297 assert(images->signature == MagickSignature);
298 if (images->debug != MagickFalse)
299 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
300 assert(exception != (ExceptionInfo *) NULL);
301 assert(exception->signature == MagickSignature);
302 cmyk_images=NewImageList();
303 for (i=0; i < (long) GetImageListLength(images); i+=4)
305 cmyk_image=CloneImage(images,images->columns,images->rows,MagickTrue,
307 if (cmyk_image == (Image *) NULL)
309 if (SetImageStorageClass(cmyk_image,DirectClass) == MagickFalse)
311 (void) SetImageColorspace(cmyk_image,CMYKColorspace);
312 for (y=0; y < (long) images->rows; y++)
314 register const PixelPacket
323 p=GetVirtualPixels(images,0,y,images->columns,1,exception);
324 q=QueueAuthenticPixels(cmyk_image,0,y,cmyk_image->columns,1,exception);
325 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
327 for (x=0; x < (long) images->columns; x++)
329 q->red=(Quantum) (QuantumRange-PixelIntensityToQuantum(p));
333 if (SyncAuthenticPixels(cmyk_image,exception) == MagickFalse)
336 images=GetNextImageInList(images);
337 if (images == (Image *) NULL)
339 for (y=0; y < (long) images->rows; y++)
341 register const PixelPacket
350 p=GetVirtualPixels(images,0,y,images->columns,1,exception);
351 q=GetAuthenticPixels(cmyk_image,0,y,cmyk_image->columns,1,exception);
352 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
354 for (x=0; x < (long) images->columns; x++)
356 q->green=(Quantum) (QuantumRange-PixelIntensityToQuantum(p));
360 if (SyncAuthenticPixels(cmyk_image,exception) == MagickFalse)
363 images=GetNextImageInList(images);
364 if (images == (Image *) NULL)
366 for (y=0; y < (long) images->rows; y++)
368 register const PixelPacket
377 p=GetVirtualPixels(images,0,y,images->columns,1,exception);
378 q=GetAuthenticPixels(cmyk_image,0,y,cmyk_image->columns,1,exception);
379 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
381 for (x=0; x < (long) images->columns; x++)
383 q->blue=(Quantum) (QuantumRange-PixelIntensityToQuantum(p));
387 if (SyncAuthenticPixels(cmyk_image,exception) == MagickFalse)
390 images=GetNextImageInList(images);
391 if (images == (Image *) NULL)
393 for (y=0; y < (long) images->rows; y++)
395 register const PixelPacket
407 p=GetVirtualPixels(images,0,y,images->columns,1,exception);
408 q=GetAuthenticPixels(cmyk_image,0,y,cmyk_image->columns,1,exception);
409 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
411 indexes=GetAuthenticIndexQueue(cmyk_image);
412 for (x=0; x < (long) images->columns; x++)
414 indexes[x]=(IndexPacket) (QuantumRange-PixelIntensityToQuantum(p));
417 if (SyncAuthenticPixels(cmyk_image,exception) == MagickFalse)
420 AppendImageToList(&cmyk_images,cmyk_image);
421 images=GetNextImageInList(images);
422 if (images == (Image *) NULL)
429 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
433 % C r o p I m a g e %
437 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
439 % CropImage() extracts a region of the image starting at the offset defined
442 % The format of the CropImage method is:
444 % Image *CropImage(const Image *image,const RectangleInfo *geometry,
445 % ExceptionInfo *exception)
447 % A description of each parameter follows:
449 % o image: the image.
451 % o geometry: Define the region of the image to crop with members
452 % x, y, width, and height.
454 % o exception: return any errors or warnings in this structure.
457 MagickExport Image *CropImage(const Image *image,const RectangleInfo *geometry,
458 ExceptionInfo *exception)
460 #define CropImageTag "Crop/Image"
483 assert(image != (const Image *) NULL);
484 assert(image->signature == MagickSignature);
485 if (image->debug != MagickFalse)
486 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
487 assert(geometry != (const RectangleInfo *) NULL);
488 assert(exception != (ExceptionInfo *) NULL);
489 assert(exception->signature == MagickSignature);
490 bounding_box=image->page;
491 if ((bounding_box.width == 0) || (bounding_box.height == 0))
493 bounding_box.width=image->columns;
494 bounding_box.height=image->rows;
498 page.width=bounding_box.width;
499 if (page.height == 0)
500 page.height=bounding_box.height;
501 if (((bounding_box.x-page.x) >= (long) page.width) ||
502 ((bounding_box.y-page.y) >= (long) page.height) ||
503 ((page.x-bounding_box.x) > (long) image->columns) ||
504 ((page.y-bounding_box.y) > (long) image->rows))
507 Crop is not within virtual canvas, return 1 pixel transparent image.
509 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
510 "GeometryDoesNotContainImage","`%s'",image->filename);
511 crop_image=CloneImage(image,1,1,MagickTrue,exception);
512 if (crop_image == (Image *) NULL)
513 return((Image *) NULL);
514 crop_image->background_color.opacity=(Quantum) TransparentOpacity;
515 (void) SetImageBackgroundColor(crop_image);
516 crop_image->page=bounding_box;
517 crop_image->page.x=(-1);
518 crop_image->page.y=(-1);
519 if (crop_image->dispose == BackgroundDispose)
520 crop_image->dispose=NoneDispose;
523 if ((page.x < 0) && (bounding_box.x >= 0))
525 page.width+=page.x-bounding_box.x;
530 page.width-=bounding_box.x-page.x;
531 page.x-=bounding_box.x;
535 if ((page.y < 0) && (bounding_box.y >= 0))
537 page.height+=page.y-bounding_box.y;
542 page.height-=bounding_box.y-page.y;
543 page.y-=bounding_box.y;
547 if ((unsigned long) (page.x+page.width) > image->columns)
548 page.width=image->columns-page.x;
549 if (geometry->width != 0)
550 if (page.width > geometry->width)
551 page.width=geometry->width;
552 if ((unsigned long) (page.y+page.height) > image->rows)
553 page.height=image->rows-page.y;
554 if (geometry->height != 0)
555 if (page.height > geometry->height)
556 page.height=geometry->height;
557 bounding_box.x+=page.x;
558 bounding_box.y+=page.y;
559 if ((page.width == 0) || (page.height == 0))
561 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
562 "GeometryDoesNotContainImage","`%s'",image->filename);
563 return((Image *) NULL);
566 Initialize crop image attributes.
568 crop_image=CloneImage(image,page.width,page.height,MagickTrue,exception);
569 if (crop_image == (Image *) NULL)
570 return((Image *) NULL);
571 crop_image->page.width=image->page.width;
572 crop_image->page.height=image->page.height;
573 if (((long) (bounding_box.x+bounding_box.width) > (long) image->page.width) ||
574 ((long) (bounding_box.y+bounding_box.height) > (long) image->page.height))
576 crop_image->page.width=bounding_box.width;
577 crop_image->page.height=bounding_box.height;
579 crop_image->page.x=bounding_box.x;
580 crop_image->page.y=bounding_box.y;
586 image_view=AcquireCacheView(image);
587 crop_view=AcquireCacheView(crop_image);
588 #if defined(MAGICKCORE_OPENMP_SUPPORT)
589 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
591 for (y=0; y < (long) crop_image->rows; y++)
593 register const IndexPacket
596 register const PixelPacket
600 *restrict crop_indexes;
605 if (status == MagickFalse)
607 p=GetCacheViewVirtualPixels(image_view,page.x,page.y+y,crop_image->columns,
609 q=QueueCacheViewAuthenticPixels(crop_view,0,y,crop_image->columns,1,
611 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
616 (void) CopyMagickMemory(q,p,(size_t) crop_image->columns*sizeof(*q));
617 indexes=GetCacheViewVirtualIndexQueue(image_view);
618 if (indexes != (IndexPacket *) NULL)
620 crop_indexes=GetCacheViewAuthenticIndexQueue(crop_view);
621 if (crop_indexes != (IndexPacket *) NULL)
622 (void) CopyMagickMemory(crop_indexes,indexes,(size_t)
623 crop_image->columns*sizeof(*crop_indexes));
625 if (SyncCacheViewAuthenticPixels(crop_view,exception) == MagickFalse)
627 if (image->progress_monitor != (MagickProgressMonitor) NULL)
632 #if defined(MAGICKCORE_OPENMP_SUPPORT)
633 #pragma omp critical (MagickCore_CropImage)
635 proceed=SetImageProgress(image,CropImageTag,progress++,image->rows);
636 if (proceed == MagickFalse)
640 crop_view=DestroyCacheView(crop_view);
641 image_view=DestroyCacheView(image_view);
642 crop_image->type=image->type;
643 if (status == MagickFalse)
644 crop_image=DestroyImage(crop_image);
649 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
653 % E x c e r p t I m a g e %
657 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
659 % ExcerptImage() returns a excerpt of the image as defined by the geometry.
661 % The format of the ExcerptImage method is:
663 % Image *ExcerptImage(const Image *image,const RectangleInfo *geometry,
664 % ExceptionInfo *exception)
666 % A description of each parameter follows:
668 % o image: the image.
670 % o geometry: Define the region of the image to extend with members
671 % x, y, width, and height.
673 % o exception: return any errors or warnings in this structure.
676 MagickExport Image *ExcerptImage(const Image *image,
677 const RectangleInfo *geometry,ExceptionInfo *exception)
679 #define ExcerptImageTag "Excerpt/Image"
696 Allocate excerpt image.
698 assert(image != (const Image *) NULL);
699 assert(image->signature == MagickSignature);
700 if (image->debug != MagickFalse)
701 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
702 assert(geometry != (const RectangleInfo *) NULL);
703 assert(exception != (ExceptionInfo *) NULL);
704 assert(exception->signature == MagickSignature);
705 excerpt_image=CloneImage(image,geometry->width,geometry->height,MagickTrue,
707 if (excerpt_image == (Image *) NULL)
708 return((Image *) NULL);
714 image_view=AcquireCacheView(image);
715 excerpt_view=AcquireCacheView(excerpt_image);
716 #if defined(MAGICKCORE_OPENMP_SUPPORT)
717 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
719 for (y=0; y < (long) excerpt_image->rows; y++)
721 register const PixelPacket
725 *restrict excerpt_indexes,
731 if (status == MagickFalse)
733 p=GetCacheViewVirtualPixels(image_view,geometry->x,geometry->y+y,
734 geometry->width,1,exception);
735 q=GetCacheViewAuthenticPixels(excerpt_view,0,y,excerpt_image->columns,1,
737 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
742 (void) CopyMagickMemory(q,p,(size_t) excerpt_image->columns*sizeof(*q));
743 indexes=GetCacheViewAuthenticIndexQueue(image_view);
744 if (indexes != (IndexPacket *) NULL)
746 excerpt_indexes=GetCacheViewAuthenticIndexQueue(excerpt_view);
747 if (excerpt_indexes != (IndexPacket *) NULL)
748 (void) CopyMagickMemory(excerpt_indexes,indexes,(size_t)
749 excerpt_image->columns*sizeof(*excerpt_indexes));
751 if (SyncCacheViewAuthenticPixels(excerpt_view,exception) == MagickFalse)
753 if (image->progress_monitor != (MagickProgressMonitor) NULL)
758 #if defined(MAGICKCORE_OPENMP_SUPPORT)
759 #pragma omp critical (MagickCore_ExcerptImage)
761 proceed=SetImageProgress(image,ExcerptImageTag,progress++,image->rows);
762 if (proceed == MagickFalse)
766 excerpt_view=DestroyCacheView(excerpt_view);
767 image_view=DestroyCacheView(image_view);
768 excerpt_image->type=image->type;
769 if (status == MagickFalse)
770 excerpt_image=DestroyImage(excerpt_image);
771 return(excerpt_image);
775 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
779 % E x t e n t I m a g e %
783 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
785 % ExtentImage() extends the image as defined by the geometry, gravity, and
786 % image background color. Set the (x,y) offset of the geometry to move the
787 % original image relative to the extended image.
789 % The format of the ExtentImage method is:
791 % Image *ExtentImage(const Image *image,const RectangleInfo *geometry,
792 % ExceptionInfo *exception)
794 % A description of each parameter follows:
796 % o image: the image.
798 % o geometry: Define the region of the image to extend with members
799 % x, y, width, and height.
801 % o exception: return any errors or warnings in this structure.
804 MagickExport Image *ExtentImage(const Image *image,
805 const RectangleInfo *geometry,ExceptionInfo *exception)
811 Allocate extent image.
813 assert(image != (const Image *) NULL);
814 assert(image->signature == MagickSignature);
815 if (image->debug != MagickFalse)
816 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
817 assert(geometry != (const RectangleInfo *) NULL);
818 assert(exception != (ExceptionInfo *) NULL);
819 assert(exception->signature == MagickSignature);
820 extent_image=CloneImage(image,geometry->width,geometry->height,MagickTrue,
822 if (extent_image == (Image *) NULL)
823 return((Image *) NULL);
824 if (SetImageStorageClass(extent_image,DirectClass) == MagickFalse)
826 InheritException(exception,&extent_image->exception);
827 extent_image=DestroyImage(extent_image);
828 return((Image *) NULL);
830 if (extent_image->background_color.opacity != OpaqueOpacity)
831 extent_image->matte=MagickTrue;
832 (void) SetImageBackgroundColor(extent_image);
833 (void) CompositeImage(extent_image,image->compose,image,geometry->x,
835 return(extent_image);
839 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
843 % F l i p I m a g e %
847 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
849 % FlipImage() creates a vertical mirror image by reflecting the pixels
850 % around the central x-axis.
852 % The format of the FlipImage method is:
854 % Image *FlipImage(const Image *image,ExceptionInfo *exception)
856 % A description of each parameter follows:
858 % o image: the image.
860 % o exception: return any errors or warnings in this structure.
863 MagickExport Image *FlipImage(const Image *image,ExceptionInfo *exception)
865 #define FlipImageTag "Flip/Image"
881 assert(image != (const Image *) NULL);
882 assert(image->signature == MagickSignature);
883 if (image->debug != MagickFalse)
884 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
885 assert(exception != (ExceptionInfo *) NULL);
886 assert(exception->signature == MagickSignature);
887 flip_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
888 if (flip_image == (Image *) NULL)
889 return((Image *) NULL);
895 image_view=AcquireCacheView(image);
896 flip_view=AcquireCacheView(flip_image);
897 #if defined(MAGICKCORE_OPENMP_SUPPORT)
898 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
900 for (y=0; y < (long) flip_image->rows; y++)
902 register const IndexPacket
905 register const PixelPacket
909 *restrict flip_indexes;
914 if (status == MagickFalse)
916 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
917 q=QueueCacheViewAuthenticPixels(flip_view,0,(long) (flip_image->rows-y-1),
918 flip_image->columns,1,exception);
919 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
924 (void) CopyMagickMemory(q,p,(size_t) image->columns*sizeof(*q));
925 indexes=GetCacheViewVirtualIndexQueue(image_view);
926 if (indexes != (const IndexPacket *) NULL)
928 flip_indexes=GetCacheViewAuthenticIndexQueue(flip_view);
929 if (flip_indexes != (IndexPacket *) NULL)
930 (void) CopyMagickMemory(flip_indexes,indexes,(size_t) image->columns*
931 sizeof(*flip_indexes));
933 if (SyncCacheViewAuthenticPixels(flip_view,exception) == MagickFalse)
935 if (image->progress_monitor != (MagickProgressMonitor) NULL)
940 #if defined(MAGICKCORE_OPENMP_SUPPORT)
941 #pragma omp critical (MagickCore_FlipImage)
943 proceed=SetImageProgress(image,FlipImageTag,progress++,image->rows);
944 if (proceed == MagickFalse)
948 flip_view=DestroyCacheView(flip_view);
949 image_view=DestroyCacheView(image_view);
950 flip_image->type=image->type;
951 if (status == MagickFalse)
952 flip_image=DestroyImage(flip_image);
957 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
961 % F l o p I m a g e %
965 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
967 % FlopImage() creates a horizontal mirror image by reflecting the pixels
968 % around the central y-axis.
970 % The format of the FlopImage method is:
972 % Image *FlopImage(const Image *image,ExceptionInfo *exception)
974 % A description of each parameter follows:
976 % o image: the image.
978 % o exception: return any errors or warnings in this structure.
981 MagickExport Image *FlopImage(const Image *image,ExceptionInfo *exception)
983 #define FlopImageTag "Flop/Image"
999 assert(image != (const Image *) NULL);
1000 assert(image->signature == MagickSignature);
1001 if (image->debug != MagickFalse)
1002 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1003 assert(exception != (ExceptionInfo *) NULL);
1004 assert(exception->signature == MagickSignature);
1005 flop_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
1006 if (flop_image == (Image *) NULL)
1007 return((Image *) NULL);
1013 image_view=AcquireCacheView(image);
1014 flop_view=AcquireCacheView(flop_image);
1015 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1016 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
1018 for (y=0; y < (long) flop_image->rows; y++)
1020 register const IndexPacket
1023 register const PixelPacket
1026 register IndexPacket
1027 *restrict flop_indexes;
1032 register PixelPacket
1035 if (status == MagickFalse)
1037 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1038 q=QueueCacheViewAuthenticPixels(flop_view,0,y,flop_image->columns,1,
1040 if ((p == (PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
1045 q+=flop_image->columns;
1046 indexes=GetCacheViewVirtualIndexQueue(image_view);
1047 flop_indexes=GetCacheViewAuthenticIndexQueue(flop_view);
1048 for (x=0; x < (long) flop_image->columns; x++)
1051 if ((indexes != (const IndexPacket *) NULL) &&
1052 (flop_indexes != (IndexPacket *) NULL))
1053 flop_indexes[flop_image->columns-x-1]=indexes[x];
1055 if (SyncCacheViewAuthenticPixels(flop_view,exception) == MagickFalse)
1057 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1062 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1063 #pragma omp critical (MagickCore_FlopImage)
1065 proceed=SetImageProgress(image,FlopImageTag,progress++,image->rows);
1066 if (proceed == MagickFalse)
1070 flop_view=DestroyCacheView(flop_view);
1071 image_view=DestroyCacheView(image_view);
1072 flop_image->type=image->type;
1073 if (status == MagickFalse)
1074 flop_image=DestroyImage(flop_image);
1079 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1083 % R o l l I m a g e %
1087 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1089 % RollImage() offsets an image as defined by x_offset and y_offset.
1091 % The format of the RollImage method is:
1093 % Image *RollImage(const Image *image,const long x_offset,
1094 % const long y_offset,ExceptionInfo *exception)
1096 % A description of each parameter follows:
1098 % o image: the image.
1100 % o x_offset: the number of columns to roll in the horizontal direction.
1102 % o y_offset: the number of rows to roll in the vertical direction.
1104 % o exception: return any errors or warnings in this structure.
1108 static inline MagickBooleanType CopyImageRegion(Image *destination,
1109 const Image *source,const unsigned long columns,const unsigned long rows,
1110 const long sx,const long sy,const long dx,const long dy,
1111 ExceptionInfo *exception)
1124 source_view=AcquireCacheView(source);
1125 destination_view=AcquireCacheView(destination);
1126 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1127 #pragma omp parallel for schedule(dynamic,4) shared(status)
1129 for (y=0; y < (long) rows; y++)
1134 register const PixelPacket
1137 register IndexPacket
1139 *restrict destination_indexes;
1144 register PixelPacket
1150 if (status == MagickFalse)
1152 p=GetCacheViewVirtualPixels(source_view,sx,sy+y,columns,1,exception);
1153 q=GetCacheViewAuthenticPixels(destination_view,dx,dy+y,columns,1,exception);
1154 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
1159 indexes=GetCacheViewAuthenticIndexQueue(source_view);
1160 for (x=0; x < (long) columns; x++)
1162 if (indexes != (IndexPacket *) NULL)
1164 destination_indexes=GetCacheViewAuthenticIndexQueue(destination_view);
1165 for (x=0; x < (long) columns; x++)
1166 destination_indexes[x]=indexes[x];
1168 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
1169 if (sync == MagickFalse)
1172 destination_view=DestroyCacheView(destination_view);
1173 source_view=DestroyCacheView(source_view);
1177 MagickExport Image *RollImage(const Image *image,const long x_offset,
1178 const long y_offset,ExceptionInfo *exception)
1180 #define RollImageTag "Roll/Image"
1192 Initialize roll image attributes.
1194 assert(image != (const Image *) NULL);
1195 assert(image->signature == MagickSignature);
1196 if (image->debug != MagickFalse)
1197 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1198 assert(exception != (ExceptionInfo *) NULL);
1199 assert(exception->signature == MagickSignature);
1200 roll_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
1201 if (roll_image == (Image *) NULL)
1202 return((Image *) NULL);
1205 while (offset.x < 0)
1206 offset.x+=image->columns;
1207 while (offset.x >= (long) image->columns)
1208 offset.x-=image->columns;
1209 while (offset.y < 0)
1210 offset.y+=image->rows;
1211 while (offset.y >= (long) image->rows)
1212 offset.y-=image->rows;
1216 status=CopyImageRegion(roll_image,image,(unsigned long) offset.x,
1217 (unsigned long) offset.y,(long) image->columns-offset.x,(long) image->rows-
1218 offset.y,0,0,exception);
1219 (void) SetImageProgress(image,RollImageTag,0,3);
1220 status|=CopyImageRegion(roll_image,image,image->columns-offset.x,
1221 (unsigned long) offset.y,0,(long) image->rows-offset.y,offset.x,0,
1223 (void) SetImageProgress(image,RollImageTag,1,3);
1224 status|=CopyImageRegion(roll_image,image,(unsigned long) offset.x,image->rows-
1225 offset.y,(long) image->columns-offset.x,0,0,offset.y,exception);
1226 (void) SetImageProgress(image,RollImageTag,2,3);
1227 status|=CopyImageRegion(roll_image,image,image->columns-offset.x,image->rows-
1228 offset.y,0,0,offset.x,offset.y,exception);
1229 (void) SetImageProgress(image,RollImageTag,3,3);
1230 roll_image->type=image->type;
1231 if (status == MagickFalse)
1232 roll_image=DestroyImage(roll_image);
1237 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1241 % S h a v e I m a g e %
1245 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1247 % ShaveImage() shaves pixels from the image edges. It allocates the memory
1248 % necessary for the new Image structure and returns a pointer to the new
1251 % The format of the ShaveImage method is:
1253 % Image *ShaveImage(const Image *image,const RectangleInfo *shave_info,
1254 % ExceptionInfo *exception)
1256 % A description of each parameter follows:
1258 % o shave_image: Method ShaveImage returns a pointer to the shaved
1259 % image. A null image is returned if there is a memory shortage or
1260 % if the image width or height is zero.
1262 % o image: the image.
1264 % o shave_info: Specifies a pointer to a RectangleInfo which defines the
1265 % region of the image to crop.
1267 % o exception: return any errors or warnings in this structure.
1270 MagickExport Image *ShaveImage(const Image *image,
1271 const RectangleInfo *shave_info,ExceptionInfo *exception)
1279 assert(image != (const Image *) NULL);
1280 assert(image->signature == MagickSignature);
1281 if (image->debug != MagickFalse)
1282 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1283 if (((2*shave_info->width) >= image->columns) ||
1284 ((2*shave_info->height) >= image->rows))
1285 ThrowImageException(OptionWarning,"GeometryDoesNotContainImage");
1286 SetGeometry(image,&geometry);
1287 geometry.width-=2*shave_info->width;
1288 geometry.height-=2*shave_info->height;
1289 geometry.x=(long) shave_info->width+image->page.x;
1290 geometry.y=(long) shave_info->height+image->page.y;
1291 shave_image=CropImage(image,&geometry,exception);
1292 if (shave_image == (Image *) NULL)
1293 return((Image *) NULL);
1294 shave_image->page.width-=2*shave_info->width;
1295 shave_image->page.height-=2*shave_info->height;
1296 shave_image->page.x-=shave_info->width;
1297 shave_image->page.y-=shave_info->height;
1298 return(shave_image);
1302 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1306 % S p l i c e I m a g e %
1310 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1312 % SpliceImage() splices a solid color into the image as defined by the
1315 % The format of the SpliceImage method is:
1317 % Image *SpliceImage(const Image *image,const RectangleInfo *geometry,
1318 % ExceptionInfo *exception)
1320 % A description of each parameter follows:
1322 % o image: the image.
1324 % o geometry: Define the region of the image to splice with members
1325 % x, y, width, and height.
1327 % o exception: return any errors or warnings in this structure.
1330 MagickExport Image *SpliceImage(const Image *image,
1331 const RectangleInfo *geometry,ExceptionInfo *exception)
1333 #define SpliceImageTag "Splice/Image"
1357 Allocate splice image.
1359 assert(image != (const Image *) NULL);
1360 assert(image->signature == MagickSignature);
1361 if (image->debug != MagickFalse)
1362 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1363 assert(geometry != (const RectangleInfo *) NULL);
1364 assert(exception != (ExceptionInfo *) NULL);
1365 assert(exception->signature == MagickSignature);
1366 splice_geometry=(*geometry);
1367 splice_image=CloneImage(image,image->columns+splice_geometry.width,
1368 image->rows+splice_geometry.height,MagickTrue,exception);
1369 if (splice_image == (Image *) NULL)
1370 return((Image *) NULL);
1371 if (SetImageStorageClass(splice_image,DirectClass) == MagickFalse)
1373 InheritException(exception,&splice_image->exception);
1374 splice_image=DestroyImage(splice_image);
1375 return((Image *) NULL);
1377 (void) SetImageBackgroundColor(splice_image);
1379 Respect image geometry.
1381 switch (image->gravity)
1384 case UndefinedGravity:
1385 case NorthWestGravity:
1389 splice_geometry.x+=splice_geometry.width/2;
1392 case NorthEastGravity:
1394 splice_geometry.x+=splice_geometry.width;
1399 splice_geometry.y+=splice_geometry.width/2;
1405 splice_geometry.x+=splice_geometry.width/2;
1406 splice_geometry.y+=splice_geometry.height/2;
1411 splice_geometry.x+=splice_geometry.width;
1412 splice_geometry.y+=splice_geometry.height/2;
1415 case SouthWestGravity:
1417 splice_geometry.y+=splice_geometry.height;
1422 splice_geometry.x+=splice_geometry.width/2;
1423 splice_geometry.y+=splice_geometry.height;
1426 case SouthEastGravity:
1428 splice_geometry.x+=splice_geometry.width;
1429 splice_geometry.y+=splice_geometry.height;
1439 image_view=AcquireCacheView(image);
1440 splice_view=AcquireCacheView(splice_image);
1441 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1442 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
1444 for (y=0; y < (long) splice_geometry.y; y++)
1446 register const PixelPacket
1449 register IndexPacket
1451 *restrict splice_indexes;
1456 register PixelPacket
1459 if (status == MagickFalse)
1461 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1462 q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1,
1464 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
1469 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1470 splice_indexes=GetCacheViewAuthenticIndexQueue(splice_view);
1471 for (x=0; x < splice_geometry.x; x++)
1476 q->opacity=OpaqueOpacity;
1477 if (image->matte != MagickFalse)
1478 q->opacity=p->opacity;
1479 if (image->colorspace == CMYKColorspace)
1480 splice_indexes[x]=(*indexes++);
1484 for ( ; x < (long) (splice_geometry.x+splice_geometry.width); x++)
1486 for ( ; x < (long) splice_image->columns; x++)
1491 q->opacity=OpaqueOpacity;
1492 if (image->matte != MagickFalse)
1493 q->opacity=p->opacity;
1494 if (image->colorspace == CMYKColorspace)
1495 splice_indexes[x]=(*indexes++);
1499 if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse)
1501 proceed=SetImageProgress(image,SpliceImageTag,y,splice_image->rows);
1502 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1507 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1508 #pragma omp critical (MagickCore_TransposeImage)
1510 proceed=SetImageProgress(image,SpliceImageTag,progress++,
1511 splice_image->rows);
1512 if (proceed == MagickFalse)
1516 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1517 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
1519 for (y=(long) (splice_geometry.y+splice_geometry.height);
1520 y < (long) splice_image->rows; y++)
1522 register const PixelPacket
1525 register IndexPacket
1527 *restrict splice_indexes;
1532 register PixelPacket
1535 if (status == MagickFalse)
1537 p=GetCacheViewVirtualPixels(image_view,0,y-splice_geometry.height,
1538 image->columns,1,exception);
1539 q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1,
1541 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
1546 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1547 splice_indexes=GetCacheViewAuthenticIndexQueue(splice_view);
1548 for (x=0; x < splice_geometry.x; x++)
1553 q->opacity=OpaqueOpacity;
1554 if (image->matte != MagickFalse)
1555 q->opacity=p->opacity;
1556 if (image->colorspace == CMYKColorspace)
1557 splice_indexes[x]=(*indexes++);
1561 for ( ; x < (long) (splice_geometry.x+splice_geometry.width); x++)
1563 for ( ; x < (long) splice_image->columns; x++)
1568 q->opacity=OpaqueOpacity;
1569 if (image->matte != MagickFalse)
1570 q->opacity=p->opacity;
1571 if (image->colorspace == CMYKColorspace)
1572 splice_indexes[x]=(*indexes++);
1576 if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse)
1578 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1583 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1584 #pragma omp critical (MagickCore_TransposeImage)
1586 proceed=SetImageProgress(image,SpliceImageTag,progress++,
1587 splice_image->rows);
1588 if (proceed == MagickFalse)
1592 splice_view=DestroyCacheView(splice_view);
1593 image_view=DestroyCacheView(image_view);
1594 if (status == MagickFalse)
1595 splice_image=DestroyImage(splice_image);
1596 return(splice_image);
1600 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1604 % T r a n s f o r m I m a g e %
1608 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1610 % TransformImage() is a convenience method that behaves like ResizeImage() or
1611 % CropImage() but accepts scaling and/or cropping information as a region
1612 % geometry specification. If the operation fails, the original image handle
1615 % The format of the TransformImage method is:
1617 % MagickBooleanType TransformImage(Image **image,const char *crop_geometry,
1618 % const char *image_geometry)
1620 % A description of each parameter follows:
1622 % o image: the image The transformed image is returned as this parameter.
1624 % o crop_geometry: A crop geometry string. This geometry defines a
1625 % subregion of the image to crop.
1627 % o image_geometry: An image geometry string. This geometry defines the
1628 % final size of the image.
1631 static inline double MagickRound(double x)
1633 /* round the fraction to nearest integer */
1635 return((double) ((long) (x+0.5)));
1636 return((double) ((long) (x-0.5)));
1639 MagickExport MagickBooleanType TransformImage(Image **image,
1640 const char *crop_geometry,const char *image_geometry)
1652 assert(image != (Image **) NULL);
1653 assert((*image)->signature == MagickSignature);
1654 if ((*image)->debug != MagickFalse)
1655 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
1656 transform_image=(*image);
1657 if (crop_geometry != (const char *) NULL)
1666 Crop image to a user specified size.
1668 crop_image=NewImageList();
1669 flags=ParseGravityGeometry(transform_image,crop_geometry,&geometry,
1670 &(*image)->exception);
1671 /* crop into NxM tiles (@ flag) - AT */
1672 if ((flags & AreaValue) != 0 )
1678 width, height, w_step, h_step, x, y;
1683 if ( geometry.width == 0 ) geometry.width = 1;
1684 if ( geometry.height == 0 ) geometry.height = 1;
1686 width=(MagickRealType)transform_image->columns;
1687 height=(MagickRealType)transform_image->rows;
1688 if ((flags & AspectValue) == 0)
1690 width -= (MagickRealType)labs(geometry.x);
1691 height -= (MagickRealType)labs(geometry.y);
1695 width += (MagickRealType)labs(geometry.x);
1696 height += (MagickRealType)labs(geometry.y);
1698 w_step=width/geometry.width;
1699 h_step=height/geometry.height;
1701 next=NewImageList();
1702 for (y=0.0; y < height; )
1704 if ((flags & AspectValue) == 0)
1706 crop.y=MagickRound(y-(geometry.y>0?0:geometry.y));
1708 crop.height=MagickRound(y+(geometry.y<0?0:geometry.y));
1712 crop.y=MagickRound(y-(geometry.y>0?geometry.y:0) );
1714 crop.height=MagickRound(y+(geometry.y<0?geometry.y:0) );
1716 crop.height -= crop.y;
1717 for (x=0.0; x < width; )
1719 if ((flags & AspectValue) == 0)
1721 crop.x=MagickRound(x-(geometry.x>0?0:geometry.x));
1723 crop.width=MagickRound(x+(geometry.x<0?0:geometry.x));
1727 crop.x=MagickRound(x-(geometry.x>0?geometry.x:0) );
1729 crop.width=MagickRound(x+(geometry.x<0?geometry.x:0) );
1731 crop.width -= crop.x;
1732 next=CropImage(transform_image,&crop,&(*image)->exception);
1733 if (next == (Image *) NULL)
1735 AppendImageToList(&crop_image,next);
1737 if (next == (Image *) NULL)
1741 /* crop a single region at +X+Y */
1742 else if (((geometry.width == 0) && (geometry.height == 0)) ||
1743 ((flags & XValue) != 0) || ((flags & YValue) != 0))
1745 crop_image=CropImage(transform_image,&geometry,&(*image)->exception);
1746 if ((crop_image != (Image *) NULL) && ((flags & AspectValue) != 0))
1748 crop_image->page.width=geometry.width;
1749 crop_image->page.height=geometry.height;
1750 crop_image->page.x-=geometry.x;
1751 crop_image->page.y-=geometry.y;
1754 /* crop into tiles of fixed size WxH */
1755 else if ((transform_image->columns > geometry.width) ||
1756 (transform_image->rows > geometry.height))
1772 Crop repeatedly to create uniform scenes.
1774 if (transform_image->page.width == 0)
1775 transform_image->page.width=transform_image->columns;
1776 if (transform_image->page.height == 0)
1777 transform_image->page.height=transform_image->rows;
1778 width=geometry.width;
1780 width=transform_image->page.width;
1781 height=geometry.height;
1783 height=transform_image->page.height;
1784 next=NewImageList();
1785 for (y=0; y < (long) transform_image->page.height; y+=height)
1787 for (x=0; x < (long) transform_image->page.width; x+=width)
1789 geometry.width=width;
1790 geometry.height=height;
1793 next=CropImage(transform_image,&geometry,&(*image)->exception);
1794 if (next == (Image *) NULL)
1796 AppendImageToList(&crop_image,next);
1798 if (next == (Image *) NULL)
1802 if (crop_image == (Image *) NULL)
1803 transform_image=CloneImage(*image,0,0,MagickTrue,&(*image)->exception);
1806 transform_image=DestroyImage(transform_image);
1807 transform_image=GetFirstImageInList(crop_image);
1809 *image=transform_image;
1811 if (image_geometry == (const char *) NULL)
1814 Scale image to a user specified size.
1816 flags=ParseRegionGeometry(transform_image,image_geometry,&geometry,
1817 &(*image)->exception);
1818 if ((transform_image->columns == geometry.width) &&
1819 (transform_image->rows == geometry.height))
1821 resize_image=ZoomImage(transform_image,geometry.width,geometry.height,
1822 &(*image)->exception);
1823 if (resize_image == (Image *) NULL)
1824 return(MagickFalse);
1825 transform_image=DestroyImage(transform_image);
1826 transform_image=resize_image;
1827 *image=transform_image;
1832 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1836 % T r a n s f o r m I m a g e s %
1839 % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1841 % TransformImages() calls TransformImage() on each image of a sequence.
1843 % The format of the TransformImage method is:
1845 % MagickBooleanType TransformImages(Image **image,
1846 % const char *crop_geometry,const char *image_geometry)
1848 % A description of each parameter follows:
1850 % o image: the image The transformed image is returned as this parameter.
1852 % o crop_geometry: A crop geometry string. This geometry defines a
1853 % subregion of the image to crop.
1855 % o image_geometry: An image geometry string. This geometry defines the
1856 % final size of the image.
1859 MagickExport MagickBooleanType TransformImages(Image **images,
1860 const char *crop_geometry,const char *image_geometry)
1873 assert(images != (Image **) NULL);
1874 assert((*images)->signature == MagickSignature);
1875 if ((*images)->debug != MagickFalse)
1876 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1877 (*images)->filename);
1878 image_list=ImageListToArray(*images,&(*images)->exception);
1879 if (image_list == (Image **) NULL)
1880 return(MagickFalse);
1882 transform_images=NewImageList();
1883 for (i=0; image_list[i] != (Image *) NULL; i++)
1885 image=image_list[i];
1886 status|=TransformImage(&image,crop_geometry,image_geometry);
1887 AppendImageToList(&transform_images,image);
1889 *images=transform_images;
1890 image_list=(Image **) RelinquishMagickMemory(image_list);
1891 return(status != 0 ? MagickTrue : MagickFalse);
1895 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1899 % T r a n s p o s e I m a g e %
1903 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1905 % TransposeImage() creates a horizontal mirror image by reflecting the pixels
1906 % around the central y-axis while rotating them by 90 degrees.
1908 % The format of the TransposeImage method is:
1910 % Image *TransposeImage(const Image *image,ExceptionInfo *exception)
1912 % A description of each parameter follows:
1914 % o image: the image.
1916 % o exception: return any errors or warnings in this structure.
1919 MagickExport Image *TransposeImage(const Image *image,ExceptionInfo *exception)
1921 #define TransposeImageTag "Transpose/Image"
1940 assert(image != (const Image *) NULL);
1941 assert(image->signature == MagickSignature);
1942 if (image->debug != MagickFalse)
1943 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1944 assert(exception != (ExceptionInfo *) NULL);
1945 assert(exception->signature == MagickSignature);
1946 transpose_image=CloneImage(image,image->rows,image->columns,MagickTrue,
1948 if (transpose_image == (Image *) NULL)
1949 return((Image *) NULL);
1955 image_view=AcquireCacheView(image);
1956 transpose_view=AcquireCacheView(transpose_image);
1957 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1958 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
1960 for (y=0; y < (long) image->rows; y++)
1962 register const PixelPacket
1965 register IndexPacket
1966 *restrict transpose_indexes,
1969 register PixelPacket
1972 if (status == MagickFalse)
1974 p=GetCacheViewVirtualPixels(image_view,0,(long) image->rows-y-1,
1975 image->columns,1,exception);
1976 q=QueueCacheViewAuthenticPixels(transpose_view,(long) (image->rows-y-1),0,
1977 1,transpose_image->rows,exception);
1978 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
1983 (void) CopyMagickMemory(q,p,(size_t) image->columns*sizeof(*q));
1984 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1985 if (indexes != (IndexPacket *) NULL)
1987 transpose_indexes=GetCacheViewAuthenticIndexQueue(transpose_view);
1988 if (transpose_indexes != (IndexPacket *) NULL)
1989 (void) CopyMagickMemory(transpose_indexes,indexes,(size_t)
1990 image->columns*sizeof(*transpose_indexes));
1992 if (SyncCacheViewAuthenticPixels(transpose_view,exception) == MagickFalse)
1994 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1999 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2000 #pragma omp critical (MagickCore_TransposeImage)
2002 proceed=SetImageProgress(image,TransposeImageTag,progress++,
2004 if (proceed == MagickFalse)
2008 transpose_view=DestroyCacheView(transpose_view);
2009 image_view=DestroyCacheView(image_view);
2010 transpose_image->type=image->type;
2011 page=transpose_image->page;
2012 Swap(page.width,page.height);
2013 Swap(page.x,page.y);
2014 if (page.width != 0)
2015 page.x=(long) (page.width-transpose_image->columns-page.x);
2016 transpose_image->page=page;
2017 if (status == MagickFalse)
2018 transpose_image=DestroyImage(transpose_image);
2019 return(transpose_image);
2023 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2027 % T r a n s v e r s e I m a g e %
2031 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2033 % TransverseImage() creates a vertical mirror image by reflecting the pixels
2034 % around the central x-axis while rotating them by 270 degrees.
2036 % The format of the TransverseImage method is:
2038 % Image *TransverseImage(const Image *image,ExceptionInfo *exception)
2040 % A description of each parameter follows:
2042 % o image: the image.
2044 % o exception: return any errors or warnings in this structure.
2047 MagickExport Image *TransverseImage(const Image *image,ExceptionInfo *exception)
2049 #define TransverseImageTag "Transverse/Image"
2068 assert(image != (const Image *) NULL);
2069 assert(image->signature == MagickSignature);
2070 if (image->debug != MagickFalse)
2071 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2072 assert(exception != (ExceptionInfo *) NULL);
2073 assert(exception->signature == MagickSignature);
2074 transverse_image=CloneImage(image,image->rows,image->columns,MagickTrue,
2076 if (transverse_image == (Image *) NULL)
2077 return((Image *) NULL);
2083 image_view=AcquireCacheView(image);
2084 transverse_view=AcquireCacheView(transverse_image);
2085 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2086 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
2088 for (y=0; y < (long) image->rows; y++)
2093 register const PixelPacket
2096 register IndexPacket
2097 *restrict transverse_indexes,
2103 register PixelPacket
2106 if (status == MagickFalse)
2108 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2109 q=QueueCacheViewAuthenticPixels(transverse_view,(long) (image->rows-y-
2110 1),0,1,transverse_image->rows,exception);
2111 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
2117 for (x=0; x < (long) image->columns; x++)
2119 indexes=GetCacheViewAuthenticIndexQueue(image_view);
2120 if (indexes != (IndexPacket *) NULL)
2122 transverse_indexes=GetCacheViewAuthenticIndexQueue(transverse_view);
2123 if (transverse_indexes != (IndexPacket *) NULL)
2124 for (x=0; x < (long) image->columns; x++)
2125 transverse_indexes[image->columns-x-1]=indexes[x];
2127 sync=SyncCacheViewAuthenticPixels(transverse_view,exception);
2128 if (sync == MagickFalse)
2130 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2135 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2136 #pragma omp critical (MagickCore_TransverseImage)
2138 proceed=SetImageProgress(image,TransverseImageTag,progress++,
2140 if (proceed == MagickFalse)
2144 transverse_view=DestroyCacheView(transverse_view);
2145 image_view=DestroyCacheView(image_view);
2146 transverse_image->type=image->type;
2147 page=transverse_image->page;
2148 Swap(page.width,page.height);
2149 Swap(page.x,page.y);
2150 if (page.height != 0)
2151 page.y=(long) (page.height-transverse_image->rows-page.y);
2152 transverse_image->page=page;
2153 if (status == MagickFalse)
2154 transverse_image=DestroyImage(transverse_image);
2155 return(transverse_image);
2159 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2163 % T r i m I m a g e %
2167 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2169 % TrimImage() trims pixels from the image edges. It allocates the memory
2170 % necessary for the new Image structure and returns a pointer to the new
2173 % The format of the TrimImage method is:
2175 % Image *TrimImage(const Image *image,ExceptionInfo *exception)
2177 % A description of each parameter follows:
2179 % o image: the image.
2181 % o exception: return any errors or warnings in this structure.
2184 MagickExport Image *TrimImage(const Image *image,ExceptionInfo *exception)
2189 assert(image != (const Image *) NULL);
2190 assert(image->signature == MagickSignature);
2191 if (image->debug != MagickFalse)
2192 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2193 geometry=GetImageBoundingBox(image,exception);
2194 if ((geometry.width == 0) || (geometry.height == 0))
2199 crop_image=CloneImage(image,1,1,MagickTrue,exception);
2200 if (crop_image == (Image *) NULL)
2201 return((Image *) NULL);
2202 crop_image->background_color.opacity=(Quantum) TransparentOpacity;
2203 (void) SetImageBackgroundColor(crop_image);
2204 crop_image->page=image->page;
2205 crop_image->page.x=(-1);
2206 crop_image->page.y=(-1);
2209 geometry.x+=image->page.x;
2210 geometry.y+=image->page.y;
2211 return(CropImage(image,&geometry,exception));