2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % TTTTT RRRR AAA N N SSSSS FFFFF OOO RRRR M M %
7 % T R R A A NN N SS F O O R R MM MM %
8 % T RRRR AAAAA N N N SSS FFF O O RRRR M M M %
9 % T R R A A N NN SS F O O R R M M %
10 % T R R A A N N SSSSS F OOO R R M M %
13 % MagickCore Image Transform Methods %
20 % Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
42 #include "MagickCore/studio.h"
43 #include "MagickCore/attribute.h"
44 #include "MagickCore/cache.h"
45 #include "MagickCore/cache-view.h"
46 #include "MagickCore/color.h"
47 #include "MagickCore/color-private.h"
48 #include "MagickCore/colorspace-private.h"
49 #include "MagickCore/composite.h"
50 #include "MagickCore/draw.h"
51 #include "MagickCore/effect.h"
52 #include "MagickCore/exception.h"
53 #include "MagickCore/exception-private.h"
54 #include "MagickCore/geometry.h"
55 #include "MagickCore/image.h"
56 #include "MagickCore/memory_.h"
57 #include "MagickCore/layer.h"
58 #include "MagickCore/list.h"
59 #include "MagickCore/monitor.h"
60 #include "MagickCore/monitor-private.h"
61 #include "MagickCore/pixel-accessor.h"
62 #include "MagickCore/resource_.h"
63 #include "MagickCore/resize.h"
64 #include "MagickCore/statistic.h"
65 #include "MagickCore/string_.h"
66 #include "MagickCore/thread-private.h"
67 #include "MagickCore/transform.h"
70 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
78 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
80 % ChopImage() removes a region of an image and collapses the image to occupy
81 % the removed portion.
83 % The format of the ChopImage method is:
85 % Image *ChopImage(const Image *image,const RectangleInfo *chop_info)
86 % ExceptionInfo *exception)
88 % A description of each parameter follows:
92 % o chop_info: Define the region of the image to chop.
94 % o exception: return any errors or warnings in this structure.
97 MagickExport Image *ChopImage(const Image *image,const RectangleInfo *chop_info,
98 ExceptionInfo *exception)
100 #define ChopImageTag "Chop/Image"
124 assert(image != (const Image *) NULL);
125 assert(image->signature == MagickSignature);
126 if (image->debug != MagickFalse)
127 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
128 assert(exception != (ExceptionInfo *) NULL);
129 assert(exception->signature == MagickSignature);
130 assert(chop_info != (RectangleInfo *) NULL);
131 if (((chop_info->x+(ssize_t) chop_info->width) < 0) ||
132 ((chop_info->y+(ssize_t) chop_info->height) < 0) ||
133 (chop_info->x > (ssize_t) image->columns) ||
134 (chop_info->y > (ssize_t) image->rows))
135 ThrowImageException(OptionWarning,"GeometryDoesNotContainImage");
137 if ((extent.x+(ssize_t) extent.width) > (ssize_t) image->columns)
138 extent.width=(size_t) ((ssize_t) image->columns-extent.x);
139 if ((extent.y+(ssize_t) extent.height) > (ssize_t) image->rows)
140 extent.height=(size_t) ((ssize_t) image->rows-extent.y);
143 extent.width-=(size_t) (-extent.x);
148 extent.height-=(size_t) (-extent.y);
151 chop_image=CloneImage(image,image->columns-extent.width,image->rows-
152 extent.height,MagickTrue,exception);
153 if (chop_image == (Image *) NULL)
154 return((Image *) NULL);
160 image_view=AcquireCacheView(image);
161 chop_view=AcquireCacheView(chop_image);
162 #if defined(MAGICKCORE_OPENMP_SUPPORT)
163 #pragma omp parallel for schedule(dynamic,4) shared(progress,status) omp_throttle(1)
165 for (y=0; y < (ssize_t) extent.y; y++)
167 register const Quantum
176 if (status == MagickFalse)
178 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
179 q=QueueCacheViewAuthenticPixels(chop_view,0,y,chop_image->columns,1,
181 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
186 for (x=0; x < (ssize_t) image->columns; x++)
188 if ((x < extent.x) || (x >= (ssize_t) (extent.x+extent.width)))
190 SetPixelRed(chop_image,GetPixelRed(image,p),q);
191 SetPixelGreen(chop_image,GetPixelGreen(image,p),q);
192 SetPixelBlue(chop_image,GetPixelBlue(image,p),q);
193 if (image->colorspace == CMYKColorspace)
194 SetPixelBlack(chop_image,GetPixelBlack(image,p),q);
195 q+=GetPixelChannels(chop_image);
197 p+=GetPixelChannels(image);
199 if (SyncCacheViewAuthenticPixels(chop_view,exception) == MagickFalse)
201 if (image->progress_monitor != (MagickProgressMonitor) NULL)
206 #if defined(MAGICKCORE_OPENMP_SUPPORT)
207 #pragma omp critical (MagickCore_ChopImage)
209 proceed=SetImageProgress(image,ChopImageTag,progress++,image->rows);
210 if (proceed == MagickFalse)
217 #if defined(MAGICKCORE_OPENMP_SUPPORT)
218 #pragma omp parallel for schedule(dynamic,4) shared(progress,status) omp_throttle(1)
220 for (y=0; y < (ssize_t) (image->rows-(extent.y+extent.height)); y++)
222 register const Quantum
231 if (status == MagickFalse)
233 p=GetCacheViewVirtualPixels(image_view,0,extent.y+extent.height+y,
234 image->columns,1,exception);
235 q=QueueCacheViewAuthenticPixels(chop_view,0,extent.y+y,chop_image->columns,
237 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
242 for (x=0; x < (ssize_t) image->columns; x++)
244 if ((x < extent.x) || (x >= (ssize_t) (extent.x+extent.width)))
246 SetPixelRed(chop_image,GetPixelRed(image,p),q);
247 SetPixelGreen(chop_image,GetPixelGreen(image,p),q);
248 SetPixelBlue(chop_image,GetPixelBlue(image,p),q);
249 p+=GetPixelChannels(image);
250 q+=GetPixelChannels(chop_image);
252 p+=GetPixelChannels(image);
254 if (SyncCacheViewAuthenticPixels(chop_view,exception) == MagickFalse)
256 if (image->progress_monitor != (MagickProgressMonitor) NULL)
261 #if defined(MAGICKCORE_OPENMP_SUPPORT)
262 #pragma omp critical (MagickCore_ChopImage)
264 proceed=SetImageProgress(image,ChopImageTag,progress++,image->rows);
265 if (proceed == MagickFalse)
269 chop_view=DestroyCacheView(chop_view);
270 image_view=DestroyCacheView(image_view);
271 chop_image->type=image->type;
276 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
280 + C o n s o l i d a t e C M Y K I m a g e %
284 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
286 % ConsolidateCMYKImage() consolidates separate C, M, Y, and K planes into a
289 % The format of the ConsolidateCMYKImage method is:
291 % Image *ConsolidateCMYKImage(const Image *image,ExceptionInfo *exception)
293 % A description of each parameter follows:
295 % o image: the image sequence.
297 % o exception: return any errors or warnings in this structure.
300 MagickExport Image *ConsolidateCMYKImages(const Image *images,
301 ExceptionInfo *exception)
318 Consolidate separate C, M, Y, and K planes into a single image.
320 assert(images != (Image *) NULL);
321 assert(images->signature == MagickSignature);
322 if (images->debug != MagickFalse)
323 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
324 assert(exception != (ExceptionInfo *) NULL);
325 assert(exception->signature == MagickSignature);
326 cmyk_images=NewImageList();
327 for (i=0; i < (ssize_t) GetImageListLength(images); i+=4)
329 cmyk_image=CloneImage(images,images->columns,images->rows,MagickTrue,
331 if (cmyk_image == (Image *) NULL)
333 if (SetImageStorageClass(cmyk_image,DirectClass,exception) == MagickFalse)
335 (void) SetImageColorspace(cmyk_image,CMYKColorspace,exception);
336 image_view=AcquireCacheView(images);
337 cmyk_view=AcquireCacheView(cmyk_image);
338 for (y=0; y < (ssize_t) images->rows; y++)
340 register const Quantum
349 p=GetCacheViewVirtualPixels(image_view,0,y,images->columns,1,exception);
350 q=QueueCacheViewAuthenticPixels(cmyk_view,0,y,cmyk_image->columns,1,
352 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
354 for (x=0; x < (ssize_t) images->columns; x++)
356 SetPixelRed(cmyk_image,QuantumRange-GetPixelIntensity(images,p),q);
357 p+=GetPixelChannels(images);
358 q+=GetPixelChannels(cmyk_image);
360 if (SyncCacheViewAuthenticPixels(cmyk_view,exception) == MagickFalse)
363 cmyk_view=DestroyCacheView(cmyk_view);
364 image_view=DestroyCacheView(image_view);
365 images=GetNextImageInList(images);
366 if (images == (Image *) NULL)
368 image_view=AcquireCacheView(images);
369 cmyk_view=AcquireCacheView(cmyk_image);
370 for (y=0; y < (ssize_t) images->rows; y++)
372 register const Quantum
381 p=GetCacheViewVirtualPixels(image_view,0,y,images->columns,1,exception);
382 q=GetCacheViewAuthenticPixels(cmyk_view,0,y,cmyk_image->columns,1,
384 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
386 for (x=0; x < (ssize_t) images->columns; x++)
388 SetPixelGreen(cmyk_image,QuantumRange-GetPixelIntensity(images,p),q);
389 p+=GetPixelChannels(images);
390 q+=GetPixelChannels(cmyk_image);
392 if (SyncCacheViewAuthenticPixels(cmyk_view,exception) == MagickFalse)
395 cmyk_view=DestroyCacheView(cmyk_view);
396 image_view=DestroyCacheView(image_view);
397 images=GetNextImageInList(images);
398 if (images == (Image *) NULL)
400 image_view=AcquireCacheView(images);
401 cmyk_view=AcquireCacheView(cmyk_image);
402 for (y=0; y < (ssize_t) images->rows; y++)
404 register const Quantum
413 p=GetCacheViewVirtualPixels(image_view,0,y,images->columns,1,exception);
414 q=GetCacheViewAuthenticPixels(cmyk_view,0,y,cmyk_image->columns,1,
416 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
418 for (x=0; x < (ssize_t) images->columns; x++)
420 SetPixelBlue(cmyk_image,QuantumRange-GetPixelIntensity(images,p),q);
421 p+=GetPixelChannels(images);
422 q+=GetPixelChannels(cmyk_image);
424 if (SyncCacheViewAuthenticPixels(cmyk_view,exception) == MagickFalse)
427 cmyk_view=DestroyCacheView(cmyk_view);
428 image_view=DestroyCacheView(image_view);
429 images=GetNextImageInList(images);
430 if (images == (Image *) NULL)
432 image_view=AcquireCacheView(images);
433 cmyk_view=AcquireCacheView(cmyk_image);
434 for (y=0; y < (ssize_t) images->rows; y++)
436 register const Quantum
445 p=GetCacheViewVirtualPixels(image_view,0,y,images->columns,1,exception);
446 q=GetCacheViewAuthenticPixels(cmyk_view,0,y,cmyk_image->columns,1,
448 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
450 for (x=0; x < (ssize_t) images->columns; x++)
452 SetPixelBlack(cmyk_image,QuantumRange-GetPixelIntensity(images,p),q);
453 p+=GetPixelChannels(images);
454 q+=GetPixelChannels(cmyk_image);
456 if (SyncCacheViewAuthenticPixels(cmyk_view,exception) == MagickFalse)
459 cmyk_view=DestroyCacheView(cmyk_view);
460 image_view=DestroyCacheView(image_view);
461 AppendImageToList(&cmyk_images,cmyk_image);
462 images=GetNextImageInList(images);
463 if (images == (Image *) NULL)
470 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
474 % C r o p I m a g e %
478 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
480 % CropImage() extracts a region of the image starting at the offset defined
481 % by geometry. Region must be fully defined, and no special handling of
482 % geometry flags is performed.
484 % The format of the CropImage method is:
486 % Image *CropImage(const Image *image,const RectangleInfo *geometry,
487 % ExceptionInfo *exception)
489 % A description of each parameter follows:
491 % o image: the image.
493 % o geometry: Define the region of the image to crop with members
494 % x, y, width, and height.
496 % o exception: return any errors or warnings in this structure.
499 MagickExport Image *CropImage(const Image *image,const RectangleInfo *geometry,
500 ExceptionInfo *exception)
502 #define CropImageTag "Crop/Image"
527 assert(image != (const Image *) NULL);
528 assert(image->signature == MagickSignature);
529 if (image->debug != MagickFalse)
530 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
531 assert(geometry != (const RectangleInfo *) NULL);
532 assert(exception != (ExceptionInfo *) NULL);
533 assert(exception->signature == MagickSignature);
534 bounding_box=image->page;
535 if ((bounding_box.width == 0) || (bounding_box.height == 0))
537 bounding_box.width=image->columns;
538 bounding_box.height=image->rows;
542 page.width=bounding_box.width;
543 if (page.height == 0)
544 page.height=bounding_box.height;
545 if (((bounding_box.x-page.x) >= (ssize_t) page.width) ||
546 ((bounding_box.y-page.y) >= (ssize_t) page.height) ||
547 ((page.x-bounding_box.x) > (ssize_t) image->columns) ||
548 ((page.y-bounding_box.y) > (ssize_t) image->rows))
551 Crop is not within virtual canvas, return 1 pixel transparent image.
553 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
554 "GeometryDoesNotContainImage","`%s'",image->filename);
555 crop_image=CloneImage(image,1,1,MagickTrue,exception);
556 if (crop_image == (Image *) NULL)
557 return((Image *) NULL);
558 crop_image->background_color.alpha=(Quantum) TransparentAlpha;
559 (void) SetImageBackgroundColor(crop_image);
560 crop_image->page=bounding_box;
561 crop_image->page.x=(-1);
562 crop_image->page.y=(-1);
563 if (crop_image->dispose == BackgroundDispose)
564 crop_image->dispose=NoneDispose;
567 if ((page.x < 0) && (bounding_box.x >= 0))
569 page.width+=page.x-bounding_box.x;
574 page.width-=bounding_box.x-page.x;
575 page.x-=bounding_box.x;
579 if ((page.y < 0) && (bounding_box.y >= 0))
581 page.height+=page.y-bounding_box.y;
586 page.height-=bounding_box.y-page.y;
587 page.y-=bounding_box.y;
591 if ((size_t) (page.x+page.width) > image->columns)
592 page.width=image->columns-page.x;
593 if ((geometry->width != 0) && (page.width > geometry->width))
594 page.width=geometry->width;
595 if ((size_t) (page.y+page.height) > image->rows)
596 page.height=image->rows-page.y;
597 if ((geometry->height != 0) && (page.height > geometry->height))
598 page.height=geometry->height;
599 bounding_box.x+=page.x;
600 bounding_box.y+=page.y;
601 if ((page.width == 0) || (page.height == 0))
603 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
604 "GeometryDoesNotContainImage","`%s'",image->filename);
605 return((Image *) NULL);
608 Initialize crop image attributes.
610 crop_image=CloneImage(image,page.width,page.height,MagickTrue,exception);
611 if (crop_image == (Image *) NULL)
612 return((Image *) NULL);
613 crop_image->page.width=image->page.width;
614 crop_image->page.height=image->page.height;
615 if (((ssize_t) (bounding_box.x+bounding_box.width) > (ssize_t) image->page.width) ||
616 ((ssize_t) (bounding_box.y+bounding_box.height) > (ssize_t) image->page.height))
618 crop_image->page.width=bounding_box.width;
619 crop_image->page.height=bounding_box.height;
621 crop_image->page.x=bounding_box.x;
622 crop_image->page.y=bounding_box.y;
628 image_view=AcquireCacheView(image);
629 crop_view=AcquireCacheView(crop_image);
630 #if defined(MAGICKCORE_OPENMP_SUPPORT)
631 #pragma omp parallel for schedule(dynamic,4) shared(progress,status) omp_throttle(1)
633 for (y=0; y < (ssize_t) crop_image->rows; y++)
635 register const Quantum
644 if (status == MagickFalse)
646 p=GetCacheViewVirtualPixels(image_view,page.x,page.y+y,crop_image->columns,
648 q=QueueCacheViewAuthenticPixels(crop_view,0,y,crop_image->columns,1,
650 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
655 for (x=0; x < (ssize_t) crop_image->columns; x++)
657 SetPixelRed(crop_image,GetPixelRed(image,p),q);
658 SetPixelGreen(crop_image,GetPixelGreen(image,p),q);
659 SetPixelBlue(crop_image,GetPixelBlue(image,p),q);
660 if (image->colorspace == CMYKColorspace)
661 SetPixelBlack(crop_image,GetPixelBlack(image,p),q);
662 SetPixelAlpha(crop_image,GetPixelAlpha(image,p),q);
663 if (image->storage_class == PseudoClass)
664 SetPixelIndex(crop_image,GetPixelIndex(image,p),q);
665 p+=GetPixelChannels(image);
666 q+=GetPixelChannels(crop_image);
668 if (SyncCacheViewAuthenticPixels(crop_view,exception) == MagickFalse)
670 if (image->progress_monitor != (MagickProgressMonitor) NULL)
675 #if defined(MAGICKCORE_OPENMP_SUPPORT)
676 #pragma omp critical (MagickCore_CropImage)
678 proceed=SetImageProgress(image,CropImageTag,progress++,image->rows);
679 if (proceed == MagickFalse)
683 crop_view=DestroyCacheView(crop_view);
684 image_view=DestroyCacheView(image_view);
685 crop_image->type=image->type;
686 if (status == MagickFalse)
687 crop_image=DestroyImage(crop_image);
692 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
696 % C r o p I m a g e T o T i l e s %
700 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
702 % CropImageToTiles() will crop a single image, into a possible list of tiles.
703 % This may include a single sub-region of the image. This basically applies
704 % all the normal geometry flags for Crop.
706 % Image *CropImageToTiles(const Image *image,const RectangleInfo
707 % *crop_geometry, ExceptionInfo *exception)
709 % A description of each parameter follows:
711 % o image: the image The transformed image is returned as this parameter.
713 % o crop_geometry: A crop geometry string.
715 % o exception: return any errors or warnings in this structure.
719 static inline ssize_t MagickRound(MagickRealType x)
722 Round the fraction to nearest integer.
725 return((ssize_t) (x+0.5));
726 return((ssize_t) (x-0.5));
729 MagickExport Image *CropImageToTiles(const Image *image,
730 const char *crop_geometry, ExceptionInfo *exception)
742 assert(image != (Image *) NULL);
743 assert(image->signature == MagickSignature);
744 if (image->debug != MagickFalse)
745 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
746 crop_image=NewImageList();
748 flags=ParseGravityGeometry(image,crop_geometry,&geometry,exception);
749 if ((flags & AreaValue) != 0)
763 Crop into NxM tiles (@ flag).
765 width=image->columns;
767 if (geometry.width == 0)
769 if (geometry.height == 0)
771 if ((flags & AspectValue) == 0)
773 width-=(geometry.x < 0 ? -1 : 1)*geometry.x;
774 height-=(geometry.y < 0 ? -1 : 1)*geometry.y;
778 width+=(geometry.x < 0 ? -1 : 1)*geometry.x;
779 height+=(geometry.y < 0 ? -1 : 1)*geometry.y;
781 delta.x=(double) width/geometry.width;
782 delta.y=(double) height/geometry.height;
783 for (offset.y=0; offset.y < (double) height; )
785 if ((flags & AspectValue) == 0)
787 crop.y=(ssize_t) MagickRound((MagickRealType) (offset.y-
788 (geometry.y > 0 ? 0 : geometry.y)));
789 offset.y+=delta.y; /* increment now to find width */
790 crop.height=(size_t) MagickRound((MagickRealType) (offset.y+
791 (geometry.y < 0 ? 0 : geometry.y)));
795 crop.y=(ssize_t) MagickRound((MagickRealType) (offset.y-
796 (geometry.y > 0 ? geometry.y : 0)));
797 offset.y+=delta.y; /* increment now to find width */
798 crop.height=(size_t) MagickRound((MagickRealType)
799 (offset.y+(geometry.y < -1 ? geometry.y : 0)));
802 crop.y+=image->page.y;
803 for (offset.x=0; offset.x < (double) width; )
805 if ((flags & AspectValue) == 0)
807 crop.x=(ssize_t) MagickRound((MagickRealType) (offset.x-
808 (geometry.x > 0 ? 0 : geometry.x)));
809 offset.x+=delta.x; /* increment now to find height */
810 crop.width=(size_t) MagickRound((MagickRealType) (offset.x+
811 (geometry.x < 0 ? 0 : geometry.x)));
815 crop.x=(ssize_t) MagickRound((MagickRealType) (offset.x-
816 (geometry.x > 0 ? geometry.x : 0)));
817 offset.x+=delta.x; /* increment now to find height */
818 crop.width=(size_t) MagickRound((MagickRealType) (offset.x+
819 (geometry.x < 0 ? geometry.x : 0)));
822 crop.x+=image->page.x;
823 next=CropImage(image,&crop,exception);
824 if (next == (Image *) NULL)
826 AppendImageToList(&crop_image,next);
828 if (next == (Image *) NULL)
831 ClearMagickException(exception);
835 if (((geometry.width == 0) && (geometry.height == 0)) ||
836 ((flags & XValue) != 0) || ((flags & YValue) != 0))
839 Crop a single region at +X+Y.
841 crop_image=CropImage(image,&geometry,exception);
842 if ((crop_image != (Image *) NULL) && ((flags & AspectValue) != 0))
844 crop_image->page.width=geometry.width;
845 crop_image->page.height=geometry.height;
846 crop_image->page.x-=geometry.x;
847 crop_image->page.y-=geometry.y;
851 if ((image->columns > geometry.width) || (image->rows > geometry.height))
865 Crop into tiles of fixed size WxH.
869 page.width=image->columns;
870 if (page.height == 0)
871 page.height=image->rows;
872 width=geometry.width;
875 height=geometry.height;
879 for (y=0; y < (ssize_t) page.height; y+=(ssize_t) height)
881 for (x=0; x < (ssize_t) page.width; x+=(ssize_t) width)
883 geometry.width=width;
884 geometry.height=height;
887 next=CropImage(image,&geometry,exception);
888 if (next == (Image *) NULL)
890 AppendImageToList(&crop_image,next);
892 if (next == (Image *) NULL)
897 return(CloneImage(image,0,0,MagickTrue,exception));
901 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
905 % E x c e r p t I m a g e %
909 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
911 % ExcerptImage() returns a excerpt of the image as defined by the geometry.
913 % The format of the ExcerptImage method is:
915 % Image *ExcerptImage(const Image *image,const RectangleInfo *geometry,
916 % ExceptionInfo *exception)
918 % A description of each parameter follows:
920 % o image: the image.
922 % o geometry: Define the region of the image to extend with members
923 % x, y, width, and height.
925 % o exception: return any errors or warnings in this structure.
928 MagickExport Image *ExcerptImage(const Image *image,
929 const RectangleInfo *geometry,ExceptionInfo *exception)
931 #define ExcerptImageTag "Excerpt/Image"
950 Allocate excerpt image.
952 assert(image != (const Image *) NULL);
953 assert(image->signature == MagickSignature);
954 if (image->debug != MagickFalse)
955 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
956 assert(geometry != (const RectangleInfo *) NULL);
957 assert(exception != (ExceptionInfo *) NULL);
958 assert(exception->signature == MagickSignature);
959 excerpt_image=CloneImage(image,geometry->width,geometry->height,MagickTrue,
961 if (excerpt_image == (Image *) NULL)
962 return((Image *) NULL);
968 image_view=AcquireCacheView(image);
969 excerpt_view=AcquireCacheView(excerpt_image);
970 #if defined(MAGICKCORE_OPENMP_SUPPORT)
971 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
973 for (y=0; y < (ssize_t) excerpt_image->rows; y++)
975 register const Quantum
984 if (status == MagickFalse)
986 p=GetCacheViewVirtualPixels(image_view,geometry->x,geometry->y+y,
987 geometry->width,1,exception);
988 q=GetCacheViewAuthenticPixels(excerpt_view,0,y,excerpt_image->columns,1,
990 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
995 for (x=0; x < (ssize_t) excerpt_image->columns; x++)
997 SetPixelRed(excerpt_image,GetPixelRed(image,p),q);
998 SetPixelGreen(excerpt_image,GetPixelGreen(image,p),q);
999 SetPixelBlue(excerpt_image,GetPixelBlue(image,p),q);
1000 if (image->colorspace == CMYKColorspace)
1001 SetPixelBlack(excerpt_image,GetPixelBlack(image,p),q);
1002 if (image->storage_class == PseudoClass)
1003 SetPixelIndex(excerpt_image,GetPixelIndex(image,p),q);
1004 SetPixelAlpha(excerpt_image,GetPixelAlpha(image,p),q);
1005 p+=GetPixelChannels(image);
1006 q+=GetPixelChannels(excerpt_image);
1008 if (SyncCacheViewAuthenticPixels(excerpt_view,exception) == MagickFalse)
1010 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1015 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1016 #pragma omp critical (MagickCore_ExcerptImage)
1018 proceed=SetImageProgress(image,ExcerptImageTag,progress++,image->rows);
1019 if (proceed == MagickFalse)
1023 excerpt_view=DestroyCacheView(excerpt_view);
1024 image_view=DestroyCacheView(image_view);
1025 excerpt_image->type=image->type;
1026 if (status == MagickFalse)
1027 excerpt_image=DestroyImage(excerpt_image);
1028 return(excerpt_image);
1032 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1036 % E x t e n t I m a g e %
1040 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1042 % ExtentImage() extends the image as defined by the geometry, gravity, and
1043 % image background color. Set the (x,y) offset of the geometry to move the
1044 % original image relative to the extended image.
1046 % The format of the ExtentImage method is:
1048 % Image *ExtentImage(const Image *image,const RectangleInfo *geometry,
1049 % ExceptionInfo *exception)
1051 % A description of each parameter follows:
1053 % o image: the image.
1055 % o geometry: Define the region of the image to extend with members
1056 % x, y, width, and height.
1058 % o exception: return any errors or warnings in this structure.
1061 MagickExport Image *ExtentImage(const Image *image,
1062 const RectangleInfo *geometry,ExceptionInfo *exception)
1068 Allocate extent image.
1070 assert(image != (const Image *) NULL);
1071 assert(image->signature == MagickSignature);
1072 if (image->debug != MagickFalse)
1073 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1074 assert(geometry != (const RectangleInfo *) NULL);
1075 assert(exception != (ExceptionInfo *) NULL);
1076 assert(exception->signature == MagickSignature);
1077 extent_image=CloneImage(image,geometry->width,geometry->height,MagickTrue,
1079 if (extent_image == (Image *) NULL)
1080 return((Image *) NULL);
1081 if (SetImageStorageClass(extent_image,DirectClass,exception) == MagickFalse)
1083 extent_image=DestroyImage(extent_image);
1084 return((Image *) NULL);
1086 if (extent_image->background_color.alpha != OpaqueAlpha)
1087 extent_image->matte=MagickTrue;
1088 (void) SetImageBackgroundColor(extent_image);
1089 (void) CompositeImage(extent_image,image->compose,image,-geometry->x,
1091 return(extent_image);
1095 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1099 % F l i p I m a g e %
1103 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1105 % FlipImage() creates a vertical mirror image by reflecting the pixels
1106 % around the central x-axis.
1108 % The format of the FlipImage method is:
1110 % Image *FlipImage(const Image *image,ExceptionInfo *exception)
1112 % A description of each parameter follows:
1114 % o image: the image.
1116 % o exception: return any errors or warnings in this structure.
1119 MagickExport Image *FlipImage(const Image *image,ExceptionInfo *exception)
1121 #define FlipImageTag "Flip/Image"
1142 assert(image != (const Image *) NULL);
1143 assert(image->signature == MagickSignature);
1144 if (image->debug != MagickFalse)
1145 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1146 assert(exception != (ExceptionInfo *) NULL);
1147 assert(exception->signature == MagickSignature);
1148 flip_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
1149 if (flip_image == (Image *) NULL)
1150 return((Image *) NULL);
1157 image_view=AcquireCacheView(image);
1158 flip_view=AcquireCacheView(flip_image);
1159 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1160 #pragma omp parallel for schedule(dynamic,4) shared(progress,status) omp_throttle(1)
1162 for (y=0; y < (ssize_t) flip_image->rows; y++)
1164 register const Quantum
1173 if (status == MagickFalse)
1175 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1176 q=QueueCacheViewAuthenticPixels(flip_view,0,(ssize_t) (flip_image->rows-y-
1177 1),flip_image->columns,1,exception);
1178 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1183 for (x=0; x < (ssize_t) flip_image->columns; x++)
1185 SetPixelRed(flip_image,GetPixelRed(image,p),q);
1186 SetPixelGreen(flip_image,GetPixelGreen(image,p),q);
1187 SetPixelBlue(flip_image,GetPixelBlue(image,p),q);
1188 if (image->colorspace == CMYKColorspace)
1189 SetPixelBlack(flip_image,GetPixelBlack(image,p),q);
1190 if (image->storage_class == PseudoClass)
1191 SetPixelIndex(flip_image,GetPixelIndex(image,p),q);
1192 SetPixelAlpha(flip_image,GetPixelAlpha(image,p),q);
1193 p+=GetPixelChannels(image);
1194 q+=GetPixelChannels(flip_image);
1196 if (SyncCacheViewAuthenticPixels(flip_view,exception) == MagickFalse)
1198 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1203 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1204 #pragma omp critical (MagickCore_FlipImage)
1206 proceed=SetImageProgress(image,FlipImageTag,progress++,image->rows);
1207 if (proceed == MagickFalse)
1211 flip_view=DestroyCacheView(flip_view);
1212 image_view=DestroyCacheView(image_view);
1213 flip_image->type=image->type;
1214 if (page.height != 0)
1215 page.y=(ssize_t) (page.height-flip_image->rows-page.y);
1216 flip_image->page=page;
1217 if (status == MagickFalse)
1218 flip_image=DestroyImage(flip_image);
1223 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1227 % F l o p I m a g e %
1231 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1233 % FlopImage() creates a horizontal mirror image by reflecting the pixels
1234 % around the central y-axis.
1236 % The format of the FlopImage method is:
1238 % Image *FlopImage(const Image *image,ExceptionInfo *exception)
1240 % A description of each parameter follows:
1242 % o image: the image.
1244 % o exception: return any errors or warnings in this structure.
1247 MagickExport Image *FlopImage(const Image *image,ExceptionInfo *exception)
1249 #define FlopImageTag "Flop/Image"
1270 assert(image != (const Image *) NULL);
1271 assert(image->signature == MagickSignature);
1272 if (image->debug != MagickFalse)
1273 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1274 assert(exception != (ExceptionInfo *) NULL);
1275 assert(exception->signature == MagickSignature);
1276 flop_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
1277 if (flop_image == (Image *) NULL)
1278 return((Image *) NULL);
1285 image_view=AcquireCacheView(image);
1286 flop_view=AcquireCacheView(flop_image);
1287 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1288 #pragma omp parallel for schedule(dynamic,4) shared(progress,status) omp_throttle(1)
1290 for (y=0; y < (ssize_t) flop_image->rows; y++)
1292 register const Quantum
1301 if (status == MagickFalse)
1303 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1304 q=QueueCacheViewAuthenticPixels(flop_view,0,y,flop_image->columns,1,
1306 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1311 q+=GetPixelChannels(flop_image)*flop_image->columns;
1312 for (x=0; x < (ssize_t) flop_image->columns; x++)
1314 q-=GetPixelChannels(flop_image);
1315 SetPixelRed(flop_image,GetPixelRed(image,p),q);
1316 SetPixelGreen(flop_image,GetPixelGreen(image,p),q);
1317 SetPixelBlue(flop_image,GetPixelBlue(image,p),q);
1318 if (image->colorspace == CMYKColorspace)
1319 SetPixelBlack(flop_image,GetPixelBlack(image,p),q);
1320 SetPixelAlpha(flop_image,GetPixelAlpha(image,p),q);
1321 if (image->storage_class == PseudoClass)
1322 SetPixelIndex(flop_image,GetPixelIndex(image,p),q);
1323 p+=GetPixelChannels(image);
1325 if (SyncCacheViewAuthenticPixels(flop_view,exception) == MagickFalse)
1327 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1332 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1333 #pragma omp critical (MagickCore_FlopImage)
1335 proceed=SetImageProgress(image,FlopImageTag,progress++,image->rows);
1336 if (proceed == MagickFalse)
1340 flop_view=DestroyCacheView(flop_view);
1341 image_view=DestroyCacheView(image_view);
1342 flop_image->type=image->type;
1343 if (page.width != 0)
1344 page.x=(ssize_t) (page.width-flop_image->columns-page.x);
1345 flop_image->page=page;
1346 if (status == MagickFalse)
1347 flop_image=DestroyImage(flop_image);
1352 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1356 % R o l l I m a g e %
1360 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1362 % RollImage() offsets an image as defined by x_offset and y_offset.
1364 % The format of the RollImage method is:
1366 % Image *RollImage(const Image *image,const ssize_t x_offset,
1367 % const ssize_t y_offset,ExceptionInfo *exception)
1369 % A description of each parameter follows:
1371 % o image: the image.
1373 % o x_offset: the number of columns to roll in the horizontal direction.
1375 % o y_offset: the number of rows to roll in the vertical direction.
1377 % o exception: return any errors or warnings in this structure.
1381 static inline MagickBooleanType CopyImageRegion(Image *destination,
1382 const Image *source,const size_t columns,const size_t rows,
1383 const ssize_t sx,const ssize_t sy,const ssize_t dx,const ssize_t dy,
1384 ExceptionInfo *exception)
1397 source_view=AcquireCacheView(source);
1398 destination_view=AcquireCacheView(destination);
1399 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1400 #pragma omp parallel for schedule(dynamic,4) shared(status)
1402 for (y=0; y < (ssize_t) rows; y++)
1407 register const Quantum
1419 if (status == MagickFalse)
1421 p=GetCacheViewVirtualPixels(source_view,sx,sy+y,columns,1,exception);
1422 q=GetCacheViewAuthenticPixels(destination_view,dx,dy+y,columns,1,exception);
1423 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1428 for (x=0; x < (ssize_t) columns; x++)
1430 SetPixelRed(destination,GetPixelRed(source,p),q);
1431 SetPixelGreen(destination,GetPixelGreen(source,p),q);
1432 SetPixelBlue(destination,GetPixelBlue(source,p),q);
1433 if (destination->colorspace == CMYKColorspace)
1434 SetPixelBlack(destination,GetPixelBlack(source,p),q);
1435 SetPixelAlpha(destination,GetPixelAlpha(source,p),q);
1436 p+=GetPixelChannels(source);
1437 q+=GetPixelChannels(destination);
1439 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
1440 if (sync == MagickFalse)
1443 destination_view=DestroyCacheView(destination_view);
1444 source_view=DestroyCacheView(source_view);
1448 MagickExport Image *RollImage(const Image *image,const ssize_t x_offset,
1449 const ssize_t y_offset,ExceptionInfo *exception)
1451 #define RollImageTag "Roll/Image"
1463 Initialize roll image attributes.
1465 assert(image != (const Image *) NULL);
1466 assert(image->signature == MagickSignature);
1467 if (image->debug != MagickFalse)
1468 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1469 assert(exception != (ExceptionInfo *) NULL);
1470 assert(exception->signature == MagickSignature);
1471 roll_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
1472 if (roll_image == (Image *) NULL)
1473 return((Image *) NULL);
1476 while (offset.x < 0)
1477 offset.x+=(ssize_t) image->columns;
1478 while (offset.x >= (ssize_t) image->columns)
1479 offset.x-=(ssize_t) image->columns;
1480 while (offset.y < 0)
1481 offset.y+=(ssize_t) image->rows;
1482 while (offset.y >= (ssize_t) image->rows)
1483 offset.y-=(ssize_t) image->rows;
1487 status=CopyImageRegion(roll_image,image,(size_t) offset.x,
1488 (size_t) offset.y,(ssize_t) image->columns-offset.x,(ssize_t) image->rows-
1489 offset.y,0,0,exception);
1490 (void) SetImageProgress(image,RollImageTag,0,3);
1491 status|=CopyImageRegion(roll_image,image,image->columns-offset.x,
1492 (size_t) offset.y,0,(ssize_t) image->rows-offset.y,offset.x,0,
1494 (void) SetImageProgress(image,RollImageTag,1,3);
1495 status|=CopyImageRegion(roll_image,image,(size_t) offset.x,image->rows-
1496 offset.y,(ssize_t) image->columns-offset.x,0,0,offset.y,exception);
1497 (void) SetImageProgress(image,RollImageTag,2,3);
1498 status|=CopyImageRegion(roll_image,image,image->columns-offset.x,image->rows-
1499 offset.y,0,0,offset.x,offset.y,exception);
1500 (void) SetImageProgress(image,RollImageTag,3,3);
1501 roll_image->type=image->type;
1502 if (status == MagickFalse)
1503 roll_image=DestroyImage(roll_image);
1508 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1512 % S h a v e I m a g e %
1516 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1518 % ShaveImage() shaves pixels from the image edges. It allocates the memory
1519 % necessary for the new Image structure and returns a pointer to the new
1522 % The format of the ShaveImage method is:
1524 % Image *ShaveImage(const Image *image,const RectangleInfo *shave_info,
1525 % ExceptionInfo *exception)
1527 % A description of each parameter follows:
1529 % o shave_image: Method ShaveImage returns a pointer to the shaved
1530 % image. A null image is returned if there is a memory shortage or
1531 % if the image width or height is zero.
1533 % o image: the image.
1535 % o shave_info: Specifies a pointer to a RectangleInfo which defines the
1536 % region of the image to crop.
1538 % o exception: return any errors or warnings in this structure.
1541 MagickExport Image *ShaveImage(const Image *image,
1542 const RectangleInfo *shave_info,ExceptionInfo *exception)
1550 assert(image != (const Image *) NULL);
1551 assert(image->signature == MagickSignature);
1552 if (image->debug != MagickFalse)
1553 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1554 if (((2*shave_info->width) >= image->columns) ||
1555 ((2*shave_info->height) >= image->rows))
1556 ThrowImageException(OptionWarning,"GeometryDoesNotContainImage");
1557 SetGeometry(image,&geometry);
1558 geometry.width-=2*shave_info->width;
1559 geometry.height-=2*shave_info->height;
1560 geometry.x=(ssize_t) shave_info->width+image->page.x;
1561 geometry.y=(ssize_t) shave_info->height+image->page.y;
1562 shave_image=CropImage(image,&geometry,exception);
1563 if (shave_image == (Image *) NULL)
1564 return((Image *) NULL);
1565 shave_image->page.width-=2*shave_info->width;
1566 shave_image->page.height-=2*shave_info->height;
1567 shave_image->page.x-=(ssize_t) shave_info->width;
1568 shave_image->page.y-=(ssize_t) shave_info->height;
1569 return(shave_image);
1573 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1577 % S p l i c e I m a g e %
1581 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1583 % SpliceImage() splices a solid color into the image as defined by the
1586 % The format of the SpliceImage method is:
1588 % Image *SpliceImage(const Image *image,const RectangleInfo *geometry,
1589 % ExceptionInfo *exception)
1591 % A description of each parameter follows:
1593 % o image: the image.
1595 % o geometry: Define the region of the image to splice with members
1596 % x, y, width, and height.
1598 % o exception: return any errors or warnings in this structure.
1601 MagickExport Image *SpliceImage(const Image *image,
1602 const RectangleInfo *geometry,ExceptionInfo *exception)
1604 #define SpliceImageTag "Splice/Image"
1626 Allocate splice image.
1628 assert(image != (const Image *) NULL);
1629 assert(image->signature == MagickSignature);
1630 if (image->debug != MagickFalse)
1631 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1632 assert(geometry != (const RectangleInfo *) NULL);
1633 assert(exception != (ExceptionInfo *) NULL);
1634 assert(exception->signature == MagickSignature);
1635 splice_geometry=(*geometry);
1636 splice_image=CloneImage(image,image->columns+splice_geometry.width,
1637 image->rows+splice_geometry.height,MagickTrue,exception);
1638 if (splice_image == (Image *) NULL)
1639 return((Image *) NULL);
1640 if (SetImageStorageClass(splice_image,DirectClass,exception) == MagickFalse)
1642 splice_image=DestroyImage(splice_image);
1643 return((Image *) NULL);
1645 (void) SetImageBackgroundColor(splice_image);
1647 Respect image geometry.
1649 switch (image->gravity)
1652 case UndefinedGravity:
1653 case NorthWestGravity:
1657 splice_geometry.x+=(ssize_t) splice_geometry.width/2;
1660 case NorthEastGravity:
1662 splice_geometry.x+=(ssize_t) splice_geometry.width;
1667 splice_geometry.y+=(ssize_t) splice_geometry.width/2;
1673 splice_geometry.x+=(ssize_t) splice_geometry.width/2;
1674 splice_geometry.y+=(ssize_t) splice_geometry.height/2;
1679 splice_geometry.x+=(ssize_t) splice_geometry.width;
1680 splice_geometry.y+=(ssize_t) splice_geometry.height/2;
1683 case SouthWestGravity:
1685 splice_geometry.y+=(ssize_t) splice_geometry.height;
1690 splice_geometry.x+=(ssize_t) splice_geometry.width/2;
1691 splice_geometry.y+=(ssize_t) splice_geometry.height;
1694 case SouthEastGravity:
1696 splice_geometry.x+=(ssize_t) splice_geometry.width;
1697 splice_geometry.y+=(ssize_t) splice_geometry.height;
1706 image_view=AcquireCacheView(image);
1707 splice_view=AcquireCacheView(splice_image);
1708 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1709 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
1711 for (y=0; y < (ssize_t) splice_geometry.y; y++)
1713 register const Quantum
1722 if (status == MagickFalse)
1724 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1725 q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1,
1727 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1732 for (x=0; x < splice_geometry.x; x++)
1734 SetPixelRed(splice_image,GetPixelRed(image,p),q);
1735 SetPixelGreen(splice_image,GetPixelGreen(image,p),q);
1736 SetPixelBlue(splice_image,GetPixelBlue(image,p),q);
1737 if (image->colorspace == CMYKColorspace)
1738 SetPixelBlack(splice_image,GetPixelBlack(image,p),q);
1739 SetPixelAlpha(splice_image,OpaqueAlpha,q);
1740 if (image->matte != MagickFalse)
1741 SetPixelAlpha(splice_image,GetPixelAlpha(image,p),q);
1742 p+=GetPixelChannels(image);
1743 q+=GetPixelChannels(splice_image);
1745 for ( ; x < (ssize_t) (splice_geometry.x+splice_geometry.width); x++)
1746 q+=GetPixelChannels(splice_image);
1747 for ( ; x < (ssize_t) splice_image->columns; x++)
1749 SetPixelRed(splice_image,GetPixelRed(image,p),q);
1750 SetPixelGreen(splice_image,GetPixelGreen(image,p),q);
1751 SetPixelBlue(splice_image,GetPixelBlue(image,p),q);
1752 if (image->colorspace == CMYKColorspace)
1753 SetPixelBlack(splice_image,GetPixelBlack(image,p),q);
1754 SetPixelAlpha(splice_image,OpaqueAlpha,q);
1755 if (image->matte != MagickFalse)
1756 SetPixelAlpha(splice_image,GetPixelAlpha(image,p),q);
1757 p+=GetPixelChannels(image);
1758 q+=GetPixelChannels(splice_image);
1760 if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse)
1762 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1767 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1768 #pragma omp critical (MagickCore_TransposeImage)
1770 proceed=SetImageProgress(image,SpliceImageTag,progress++,
1771 splice_image->rows);
1772 if (proceed == MagickFalse)
1776 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1777 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
1779 for (y=(ssize_t) (splice_geometry.y+splice_geometry.height);
1780 y < (ssize_t) splice_image->rows; y++)
1782 register const Quantum
1791 if (status == MagickFalse)
1793 p=GetCacheViewVirtualPixels(image_view,0,y-(ssize_t) splice_geometry.height,
1794 image->columns,1,exception);
1795 if ((y < 0) || (y >= (ssize_t) splice_image->rows))
1797 q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1,
1799 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1804 for (x=0; x < splice_geometry.x; x++)
1806 SetPixelRed(splice_image,GetPixelRed(image,p),q);
1807 SetPixelGreen(splice_image,GetPixelGreen(image,p),q);
1808 SetPixelBlue(splice_image,GetPixelBlue(image,p),q);
1809 SetPixelAlpha(splice_image,OpaqueAlpha,q);
1810 if (image->colorspace == CMYKColorspace)
1811 SetPixelBlack(splice_image,GetPixelBlack(image,p),q);
1812 if (image->matte != MagickFalse)
1813 SetPixelAlpha(splice_image,GetPixelAlpha(image,p),q);
1814 p+=GetPixelChannels(image);
1815 q+=GetPixelChannels(splice_image);
1817 for ( ; x < (ssize_t) (splice_geometry.x+splice_geometry.width); x++)
1818 q+=GetPixelChannels(splice_image);
1819 for ( ; x < (ssize_t) splice_image->columns; x++)
1821 SetPixelRed(splice_image,GetPixelRed(image,p),q);
1822 SetPixelGreen(splice_image,GetPixelGreen(image,p),q);
1823 SetPixelBlue(splice_image,GetPixelBlue(image,p),q);
1824 SetPixelAlpha(splice_image,OpaqueAlpha,q);
1825 if (image->colorspace == CMYKColorspace)
1826 SetPixelBlack(splice_image,GetPixelBlack(image,p),q);
1827 if (image->matte != MagickFalse)
1828 SetPixelAlpha(splice_image,GetPixelAlpha(image,p),q);
1829 p+=GetPixelChannels(image);
1830 q+=GetPixelChannels(splice_image);
1832 if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse)
1834 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1839 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1840 #pragma omp critical (MagickCore_TransposeImage)
1842 proceed=SetImageProgress(image,SpliceImageTag,progress++,
1843 splice_image->rows);
1844 if (proceed == MagickFalse)
1848 splice_view=DestroyCacheView(splice_view);
1849 image_view=DestroyCacheView(image_view);
1850 if (status == MagickFalse)
1851 splice_image=DestroyImage(splice_image);
1852 return(splice_image);
1856 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1860 % T r a n s f o r m I m a g e %
1864 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1866 % TransformImage() is a convenience method that behaves like ResizeImage() or
1867 % CropImage() but accepts scaling and/or cropping information as a region
1868 % geometry specification. If the operation fails, the original image handle
1871 % This should only be used for single images.
1873 % The format of the TransformImage method is:
1875 % MagickBooleanType TransformImage(Image **image,const char *crop_geometry,
1876 % const char *image_geometry)
1878 % A description of each parameter follows:
1880 % o image: the image The transformed image is returned as this parameter.
1882 % o crop_geometry: A crop geometry string. This geometry defines a
1883 % subregion of the image to crop.
1885 % o image_geometry: An image geometry string. This geometry defines the
1886 % final size of the image.
1890 DANGER: This function destroys what it assumes to be a single image list.
1891 If the input image is part of a larger list, all other images in that list
1892 will be simply 'lost', not destroyed.
1894 Also if the crop generates a list of images only the first image is resized.
1895 And finally if the crop succeeds and the resize failed, you will get a
1896 cropped image, as well as a 'false' or 'failed' report.
1898 This function and should probably be depreciated in favor of direct calls
1899 to CropImageToTiles() or ResizeImage(), as appropriate.
1902 MagickExport MagickBooleanType TransformImage(Image **image,
1903 const char *crop_geometry,const char *image_geometry)
1915 assert(image != (Image **) NULL);
1916 assert((*image)->signature == MagickSignature);
1917 if ((*image)->debug != MagickFalse)
1918 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
1919 transform_image=(*image);
1920 if (crop_geometry != (const char *) NULL)
1926 Crop image to a user specified size.
1928 crop_image=CropImageToTiles(*image,crop_geometry,&(*image)->exception);
1929 if (crop_image == (Image *) NULL)
1930 transform_image=CloneImage(*image,0,0,MagickTrue,&(*image)->exception);
1933 transform_image=DestroyImage(transform_image);
1934 transform_image=GetFirstImageInList(crop_image);
1936 *image=transform_image;
1938 if (image_geometry == (const char *) NULL)
1942 Scale image to a user specified size.
1944 flags=ParseRegionGeometry(transform_image,image_geometry,&geometry,
1945 &(*image)->exception);
1947 if ((transform_image->columns == geometry.width) &&
1948 (transform_image->rows == geometry.height))
1950 resize_image=ResizeImage(transform_image,geometry.width,geometry.height,
1951 transform_image->filter,transform_image->blur,&(*image)->exception);
1952 if (resize_image == (Image *) NULL)
1953 return(MagickFalse);
1954 transform_image=DestroyImage(transform_image);
1955 transform_image=resize_image;
1956 *image=transform_image;
1961 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1965 % T r a n s f o r m I m a g e s %
1969 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1971 % TransformImages() calls TransformImage() on each image of a sequence.
1973 % The format of the TransformImage method is:
1975 % MagickBooleanType TransformImages(Image **image,
1976 % const char *crop_geometry,const char *image_geometry)
1978 % A description of each parameter follows:
1980 % o image: the image The transformed image is returned as this parameter.
1982 % o crop_geometry: A crop geometry string. This geometry defines a
1983 % subregion of the image to crop.
1985 % o image_geometry: An image geometry string. This geometry defines the
1986 % final size of the image.
1989 MagickExport MagickBooleanType TransformImages(Image **images,
1990 const char *crop_geometry,const char *image_geometry)
2003 assert(images != (Image **) NULL);
2004 assert((*images)->signature == MagickSignature);
2005 if ((*images)->debug != MagickFalse)
2006 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2007 (*images)->filename);
2008 image_list=ImageListToArray(*images,&(*images)->exception);
2009 if (image_list == (Image **) NULL)
2010 return(MagickFalse);
2012 transform_images=NewImageList();
2013 for (i=0; image_list[i] != (Image *) NULL; i++)
2015 image=image_list[i];
2016 status|=TransformImage(&image,crop_geometry,image_geometry);
2017 AppendImageToList(&transform_images,image);
2019 *images=transform_images;
2020 image_list=(Image **) RelinquishMagickMemory(image_list);
2021 return(status != 0 ? MagickTrue : MagickFalse);
2025 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2029 % T r a n s p o s e I m a g e %
2033 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2035 % TransposeImage() creates a horizontal mirror image by reflecting the pixels
2036 % around the central y-axis while rotating them by 90 degrees.
2038 % The format of the TransposeImage method is:
2040 % Image *TransposeImage(const Image *image,ExceptionInfo *exception)
2042 % A description of each parameter follows:
2044 % o image: the image.
2046 % o exception: return any errors or warnings in this structure.
2049 MagickExport Image *TransposeImage(const Image *image,ExceptionInfo *exception)
2051 #define TransposeImageTag "Transpose/Image"
2072 assert(image != (const Image *) NULL);
2073 assert(image->signature == MagickSignature);
2074 if (image->debug != MagickFalse)
2075 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2076 assert(exception != (ExceptionInfo *) NULL);
2077 assert(exception->signature == MagickSignature);
2078 transpose_image=CloneImage(image,image->rows,image->columns,MagickTrue,
2080 if (transpose_image == (Image *) NULL)
2081 return((Image *) NULL);
2087 image_view=AcquireCacheView(image);
2088 transpose_view=AcquireCacheView(transpose_image);
2089 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2090 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
2092 for (y=0; y < (ssize_t) image->rows; y++)
2094 register const Quantum
2103 if (status == MagickFalse)
2105 p=GetCacheViewVirtualPixels(image_view,0,(ssize_t) image->rows-y-1,
2106 image->columns,1,exception);
2107 q=QueueCacheViewAuthenticPixels(transpose_view,(ssize_t) (image->rows-y-1),
2108 0,1,transpose_image->rows,exception);
2109 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2114 for (x=0; x < (ssize_t) image->columns; x++)
2116 SetPixelRed(transpose_image,GetPixelRed(image,p),q);
2117 SetPixelGreen(transpose_image,GetPixelGreen(image,p),q);
2118 SetPixelBlue(transpose_image,GetPixelBlue(image,p),q);
2119 if (image->colorspace == CMYKColorspace)
2120 SetPixelBlack(transpose_image,GetPixelBlack(image,p),q);
2121 SetPixelAlpha(transpose_image,GetPixelAlpha(image,p),q);
2122 p+=GetPixelChannels(image);
2123 q+=GetPixelChannels(transpose_image);
2125 if (SyncCacheViewAuthenticPixels(transpose_view,exception) == MagickFalse)
2127 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2132 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2133 #pragma omp critical (MagickCore_TransposeImage)
2135 proceed=SetImageProgress(image,TransposeImageTag,progress++,
2137 if (proceed == MagickFalse)
2141 transpose_view=DestroyCacheView(transpose_view);
2142 image_view=DestroyCacheView(image_view);
2143 transpose_image->type=image->type;
2144 page=transpose_image->page;
2145 Swap(page.width,page.height);
2146 Swap(page.x,page.y);
2147 transpose_image->page=page;
2148 if (status == MagickFalse)
2149 transpose_image=DestroyImage(transpose_image);
2150 return(transpose_image);
2154 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2158 % T r a n s v e r s e I m a g e %
2162 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2164 % TransverseImage() creates a vertical mirror image by reflecting the pixels
2165 % around the central x-axis while rotating them by 270 degrees.
2167 % The format of the TransverseImage method is:
2169 % Image *TransverseImage(const Image *image,ExceptionInfo *exception)
2171 % A description of each parameter follows:
2173 % o image: the image.
2175 % o exception: return any errors or warnings in this structure.
2178 MagickExport Image *TransverseImage(const Image *image,ExceptionInfo *exception)
2180 #define TransverseImageTag "Transverse/Image"
2201 assert(image != (const Image *) NULL);
2202 assert(image->signature == MagickSignature);
2203 if (image->debug != MagickFalse)
2204 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2205 assert(exception != (ExceptionInfo *) NULL);
2206 assert(exception->signature == MagickSignature);
2207 transverse_image=CloneImage(image,image->rows,image->columns,MagickTrue,
2209 if (transverse_image == (Image *) NULL)
2210 return((Image *) NULL);
2216 image_view=AcquireCacheView(image);
2217 transverse_view=AcquireCacheView(transverse_image);
2218 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2219 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
2221 for (y=0; y < (ssize_t) image->rows; y++)
2226 register const Quantum
2235 if (status == MagickFalse)
2237 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2238 q=QueueCacheViewAuthenticPixels(transverse_view,(ssize_t) (image->rows-y-
2239 1),0,1,transverse_image->rows,exception);
2240 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2245 q+=GetPixelChannels(transverse_image)*image->columns;
2246 for (x=0; x < (ssize_t) image->columns; x++)
2248 q-=GetPixelChannels(transverse_image);
2249 SetPixelRed(transverse_image,GetPixelRed(image,p),q);
2250 SetPixelGreen(transverse_image,GetPixelGreen(image,p),q);
2251 SetPixelBlue(transverse_image,GetPixelBlue(image,p),q);
2252 SetPixelAlpha(transverse_image,GetPixelAlpha(image,p),q);
2253 if (image->colorspace == CMYKColorspace)
2254 SetPixelBlack(transverse_image,GetPixelBlack(image,p),q);
2255 p+=GetPixelChannels(image);
2257 sync=SyncCacheViewAuthenticPixels(transverse_view,exception);
2258 if (sync == MagickFalse)
2260 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2265 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2266 #pragma omp critical (MagickCore_TransverseImage)
2268 proceed=SetImageProgress(image,TransverseImageTag,progress++,
2270 if (proceed == MagickFalse)
2274 transverse_view=DestroyCacheView(transverse_view);
2275 image_view=DestroyCacheView(image_view);
2276 transverse_image->type=image->type;
2277 page=transverse_image->page;
2278 Swap(page.width,page.height);
2279 Swap(page.x,page.y);
2280 if (page.width != 0)
2281 page.x=(ssize_t) (page.width-transverse_image->columns-page.x);
2282 if (page.height != 0)
2283 page.y=(ssize_t) (page.height-transverse_image->rows-page.y);
2284 transverse_image->page=page;
2285 if (status == MagickFalse)
2286 transverse_image=DestroyImage(transverse_image);
2287 return(transverse_image);
2291 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2295 % T r i m I m a g e %
2299 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2301 % TrimImage() trims pixels from the image edges. It allocates the memory
2302 % necessary for the new Image structure and returns a pointer to the new
2305 % The format of the TrimImage method is:
2307 % Image *TrimImage(const Image *image,ExceptionInfo *exception)
2309 % A description of each parameter follows:
2311 % o image: the image.
2313 % o exception: return any errors or warnings in this structure.
2316 MagickExport Image *TrimImage(const Image *image,ExceptionInfo *exception)
2321 assert(image != (const Image *) NULL);
2322 assert(image->signature == MagickSignature);
2323 if (image->debug != MagickFalse)
2324 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2325 geometry=GetImageBoundingBox(image,exception);
2326 if ((geometry.width == 0) || (geometry.height == 0))
2331 crop_image=CloneImage(image,1,1,MagickTrue,exception);
2332 if (crop_image == (Image *) NULL)
2333 return((Image *) NULL);
2334 crop_image->background_color.alpha=(Quantum) TransparentAlpha;
2335 (void) SetImageBackgroundColor(crop_image);
2336 crop_image->page=image->page;
2337 crop_image->page.x=(-1);
2338 crop_image->page.y=(-1);
2341 geometry.x+=image->page.x;
2342 geometry.y+=image->page.y;
2343 return(CropImage(image,&geometry,exception));