2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % TTTTT RRRR AAA N N SSSSS FFFFF OOO RRRR M M %
7 % T R R A A NN N SS F O O R R MM MM %
8 % T RRRR AAAAA N N N SSS FFF O O RRRR M M M %
9 % T R R A A N NN SS F O O R R M M %
10 % T R R A A N N SSSSS F OOO R R M M %
13 % MagickCore Image Transform Methods %
20 % Copyright 1999-2010 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
42 #include "magick/studio.h"
43 #include "magick/attribute.h"
44 #include "magick/cache.h"
45 #include "magick/cache-view.h"
46 #include "magick/color.h"
47 #include "magick/color-private.h"
48 #include "magick/colorspace-private.h"
49 #include "magick/composite.h"
50 #include "magick/draw.h"
51 #include "magick/effect.h"
52 #include "magick/exception.h"
53 #include "magick/exception-private.h"
54 #include "magick/geometry.h"
55 #include "magick/image.h"
56 #include "magick/memory_.h"
57 #include "magick/layer.h"
58 #include "magick/list.h"
59 #include "magick/monitor.h"
60 #include "magick/monitor-private.h"
61 #include "magick/pixel-private.h"
62 #include "magick/resource_.h"
63 #include "magick/resize.h"
64 #include "magick/statistic.h"
65 #include "magick/string_.h"
66 #include "magick/transform.h"
69 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
77 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
79 % Chop() removes a region of an image and collapses the image to occupy the
82 % The format of the ChopImage method is:
84 % Image *ChopImage(const Image *image,const RectangleInfo *chop_info)
85 % ExceptionInfo *exception)
87 % A description of each parameter follows:
91 % o chop_info: Define the region of the image to chop.
93 % o exception: return any errors or warnings in this structure.
96 MagickExport Image *ChopImage(const Image *image,const RectangleInfo *chop_info,
97 ExceptionInfo *exception)
99 #define ChopImageTag "Chop/Image"
124 assert(image != (const Image *) NULL);
125 assert(image->signature == MagickSignature);
126 if (image->debug != MagickFalse)
127 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
128 assert(exception != (ExceptionInfo *) NULL);
129 assert(exception->signature == MagickSignature);
130 assert(chop_info != (RectangleInfo *) NULL);
131 if (((chop_info->x+(long) chop_info->width) < 0) ||
132 ((chop_info->y+(long) chop_info->height) < 0) ||
133 (chop_info->x > (long) image->columns) ||
134 (chop_info->y > (long) image->rows))
135 ThrowImageException(OptionWarning,"GeometryDoesNotContainImage");
137 if ((extent.x+(long) extent.width) > (long) image->columns)
138 extent.width=(unsigned long) ((long) image->columns-extent.x);
139 if ((extent.y+(long) extent.height) > (long) image->rows)
140 extent.height=(unsigned long) ((long) image->rows-extent.y);
143 extent.width-=(unsigned long) (-extent.x);
148 extent.height-=(unsigned long) (-extent.y);
151 chop_image=CloneImage(image,image->columns-extent.width,image->rows-
152 extent.height,MagickTrue,exception);
153 if (chop_image == (Image *) NULL)
154 return((Image *) NULL);
160 image_view=AcquireCacheView(image);
161 chop_view=AcquireCacheView(chop_image);
162 for (y=0; y < (long) extent.y; y++)
164 register const PixelPacket
168 *restrict chop_indexes,
177 p=GetCacheViewVirtualPixels(image_view,0,i++,image->columns,1,exception);
178 q=QueueCacheViewAuthenticPixels(chop_view,0,j++,chop_image->columns,1,
180 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
182 indexes=GetCacheViewAuthenticIndexQueue(image_view);
183 chop_indexes=GetCacheViewAuthenticIndexQueue(chop_view);
184 for (x=0; x < (long) image->columns; x++)
186 if ((x < extent.x) || (x >= (long) (extent.x+extent.width)))
189 if (indexes != (IndexPacket *) NULL)
191 if (chop_indexes != (IndexPacket *) NULL)
192 *chop_indexes++=indexes[x];
198 if (SyncCacheViewAuthenticPixels(chop_view,exception) == MagickFalse)
200 proceed=SetImageProgress(image,ChopImageTag,y,chop_image->rows);
201 if (proceed == MagickFalse)
208 for (y=0; y < (long) (image->rows-(extent.y+extent.height)); y++)
210 register const PixelPacket
214 *restrict chop_indexes,
223 p=GetCacheViewVirtualPixels(image_view,0,i++,image->columns,1,exception);
224 q=QueueCacheViewAuthenticPixels(chop_view,0,j++,chop_image->columns,1,
226 if ((p == (PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
228 indexes=GetCacheViewAuthenticIndexQueue(image_view);
229 chop_indexes=GetCacheViewAuthenticIndexQueue(chop_view);
230 for (x=0; x < (long) image->columns; x++)
232 if ((x < extent.x) || (x >= (long) (extent.x+extent.width)))
235 if (indexes != (IndexPacket *) NULL)
237 if (chop_indexes != (IndexPacket *) NULL)
238 *chop_indexes++=indexes[x];
244 if (SyncCacheViewAuthenticPixels(chop_view,exception) == MagickFalse)
246 proceed=SetImageProgress(image,ChopImageTag,y,chop_image->rows);
247 if (proceed == MagickFalse)
250 chop_view=DestroyCacheView(chop_view);
251 image_view=DestroyCacheView(image_view);
252 chop_image->type=image->type;
257 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
261 + C o n s o l i d a t e C M Y K I m a g e %
265 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
267 % ConsolidateCMYKImage() consolidates separate C, M, Y, and K planes into a
270 % The format of the ConsolidateCMYKImage method is:
272 % Image *ConsolidateCMYKImage(const Image *image,ExceptionInfo *exception)
274 % A description of each parameter follows:
276 % o image: the image sequence.
278 % o exception: return any errors or warnings in this structure.
281 MagickExport Image *ConsolidateCMYKImages(const Image *images,
282 ExceptionInfo *exception)
295 Consolidate separate C, M, Y, and K planes into a single image.
297 assert(images != (Image *) NULL);
298 assert(images->signature == MagickSignature);
299 if (images->debug != MagickFalse)
300 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
301 assert(exception != (ExceptionInfo *) NULL);
302 assert(exception->signature == MagickSignature);
303 cmyk_images=NewImageList();
304 for (i=0; i < (long) GetImageListLength(images); i+=4)
306 cmyk_image=CloneImage(images,images->columns,images->rows,MagickTrue,
308 if (cmyk_image == (Image *) NULL)
310 if (SetImageStorageClass(cmyk_image,DirectClass) == MagickFalse)
312 (void) SetImageColorspace(cmyk_image,CMYKColorspace);
313 for (y=0; y < (long) images->rows; y++)
315 register const PixelPacket
324 p=GetVirtualPixels(images,0,y,images->columns,1,exception);
325 q=QueueAuthenticPixels(cmyk_image,0,y,cmyk_image->columns,1,exception);
326 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
328 for (x=0; x < (long) images->columns; x++)
330 q->red=(Quantum) (QuantumRange-PixelIntensityToQuantum(p));
334 if (SyncAuthenticPixels(cmyk_image,exception) == MagickFalse)
337 images=GetNextImageInList(images);
338 if (images == (Image *) NULL)
340 for (y=0; y < (long) images->rows; y++)
342 register const PixelPacket
351 p=GetVirtualPixels(images,0,y,images->columns,1,exception);
352 q=GetAuthenticPixels(cmyk_image,0,y,cmyk_image->columns,1,exception);
353 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
355 for (x=0; x < (long) images->columns; x++)
357 q->green=(Quantum) (QuantumRange-PixelIntensityToQuantum(p));
361 if (SyncAuthenticPixels(cmyk_image,exception) == MagickFalse)
364 images=GetNextImageInList(images);
365 if (images == (Image *) NULL)
367 for (y=0; y < (long) images->rows; y++)
369 register const PixelPacket
378 p=GetVirtualPixels(images,0,y,images->columns,1,exception);
379 q=GetAuthenticPixels(cmyk_image,0,y,cmyk_image->columns,1,exception);
380 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
382 for (x=0; x < (long) images->columns; x++)
384 q->blue=(Quantum) (QuantumRange-PixelIntensityToQuantum(p));
388 if (SyncAuthenticPixels(cmyk_image,exception) == MagickFalse)
391 images=GetNextImageInList(images);
392 if (images == (Image *) NULL)
394 for (y=0; y < (long) images->rows; y++)
396 register const PixelPacket
408 p=GetVirtualPixels(images,0,y,images->columns,1,exception);
409 q=GetAuthenticPixels(cmyk_image,0,y,cmyk_image->columns,1,exception);
410 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
412 indexes=GetAuthenticIndexQueue(cmyk_image);
413 for (x=0; x < (long) images->columns; x++)
415 indexes[x]=(IndexPacket) (QuantumRange-PixelIntensityToQuantum(p));
418 if (SyncAuthenticPixels(cmyk_image,exception) == MagickFalse)
421 AppendImageToList(&cmyk_images,cmyk_image);
422 images=GetNextImageInList(images);
423 if (images == (Image *) NULL)
430 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
434 % C r o p I m a g e %
438 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
440 % CropImage() extracts a region of the image starting at the offset defined
443 % The format of the CropImage method is:
445 % Image *CropImage(const Image *image,const RectangleInfo *geometry,
446 % ExceptionInfo *exception)
448 % A description of each parameter follows:
450 % o image: the image.
452 % o geometry: Define the region of the image to crop with members
453 % x, y, width, and height.
455 % o exception: return any errors or warnings in this structure.
458 MagickExport Image *CropImage(const Image *image,const RectangleInfo *geometry,
459 ExceptionInfo *exception)
461 #define CropImageTag "Crop/Image"
484 assert(image != (const Image *) NULL);
485 assert(image->signature == MagickSignature);
486 if (image->debug != MagickFalse)
487 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
488 assert(geometry != (const RectangleInfo *) NULL);
489 assert(exception != (ExceptionInfo *) NULL);
490 assert(exception->signature == MagickSignature);
491 bounding_box=image->page;
492 if ((bounding_box.width == 0) || (bounding_box.height == 0))
494 bounding_box.width=image->columns;
495 bounding_box.height=image->rows;
499 page.width=bounding_box.width;
500 if (page.height == 0)
501 page.height=bounding_box.height;
502 if (((bounding_box.x-page.x) >= (long) page.width) ||
503 ((bounding_box.y-page.y) >= (long) page.height) ||
504 ((page.x-bounding_box.x) > (long) image->columns) ||
505 ((page.y-bounding_box.y) > (long) image->rows))
508 Crop is not within virtual canvas, return 1 pixel transparent image.
510 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
511 "GeometryDoesNotContainImage","`%s'",image->filename);
512 crop_image=CloneImage(image,1,1,MagickTrue,exception);
513 if (crop_image == (Image *) NULL)
514 return((Image *) NULL);
515 crop_image->background_color.opacity=(Quantum) TransparentOpacity;
516 (void) SetImageBackgroundColor(crop_image);
517 crop_image->page=bounding_box;
518 crop_image->page.x=(-1);
519 crop_image->page.y=(-1);
520 if (crop_image->dispose == BackgroundDispose)
521 crop_image->dispose=NoneDispose;
524 if ((page.x < 0) && (bounding_box.x >= 0))
526 page.width+=page.x-bounding_box.x;
531 page.width-=bounding_box.x-page.x;
532 page.x-=bounding_box.x;
536 if ((page.y < 0) && (bounding_box.y >= 0))
538 page.height+=page.y-bounding_box.y;
543 page.height-=bounding_box.y-page.y;
544 page.y-=bounding_box.y;
548 if ((unsigned long) (page.x+page.width) > image->columns)
549 page.width=image->columns-page.x;
550 if (geometry->width != 0)
551 if (page.width > geometry->width)
552 page.width=geometry->width;
553 if ((unsigned long) (page.y+page.height) > image->rows)
554 page.height=image->rows-page.y;
555 if (geometry->height != 0)
556 if (page.height > geometry->height)
557 page.height=geometry->height;
558 bounding_box.x+=page.x;
559 bounding_box.y+=page.y;
560 if ((page.width == 0) || (page.height == 0))
562 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
563 "GeometryDoesNotContainImage","`%s'",image->filename);
564 return((Image *) NULL);
567 Initialize crop image attributes.
569 crop_image=CloneImage(image,page.width,page.height,MagickTrue,exception);
570 if (crop_image == (Image *) NULL)
571 return((Image *) NULL);
572 crop_image->page.width=image->page.width;
573 crop_image->page.height=image->page.height;
574 if (((long) (bounding_box.x+bounding_box.width) > (long) image->page.width) ||
575 ((long) (bounding_box.y+bounding_box.height) > (long) image->page.height))
577 crop_image->page.width=bounding_box.width;
578 crop_image->page.height=bounding_box.height;
580 crop_image->page.x=bounding_box.x;
581 crop_image->page.y=bounding_box.y;
587 image_view=AcquireCacheView(image);
588 crop_view=AcquireCacheView(crop_image);
589 #if defined(MAGICKCORE_OPENMP_SUPPORT)
590 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
592 for (y=0; y < (long) crop_image->rows; y++)
594 register const IndexPacket
597 register const PixelPacket
601 *restrict crop_indexes;
606 if (status == MagickFalse)
608 p=GetCacheViewVirtualPixels(image_view,page.x,page.y+y,crop_image->columns,
610 q=QueueCacheViewAuthenticPixels(crop_view,0,y,crop_image->columns,1,
612 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
617 (void) CopyMagickMemory(q,p,(size_t) crop_image->columns*sizeof(*q));
618 indexes=GetCacheViewVirtualIndexQueue(image_view);
619 if (indexes != (IndexPacket *) NULL)
621 crop_indexes=GetCacheViewAuthenticIndexQueue(crop_view);
622 if (crop_indexes != (IndexPacket *) NULL)
623 (void) CopyMagickMemory(crop_indexes,indexes,(size_t)
624 crop_image->columns*sizeof(*crop_indexes));
626 if (SyncCacheViewAuthenticPixels(crop_view,exception) == MagickFalse)
628 if (image->progress_monitor != (MagickProgressMonitor) NULL)
633 #if defined(MAGICKCORE_OPENMP_SUPPORT)
634 #pragma omp critical (MagickCore_CropImage)
636 proceed=SetImageProgress(image,CropImageTag,progress++,image->rows);
637 if (proceed == MagickFalse)
641 crop_view=DestroyCacheView(crop_view);
642 image_view=DestroyCacheView(image_view);
643 crop_image->type=image->type;
644 if (status == MagickFalse)
645 crop_image=DestroyImage(crop_image);
650 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
654 % E x c e r p t I m a g e %
658 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
660 % ExcerptImage() returns a excerpt of the image as defined by the geometry.
662 % The format of the ExcerptImage method is:
664 % Image *ExcerptImage(const Image *image,const RectangleInfo *geometry,
665 % ExceptionInfo *exception)
667 % A description of each parameter follows:
669 % o image: the image.
671 % o geometry: Define the region of the image to extend with members
672 % x, y, width, and height.
674 % o exception: return any errors or warnings in this structure.
677 MagickExport Image *ExcerptImage(const Image *image,
678 const RectangleInfo *geometry,ExceptionInfo *exception)
680 #define ExcerptImageTag "Excerpt/Image"
697 Allocate excerpt image.
699 assert(image != (const Image *) NULL);
700 assert(image->signature == MagickSignature);
701 if (image->debug != MagickFalse)
702 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
703 assert(geometry != (const RectangleInfo *) NULL);
704 assert(exception != (ExceptionInfo *) NULL);
705 assert(exception->signature == MagickSignature);
706 excerpt_image=CloneImage(image,geometry->width,geometry->height,MagickTrue,
708 if (excerpt_image == (Image *) NULL)
709 return((Image *) NULL);
715 image_view=AcquireCacheView(image);
716 excerpt_view=AcquireCacheView(excerpt_image);
717 #if defined(MAGICKCORE_OPENMP_SUPPORT)
718 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
720 for (y=0; y < (long) excerpt_image->rows; y++)
722 register const PixelPacket
726 *restrict excerpt_indexes,
732 if (status == MagickFalse)
734 p=GetCacheViewVirtualPixels(image_view,geometry->x,geometry->y+y,
735 geometry->width,1,exception);
736 q=GetCacheViewAuthenticPixels(excerpt_view,0,y,excerpt_image->columns,1,
738 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
743 (void) CopyMagickMemory(q,p,(size_t) excerpt_image->columns*sizeof(*q));
744 indexes=GetCacheViewAuthenticIndexQueue(image_view);
745 if (indexes != (IndexPacket *) NULL)
747 excerpt_indexes=GetCacheViewAuthenticIndexQueue(excerpt_view);
748 if (excerpt_indexes != (IndexPacket *) NULL)
749 (void) CopyMagickMemory(excerpt_indexes,indexes,(size_t)
750 excerpt_image->columns*sizeof(*excerpt_indexes));
752 if (SyncCacheViewAuthenticPixels(excerpt_view,exception) == MagickFalse)
754 if (image->progress_monitor != (MagickProgressMonitor) NULL)
759 #if defined(MAGICKCORE_OPENMP_SUPPORT)
760 #pragma omp critical (MagickCore_ExcerptImage)
762 proceed=SetImageProgress(image,ExcerptImageTag,progress++,image->rows);
763 if (proceed == MagickFalse)
767 excerpt_view=DestroyCacheView(excerpt_view);
768 image_view=DestroyCacheView(image_view);
769 excerpt_image->type=image->type;
770 if (status == MagickFalse)
771 excerpt_image=DestroyImage(excerpt_image);
772 return(excerpt_image);
776 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
780 % E x t e n t I m a g e %
784 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
786 % ExtentImage() extends the image as defined by the geometry, gravity, and
787 % image background color. Set the (x,y) offset of the geometry to move the
788 % original image relative to the extended image.
790 % The format of the ExtentImage method is:
792 % Image *ExtentImage(const Image *image,const RectangleInfo *geometry,
793 % ExceptionInfo *exception)
795 % A description of each parameter follows:
797 % o image: the image.
799 % o geometry: Define the region of the image to extend with members
800 % x, y, width, and height.
802 % o exception: return any errors or warnings in this structure.
805 MagickExport Image *ExtentImage(const Image *image,
806 const RectangleInfo *geometry,ExceptionInfo *exception)
812 Allocate extent image.
814 assert(image != (const Image *) NULL);
815 assert(image->signature == MagickSignature);
816 if (image->debug != MagickFalse)
817 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
818 assert(geometry != (const RectangleInfo *) NULL);
819 assert(exception != (ExceptionInfo *) NULL);
820 assert(exception->signature == MagickSignature);
821 extent_image=CloneImage(image,geometry->width,geometry->height,MagickTrue,
823 if (extent_image == (Image *) NULL)
824 return((Image *) NULL);
825 if (SetImageStorageClass(extent_image,DirectClass) == MagickFalse)
827 InheritException(exception,&extent_image->exception);
828 extent_image=DestroyImage(extent_image);
829 return((Image *) NULL);
831 if (extent_image->background_color.opacity != OpaqueOpacity)
832 extent_image->matte=MagickTrue;
833 (void) SetImageBackgroundColor(extent_image);
834 (void) CompositeImage(extent_image,image->compose,image,geometry->x,
836 return(extent_image);
840 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
844 % F l i p I m a g e %
848 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
850 % FlipImage() creates a vertical mirror image by reflecting the pixels
851 % around the central x-axis.
853 % The format of the FlipImage method is:
855 % Image *FlipImage(const Image *image,ExceptionInfo *exception)
857 % A description of each parameter follows:
859 % o image: the image.
861 % o exception: return any errors or warnings in this structure.
864 MagickExport Image *FlipImage(const Image *image,ExceptionInfo *exception)
866 #define FlipImageTag "Flip/Image"
882 assert(image != (const Image *) NULL);
883 assert(image->signature == MagickSignature);
884 if (image->debug != MagickFalse)
885 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
886 assert(exception != (ExceptionInfo *) NULL);
887 assert(exception->signature == MagickSignature);
888 flip_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
889 if (flip_image == (Image *) NULL)
890 return((Image *) NULL);
896 image_view=AcquireCacheView(image);
897 flip_view=AcquireCacheView(flip_image);
898 #if defined(MAGICKCORE_OPENMP_SUPPORT)
899 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
901 for (y=0; y < (long) flip_image->rows; y++)
903 register const IndexPacket
906 register const PixelPacket
910 *restrict flip_indexes;
915 if (status == MagickFalse)
917 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
918 q=QueueCacheViewAuthenticPixels(flip_view,0,(long) (flip_image->rows-y-1),
919 flip_image->columns,1,exception);
920 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
925 (void) CopyMagickMemory(q,p,(size_t) image->columns*sizeof(*q));
926 indexes=GetCacheViewVirtualIndexQueue(image_view);
927 if (indexes != (const IndexPacket *) NULL)
929 flip_indexes=GetCacheViewAuthenticIndexQueue(flip_view);
930 if (flip_indexes != (IndexPacket *) NULL)
931 (void) CopyMagickMemory(flip_indexes,indexes,(size_t) image->columns*
932 sizeof(*flip_indexes));
934 if (SyncCacheViewAuthenticPixels(flip_view,exception) == MagickFalse)
936 if (image->progress_monitor != (MagickProgressMonitor) NULL)
941 #if defined(MAGICKCORE_OPENMP_SUPPORT)
942 #pragma omp critical (MagickCore_FlipImage)
944 proceed=SetImageProgress(image,FlipImageTag,progress++,image->rows);
945 if (proceed == MagickFalse)
949 flip_view=DestroyCacheView(flip_view);
950 image_view=DestroyCacheView(image_view);
951 flip_image->type=image->type;
952 if (status == MagickFalse)
953 flip_image=DestroyImage(flip_image);
958 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
962 % F l o p I m a g e %
966 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
968 % FlopImage() creates a horizontal mirror image by reflecting the pixels
969 % around the central y-axis.
971 % The format of the FlopImage method is:
973 % Image *FlopImage(const Image *image,ExceptionInfo *exception)
975 % A description of each parameter follows:
977 % o image: the image.
979 % o exception: return any errors or warnings in this structure.
982 MagickExport Image *FlopImage(const Image *image,ExceptionInfo *exception)
984 #define FlopImageTag "Flop/Image"
1000 assert(image != (const Image *) NULL);
1001 assert(image->signature == MagickSignature);
1002 if (image->debug != MagickFalse)
1003 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1004 assert(exception != (ExceptionInfo *) NULL);
1005 assert(exception->signature == MagickSignature);
1006 flop_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
1007 if (flop_image == (Image *) NULL)
1008 return((Image *) NULL);
1014 image_view=AcquireCacheView(image);
1015 flop_view=AcquireCacheView(flop_image);
1016 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1017 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
1019 for (y=0; y < (long) flop_image->rows; y++)
1021 register const IndexPacket
1024 register const PixelPacket
1027 register IndexPacket
1028 *restrict flop_indexes;
1033 register PixelPacket
1036 if (status == MagickFalse)
1038 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1039 q=QueueCacheViewAuthenticPixels(flop_view,0,y,flop_image->columns,1,
1041 if ((p == (PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
1046 q+=flop_image->columns;
1047 indexes=GetCacheViewVirtualIndexQueue(image_view);
1048 flop_indexes=GetCacheViewAuthenticIndexQueue(flop_view);
1049 for (x=0; x < (long) flop_image->columns; x++)
1052 if ((indexes != (const IndexPacket *) NULL) &&
1053 (flop_indexes != (IndexPacket *) NULL))
1054 flop_indexes[flop_image->columns-x-1]=indexes[x];
1056 if (SyncCacheViewAuthenticPixels(flop_view,exception) == MagickFalse)
1058 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1063 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1064 #pragma omp critical (MagickCore_FlopImage)
1066 proceed=SetImageProgress(image,FlopImageTag,progress++,image->rows);
1067 if (proceed == MagickFalse)
1071 flop_view=DestroyCacheView(flop_view);
1072 image_view=DestroyCacheView(image_view);
1073 flop_image->type=image->type;
1074 if (status == MagickFalse)
1075 flop_image=DestroyImage(flop_image);
1080 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1084 % R o l l I m a g e %
1088 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1090 % RollImage() offsets an image as defined by x_offset and y_offset.
1092 % The format of the RollImage method is:
1094 % Image *RollImage(const Image *image,const long x_offset,
1095 % const long y_offset,ExceptionInfo *exception)
1097 % A description of each parameter follows:
1099 % o image: the image.
1101 % o x_offset: the number of columns to roll in the horizontal direction.
1103 % o y_offset: the number of rows to roll in the vertical direction.
1105 % o exception: return any errors or warnings in this structure.
1109 static inline MagickBooleanType CopyImageRegion(Image *destination,
1110 const Image *source,const unsigned long columns,const unsigned long rows,
1111 const long sx,const long sy,const long dx,const long dy,
1112 ExceptionInfo *exception)
1125 source_view=AcquireCacheView(source);
1126 destination_view=AcquireCacheView(destination);
1127 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1128 #pragma omp parallel for schedule(dynamic,4) shared(status)
1130 for (y=0; y < (long) rows; y++)
1135 register const PixelPacket
1138 register IndexPacket
1140 *restrict destination_indexes;
1145 register PixelPacket
1151 if (status == MagickFalse)
1153 p=GetCacheViewVirtualPixels(source_view,sx,sy+y,columns,1,exception);
1154 q=GetCacheViewAuthenticPixels(destination_view,dx,dy+y,columns,1,exception);
1155 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
1160 indexes=GetCacheViewAuthenticIndexQueue(source_view);
1161 for (x=0; x < (long) columns; x++)
1163 if (indexes != (IndexPacket *) NULL)
1165 destination_indexes=GetCacheViewAuthenticIndexQueue(destination_view);
1166 for (x=0; x < (long) columns; x++)
1167 destination_indexes[x]=indexes[x];
1169 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
1170 if (sync == MagickFalse)
1173 destination_view=DestroyCacheView(destination_view);
1174 source_view=DestroyCacheView(source_view);
1178 MagickExport Image *RollImage(const Image *image,const long x_offset,
1179 const long y_offset,ExceptionInfo *exception)
1181 #define RollImageTag "Roll/Image"
1193 Initialize roll image attributes.
1195 assert(image != (const Image *) NULL);
1196 assert(image->signature == MagickSignature);
1197 if (image->debug != MagickFalse)
1198 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1199 assert(exception != (ExceptionInfo *) NULL);
1200 assert(exception->signature == MagickSignature);
1201 roll_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
1202 if (roll_image == (Image *) NULL)
1203 return((Image *) NULL);
1206 while (offset.x < 0)
1207 offset.x+=image->columns;
1208 while (offset.x >= (long) image->columns)
1209 offset.x-=image->columns;
1210 while (offset.y < 0)
1211 offset.y+=image->rows;
1212 while (offset.y >= (long) image->rows)
1213 offset.y-=image->rows;
1217 status=CopyImageRegion(roll_image,image,(unsigned long) offset.x,
1218 (unsigned long) offset.y,(long) image->columns-offset.x,(long) image->rows-
1219 offset.y,0,0,exception);
1220 (void) SetImageProgress(image,RollImageTag,0,3);
1221 status|=CopyImageRegion(roll_image,image,image->columns-offset.x,
1222 (unsigned long) offset.y,0,(long) image->rows-offset.y,offset.x,0,
1224 (void) SetImageProgress(image,RollImageTag,1,3);
1225 status|=CopyImageRegion(roll_image,image,(unsigned long) offset.x,image->rows-
1226 offset.y,(long) image->columns-offset.x,0,0,offset.y,exception);
1227 (void) SetImageProgress(image,RollImageTag,2,3);
1228 status|=CopyImageRegion(roll_image,image,image->columns-offset.x,image->rows-
1229 offset.y,0,0,offset.x,offset.y,exception);
1230 (void) SetImageProgress(image,RollImageTag,3,3);
1231 roll_image->type=image->type;
1232 if (status == MagickFalse)
1233 roll_image=DestroyImage(roll_image);
1238 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1242 % S h a v e I m a g e %
1246 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1248 % ShaveImage() shaves pixels from the image edges. It allocates the memory
1249 % necessary for the new Image structure and returns a pointer to the new
1252 % The format of the ShaveImage method is:
1254 % Image *ShaveImage(const Image *image,const RectangleInfo *shave_info,
1255 % ExceptionInfo *exception)
1257 % A description of each parameter follows:
1259 % o shave_image: Method ShaveImage returns a pointer to the shaved
1260 % image. A null image is returned if there is a memory shortage or
1261 % if the image width or height is zero.
1263 % o image: the image.
1265 % o shave_info: Specifies a pointer to a RectangleInfo which defines the
1266 % region of the image to crop.
1268 % o exception: return any errors or warnings in this structure.
1271 MagickExport Image *ShaveImage(const Image *image,
1272 const RectangleInfo *shave_info,ExceptionInfo *exception)
1280 assert(image != (const Image *) NULL);
1281 assert(image->signature == MagickSignature);
1282 if (image->debug != MagickFalse)
1283 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1284 if (((2*shave_info->width) >= image->columns) ||
1285 ((2*shave_info->height) >= image->rows))
1286 ThrowImageException(OptionWarning,"GeometryDoesNotContainImage");
1287 SetGeometry(image,&geometry);
1288 geometry.width-=2*shave_info->width;
1289 geometry.height-=2*shave_info->height;
1290 geometry.x=(long) shave_info->width+image->page.x;
1291 geometry.y=(long) shave_info->height+image->page.y;
1292 shave_image=CropImage(image,&geometry,exception);
1293 if (shave_image == (Image *) NULL)
1294 return((Image *) NULL);
1295 shave_image->page.width-=2*shave_info->width;
1296 shave_image->page.height-=2*shave_info->height;
1297 shave_image->page.x-=shave_info->width;
1298 shave_image->page.y-=shave_info->height;
1299 return(shave_image);
1303 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1307 % S p l i c e I m a g e %
1311 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1313 % SpliceImage() splices a solid color into the image as defined by the
1316 % The format of the SpliceImage method is:
1318 % Image *SpliceImage(const Image *image,const RectangleInfo *geometry,
1319 % ExceptionInfo *exception)
1321 % A description of each parameter follows:
1323 % o image: the image.
1325 % o geometry: Define the region of the image to splice with members
1326 % x, y, width, and height.
1328 % o exception: return any errors or warnings in this structure.
1331 MagickExport Image *SpliceImage(const Image *image,
1332 const RectangleInfo *geometry,ExceptionInfo *exception)
1334 #define SpliceImageTag "Splice/Image"
1358 Allocate splice image.
1360 assert(image != (const Image *) NULL);
1361 assert(image->signature == MagickSignature);
1362 if (image->debug != MagickFalse)
1363 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1364 assert(geometry != (const RectangleInfo *) NULL);
1365 assert(exception != (ExceptionInfo *) NULL);
1366 assert(exception->signature == MagickSignature);
1367 splice_geometry=(*geometry);
1368 splice_image=CloneImage(image,image->columns+splice_geometry.width,
1369 image->rows+splice_geometry.height,MagickTrue,exception);
1370 if (splice_image == (Image *) NULL)
1371 return((Image *) NULL);
1372 if (SetImageStorageClass(splice_image,DirectClass) == MagickFalse)
1374 InheritException(exception,&splice_image->exception);
1375 splice_image=DestroyImage(splice_image);
1376 return((Image *) NULL);
1378 (void) SetImageBackgroundColor(splice_image);
1380 Respect image geometry.
1382 switch (image->gravity)
1385 case UndefinedGravity:
1386 case NorthWestGravity:
1390 splice_geometry.x+=splice_geometry.width/2;
1393 case NorthEastGravity:
1395 splice_geometry.x+=splice_geometry.width;
1400 splice_geometry.y+=splice_geometry.width/2;
1406 splice_geometry.x+=splice_geometry.width/2;
1407 splice_geometry.y+=splice_geometry.height/2;
1412 splice_geometry.x+=splice_geometry.width;
1413 splice_geometry.y+=splice_geometry.height/2;
1416 case SouthWestGravity:
1418 splice_geometry.y+=splice_geometry.height;
1423 splice_geometry.x+=splice_geometry.width/2;
1424 splice_geometry.y+=splice_geometry.height;
1427 case SouthEastGravity:
1429 splice_geometry.x+=splice_geometry.width;
1430 splice_geometry.y+=splice_geometry.height;
1440 image_view=AcquireCacheView(image);
1441 splice_view=AcquireCacheView(splice_image);
1442 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1443 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
1445 for (y=0; y < (long) splice_geometry.y; y++)
1447 register const PixelPacket
1450 register IndexPacket
1452 *restrict splice_indexes;
1457 register PixelPacket
1460 if (status == MagickFalse)
1462 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1463 q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1,
1465 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
1470 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1471 splice_indexes=GetCacheViewAuthenticIndexQueue(splice_view);
1472 for (x=0; x < splice_geometry.x; x++)
1474 SetRedPixelComponent(q,GetRedPixelComponent(p));
1475 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
1476 SetBluePixelComponent(q,GetBluePixelComponent(p));
1477 SetOpacityPixelComponent(q,OpaqueOpacity);
1478 if (image->matte != MagickFalse)
1479 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
1480 if (image->colorspace == CMYKColorspace)
1481 splice_indexes[x]=(*indexes++);
1485 for ( ; x < (long) (splice_geometry.x+splice_geometry.width); x++)
1487 for ( ; x < (long) splice_image->columns; x++)
1489 SetRedPixelComponent(q,GetRedPixelComponent(p));
1490 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
1491 SetBluePixelComponent(q,GetBluePixelComponent(p));
1492 SetOpacityPixelComponent(q,OpaqueOpacity);
1493 if (image->matte != MagickFalse)
1494 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
1495 if (image->colorspace == CMYKColorspace)
1496 splice_indexes[x]=(*indexes++);
1500 if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse)
1502 proceed=SetImageProgress(image,SpliceImageTag,y,splice_image->rows);
1503 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1508 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1509 #pragma omp critical (MagickCore_TransposeImage)
1511 proceed=SetImageProgress(image,SpliceImageTag,progress++,
1512 splice_image->rows);
1513 if (proceed == MagickFalse)
1517 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1518 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
1520 for (y=(long) (splice_geometry.y+splice_geometry.height);
1521 y < (long) splice_image->rows; y++)
1523 register const PixelPacket
1526 register IndexPacket
1528 *restrict splice_indexes;
1533 register PixelPacket
1536 if (status == MagickFalse)
1538 p=GetCacheViewVirtualPixels(image_view,0,y-splice_geometry.height,
1539 image->columns,1,exception);
1540 q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1,
1542 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
1547 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1548 splice_indexes=GetCacheViewAuthenticIndexQueue(splice_view);
1549 for (x=0; x < splice_geometry.x; x++)
1551 SetRedPixelComponent(q,GetRedPixelComponent(p));
1552 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
1553 SetBluePixelComponent(q,GetBluePixelComponent(p));
1554 SetOpacityPixelComponent(q,OpaqueOpacity);
1555 if (image->matte != MagickFalse)
1556 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
1557 if (image->colorspace == CMYKColorspace)
1558 splice_indexes[x]=(*indexes++);
1562 for ( ; x < (long) (splice_geometry.x+splice_geometry.width); x++)
1564 for ( ; x < (long) splice_image->columns; x++)
1566 SetRedPixelComponent(q,GetRedPixelComponent(p));
1567 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
1568 SetBluePixelComponent(q,GetBluePixelComponent(p));
1569 SetOpacityPixelComponent(q,OpaqueOpacity);
1570 if (image->matte != MagickFalse)
1571 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
1572 if (image->colorspace == CMYKColorspace)
1573 splice_indexes[x]=(*indexes++);
1577 if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse)
1579 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1584 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1585 #pragma omp critical (MagickCore_TransposeImage)
1587 proceed=SetImageProgress(image,SpliceImageTag,progress++,
1588 splice_image->rows);
1589 if (proceed == MagickFalse)
1593 splice_view=DestroyCacheView(splice_view);
1594 image_view=DestroyCacheView(image_view);
1595 if (status == MagickFalse)
1596 splice_image=DestroyImage(splice_image);
1597 return(splice_image);
1601 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1605 % T r a n s f o r m I m a g e %
1609 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1611 % TransformImage() is a convenience method that behaves like ResizeImage() or
1612 % CropImage() but accepts scaling and/or cropping information as a region
1613 % geometry specification. If the operation fails, the original image handle
1616 % The format of the TransformImage method is:
1618 % MagickBooleanType TransformImage(Image **image,const char *crop_geometry,
1619 % const char *image_geometry)
1621 % A description of each parameter follows:
1623 % o image: the image The transformed image is returned as this parameter.
1625 % o crop_geometry: A crop geometry string. This geometry defines a
1626 % subregion of the image to crop.
1628 % o image_geometry: An image geometry string. This geometry defines the
1629 % final size of the image.
1632 static inline long MagickRound(MagickRealType x)
1635 Round the fraction to nearest integer.
1638 return((long) (x+0.5));
1639 return((long) (x-0.5));
1642 MagickExport MagickBooleanType TransformImage(Image **image,
1643 const char *crop_geometry,const char *image_geometry)
1664 assert(image != (Image **) NULL);
1665 assert((*image)->signature == MagickSignature);
1666 if ((*image)->debug != MagickFalse)
1667 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
1668 transform_image=(*image);
1669 if (crop_geometry != (const char *) NULL)
1678 Crop image to a user specified size.
1680 crop_image=NewImageList();
1681 flags=ParseGravityGeometry(transform_image,crop_geometry,&geometry,
1682 &(*image)->exception);
1683 if ((flags & AreaValue) != 0)
1693 Crop into NxM tiles (@ flag) - AT.
1695 if (geometry.width == 0)
1697 if (geometry.height == 0)
1699 width=transform_image->columns;
1700 height=transform_image->rows;
1701 if ((flags & AspectValue) == 0)
1703 width-=(geometry.x < 0 ? -1 : 1)*geometry.x;
1704 height-=(geometry.y < 0 ? -1 : 1)*geometry.y;
1708 width+=(geometry.x < 0 ? -1 : 1)*geometry.x;
1709 height+=(geometry.y < 0 ? -1 : 1)*geometry.y;
1711 delta.x=(double) width/geometry.width;
1712 delta.y=(double) height/geometry.height;
1713 next=NewImageList();
1714 for (offset.y=0; offset.y < (double) height; )
1716 if ((flags & AspectValue) == 0)
1718 crop.y=(long) MagickRound((MagickRealType) (offset.y-
1719 (geometry.y > 0 ? 0 : geometry.y)));
1721 crop.height=(unsigned long) MagickRound((MagickRealType)
1722 (offset.y+(geometry.y < 0 ? 0 : geometry.y)));
1726 crop.y=(long) MagickRound((MagickRealType) (offset.y-
1727 (geometry.y > 0 ? geometry.y : 0)));
1729 crop.height=(unsigned long) MagickRound((MagickRealType)
1730 (offset.y+(geometry.y < 0 ? geometry.y : 0)));
1732 crop.height-=crop.y;
1733 for (offset.x=0; offset.x < (double) width; )
1735 if ((flags & AspectValue) == 0)
1737 crop.x=(long) MagickRound((MagickRealType) (offset.x-
1738 (geometry.x > 0 ? 0 : geometry.x)));
1740 crop.width=(unsigned long) MagickRound((MagickRealType)
1741 (offset.x+(geometry.x < 0 ? 0 : geometry.x)));
1745 crop.x=(long) MagickRound((MagickRealType) (offset.x-
1746 (geometry.x > 0 ? geometry.x : 0)));
1748 crop.width=(unsigned long) MagickRound((MagickRealType)
1749 (offset.x+(geometry.x < 0 ? geometry.x : 0)));
1752 next=CropImage(transform_image,&crop,&(*image)->exception);
1753 if (next == (Image *) NULL)
1755 AppendImageToList(&crop_image,next);
1757 if (next == (Image *) NULL)
1762 if (((geometry.width == 0) && (geometry.height == 0)) ||
1763 ((flags & XValue) != 0) || ((flags & YValue) != 0))
1766 Crop a single region at +X+Y.
1768 crop_image=CropImage(transform_image,&geometry,
1769 &(*image)->exception);
1770 if ((crop_image != (Image *) NULL) && ((flags & AspectValue) != 0))
1772 crop_image->page.width=geometry.width;
1773 crop_image->page.height=geometry.height;
1774 crop_image->page.x-=geometry.x;
1775 crop_image->page.y-=geometry.y;
1779 if ((transform_image->columns > geometry.width) ||
1780 (transform_image->rows > geometry.height))
1785 MagickProgressMonitor
1795 Crop into tiles of fixed size WxH.
1797 if (transform_image->page.width == 0)
1798 transform_image->page.width=transform_image->columns;
1799 if (transform_image->page.height == 0)
1800 transform_image->page.height=transform_image->rows;
1801 width=geometry.width;
1803 width=transform_image->page.width;
1804 height=geometry.height;
1806 height=transform_image->page.height;
1807 next=NewImageList();
1810 number_images=(MagickSizeType) transform_image->page.height*
1811 transform_image->page.width/height/width;
1812 for (y=0; y < (long) transform_image->page.height; y+=height)
1814 for (x=0; x < (long) transform_image->page.width; x+=width)
1816 progress_monitor=SetImageProgressMonitor(transform_image,
1817 (MagickProgressMonitor) NULL,transform_image->client_data);
1818 geometry.width=width;
1819 geometry.height=height;
1822 next=CropImage(transform_image,&geometry,&(*image)->exception);
1823 (void) SetImageProgressMonitor(transform_image,
1824 progress_monitor,transform_image->client_data);
1825 proceed=SetImageProgress(transform_image,CropImageTag,i++,
1827 if (proceed == MagickFalse)
1829 if (next == (Image *) NULL)
1831 (void) SetImageProgressMonitor(next,progress_monitor,
1833 AppendImageToList(&crop_image,next);
1835 if (next == (Image *) NULL)
1837 if (proceed == MagickFalse)
1841 if (crop_image == (Image *) NULL)
1842 transform_image=CloneImage(*image,0,0,MagickTrue,&(*image)->exception);
1845 transform_image=DestroyImage(transform_image);
1846 transform_image=GetFirstImageInList(crop_image);
1848 *image=transform_image;
1850 if (image_geometry == (const char *) NULL)
1853 Scale image to a user specified size.
1855 flags=ParseRegionGeometry(transform_image,image_geometry,&geometry,
1856 &(*image)->exception);
1857 if ((transform_image->columns == geometry.width) &&
1858 (transform_image->rows == geometry.height))
1860 resize_image=ZoomImage(transform_image,geometry.width,geometry.height,
1861 &(*image)->exception);
1862 if (resize_image == (Image *) NULL)
1863 return(MagickFalse);
1864 transform_image=DestroyImage(transform_image);
1865 transform_image=resize_image;
1866 *image=transform_image;
1871 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1875 % T r a n s f o r m I m a g e s %
1878 % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1880 % TransformImages() calls TransformImage() on each image of a sequence.
1882 % The format of the TransformImage method is:
1884 % MagickBooleanType TransformImages(Image **image,
1885 % const char *crop_geometry,const char *image_geometry)
1887 % A description of each parameter follows:
1889 % o image: the image The transformed image is returned as this parameter.
1891 % o crop_geometry: A crop geometry string. This geometry defines a
1892 % subregion of the image to crop.
1894 % o image_geometry: An image geometry string. This geometry defines the
1895 % final size of the image.
1898 MagickExport MagickBooleanType TransformImages(Image **images,
1899 const char *crop_geometry,const char *image_geometry)
1912 assert(images != (Image **) NULL);
1913 assert((*images)->signature == MagickSignature);
1914 if ((*images)->debug != MagickFalse)
1915 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1916 (*images)->filename);
1917 image_list=ImageListToArray(*images,&(*images)->exception);
1918 if (image_list == (Image **) NULL)
1919 return(MagickFalse);
1921 transform_images=NewImageList();
1922 for (i=0; image_list[i] != (Image *) NULL; i++)
1924 image=image_list[i];
1925 status|=TransformImage(&image,crop_geometry,image_geometry);
1926 AppendImageToList(&transform_images,image);
1928 *images=transform_images;
1929 image_list=(Image **) RelinquishMagickMemory(image_list);
1930 return(status != 0 ? MagickTrue : MagickFalse);
1934 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1938 % T r a n s p o s e I m a g e %
1942 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1944 % TransposeImage() creates a horizontal mirror image by reflecting the pixels
1945 % around the central y-axis while rotating them by 90 degrees.
1947 % The format of the TransposeImage method is:
1949 % Image *TransposeImage(const Image *image,ExceptionInfo *exception)
1951 % A description of each parameter follows:
1953 % o image: the image.
1955 % o exception: return any errors or warnings in this structure.
1958 MagickExport Image *TransposeImage(const Image *image,ExceptionInfo *exception)
1960 #define TransposeImageTag "Transpose/Image"
1979 assert(image != (const Image *) NULL);
1980 assert(image->signature == MagickSignature);
1981 if (image->debug != MagickFalse)
1982 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1983 assert(exception != (ExceptionInfo *) NULL);
1984 assert(exception->signature == MagickSignature);
1985 transpose_image=CloneImage(image,image->rows,image->columns,MagickTrue,
1987 if (transpose_image == (Image *) NULL)
1988 return((Image *) NULL);
1994 image_view=AcquireCacheView(image);
1995 transpose_view=AcquireCacheView(transpose_image);
1996 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1997 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
1999 for (y=0; y < (long) image->rows; y++)
2001 register const PixelPacket
2004 register IndexPacket
2005 *restrict transpose_indexes,
2008 register PixelPacket
2011 if (status == MagickFalse)
2013 p=GetCacheViewVirtualPixels(image_view,0,(long) image->rows-y-1,
2014 image->columns,1,exception);
2015 q=QueueCacheViewAuthenticPixels(transpose_view,(long) (image->rows-y-1),0,
2016 1,transpose_image->rows,exception);
2017 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
2022 (void) CopyMagickMemory(q,p,(size_t) image->columns*sizeof(*q));
2023 indexes=GetCacheViewAuthenticIndexQueue(image_view);
2024 if (indexes != (IndexPacket *) NULL)
2026 transpose_indexes=GetCacheViewAuthenticIndexQueue(transpose_view);
2027 if (transpose_indexes != (IndexPacket *) NULL)
2028 (void) CopyMagickMemory(transpose_indexes,indexes,(size_t)
2029 image->columns*sizeof(*transpose_indexes));
2031 if (SyncCacheViewAuthenticPixels(transpose_view,exception) == MagickFalse)
2033 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2038 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2039 #pragma omp critical (MagickCore_TransposeImage)
2041 proceed=SetImageProgress(image,TransposeImageTag,progress++,
2043 if (proceed == MagickFalse)
2047 transpose_view=DestroyCacheView(transpose_view);
2048 image_view=DestroyCacheView(image_view);
2049 transpose_image->type=image->type;
2050 page=transpose_image->page;
2051 Swap(page.width,page.height);
2052 Swap(page.x,page.y);
2053 if (page.width != 0)
2054 page.x=(long) (page.width-transpose_image->columns-page.x);
2055 transpose_image->page=page;
2056 if (status == MagickFalse)
2057 transpose_image=DestroyImage(transpose_image);
2058 return(transpose_image);
2062 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2066 % T r a n s v e r s e I m a g e %
2070 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2072 % TransverseImage() creates a vertical mirror image by reflecting the pixels
2073 % around the central x-axis while rotating them by 270 degrees.
2075 % The format of the TransverseImage method is:
2077 % Image *TransverseImage(const Image *image,ExceptionInfo *exception)
2079 % A description of each parameter follows:
2081 % o image: the image.
2083 % o exception: return any errors or warnings in this structure.
2086 MagickExport Image *TransverseImage(const Image *image,ExceptionInfo *exception)
2088 #define TransverseImageTag "Transverse/Image"
2107 assert(image != (const Image *) NULL);
2108 assert(image->signature == MagickSignature);
2109 if (image->debug != MagickFalse)
2110 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2111 assert(exception != (ExceptionInfo *) NULL);
2112 assert(exception->signature == MagickSignature);
2113 transverse_image=CloneImage(image,image->rows,image->columns,MagickTrue,
2115 if (transverse_image == (Image *) NULL)
2116 return((Image *) NULL);
2122 image_view=AcquireCacheView(image);
2123 transverse_view=AcquireCacheView(transverse_image);
2124 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2125 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
2127 for (y=0; y < (long) image->rows; y++)
2132 register const PixelPacket
2135 register IndexPacket
2136 *restrict transverse_indexes,
2142 register PixelPacket
2145 if (status == MagickFalse)
2147 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2148 q=QueueCacheViewAuthenticPixels(transverse_view,(long) (image->rows-y-
2149 1),0,1,transverse_image->rows,exception);
2150 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
2156 for (x=0; x < (long) image->columns; x++)
2158 indexes=GetCacheViewAuthenticIndexQueue(image_view);
2159 if (indexes != (IndexPacket *) NULL)
2161 transverse_indexes=GetCacheViewAuthenticIndexQueue(transverse_view);
2162 if (transverse_indexes != (IndexPacket *) NULL)
2163 for (x=0; x < (long) image->columns; x++)
2164 transverse_indexes[image->columns-x-1]=indexes[x];
2166 sync=SyncCacheViewAuthenticPixels(transverse_view,exception);
2167 if (sync == MagickFalse)
2169 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2174 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2175 #pragma omp critical (MagickCore_TransverseImage)
2177 proceed=SetImageProgress(image,TransverseImageTag,progress++,
2179 if (proceed == MagickFalse)
2183 transverse_view=DestroyCacheView(transverse_view);
2184 image_view=DestroyCacheView(image_view);
2185 transverse_image->type=image->type;
2186 page=transverse_image->page;
2187 Swap(page.width,page.height);
2188 Swap(page.x,page.y);
2189 if (page.height != 0)
2190 page.y=(long) (page.height-transverse_image->rows-page.y);
2191 transverse_image->page=page;
2192 if (status == MagickFalse)
2193 transverse_image=DestroyImage(transverse_image);
2194 return(transverse_image);
2198 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2202 % T r i m I m a g e %
2206 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2208 % TrimImage() trims pixels from the image edges. It allocates the memory
2209 % necessary for the new Image structure and returns a pointer to the new
2212 % The format of the TrimImage method is:
2214 % Image *TrimImage(const Image *image,ExceptionInfo *exception)
2216 % A description of each parameter follows:
2218 % o image: the image.
2220 % o exception: return any errors or warnings in this structure.
2223 MagickExport Image *TrimImage(const Image *image,ExceptionInfo *exception)
2228 assert(image != (const Image *) NULL);
2229 assert(image->signature == MagickSignature);
2230 if (image->debug != MagickFalse)
2231 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2232 geometry=GetImageBoundingBox(image,exception);
2233 if ((geometry.width == 0) || (geometry.height == 0))
2238 crop_image=CloneImage(image,1,1,MagickTrue,exception);
2239 if (crop_image == (Image *) NULL)
2240 return((Image *) NULL);
2241 crop_image->background_color.opacity=(Quantum) TransparentOpacity;
2242 (void) SetImageBackgroundColor(crop_image);
2243 crop_image->page=image->page;
2244 crop_image->page.x=(-1);
2245 crop_image->page.y=(-1);
2248 geometry.x+=image->page.x;
2249 geometry.y+=image->page.y;
2250 return(CropImage(image,&geometry,exception));