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-2012 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=AcquireVirtualCacheView(image,exception);
161 chop_view=AcquireAuthenticCacheView(chop_image,exception);
162 #if defined(MAGICKCORE_OPENMP_SUPPORT)
163 #pragma omp parallel for schedule(static) shared(progress,status) \
164 dynamic_number_threads(image,image->columns,image->rows,1)
166 for (y=0; y < (ssize_t) extent.y; y++)
168 register const Quantum
177 if (status == MagickFalse)
179 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
180 q=QueueCacheViewAuthenticPixels(chop_view,0,y,chop_image->columns,1,
182 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
187 for (x=0; x < (ssize_t) image->columns; x++)
189 if ((x < extent.x) || (x >= (ssize_t) (extent.x+extent.width)))
194 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
203 channel=GetPixelChannelMapChannel(image,i);
204 traits=GetPixelChannelMapTraits(image,channel);
205 chop_traits=GetPixelChannelMapTraits(chop_image,channel);
206 if ((traits == UndefinedPixelTrait) ||
207 (chop_traits == UndefinedPixelTrait))
209 SetPixelChannel(chop_image,channel,p[i],q);
211 q+=GetPixelChannels(chop_image);
213 p+=GetPixelChannels(image);
215 if (SyncCacheViewAuthenticPixels(chop_view,exception) == MagickFalse)
217 if (image->progress_monitor != (MagickProgressMonitor) NULL)
222 #if defined(MAGICKCORE_OPENMP_SUPPORT)
223 #pragma omp critical (MagickCore_ChopImage)
225 proceed=SetImageProgress(image,ChopImageTag,progress++,image->rows);
226 if (proceed == MagickFalse)
233 #if defined(MAGICKCORE_OPENMP_SUPPORT)
234 #pragma omp parallel for schedule(static) shared(progress,status) \
235 dynamic_number_threads(image,image->columns,image->rows,1)
237 for (y=0; y < (ssize_t) (image->rows-(extent.y+extent.height)); y++)
239 register const Quantum
248 if (status == MagickFalse)
250 p=GetCacheViewVirtualPixels(image_view,0,extent.y+extent.height+y,
251 image->columns,1,exception);
252 q=QueueCacheViewAuthenticPixels(chop_view,0,extent.y+y,chop_image->columns,
254 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
259 for (x=0; x < (ssize_t) image->columns; x++)
261 if ((x < extent.x) || (x >= (ssize_t) (extent.x+extent.width)))
266 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
275 channel=GetPixelChannelMapChannel(image,i);
276 traits=GetPixelChannelMapTraits(image,channel);
277 chop_traits=GetPixelChannelMapTraits(chop_image,channel);
278 if ((traits == UndefinedPixelTrait) ||
279 (chop_traits == UndefinedPixelTrait))
281 SetPixelChannel(chop_image,channel,p[i],q);
283 q+=GetPixelChannels(chop_image);
285 p+=GetPixelChannels(image);
287 if (SyncCacheViewAuthenticPixels(chop_view,exception) == MagickFalse)
289 if (image->progress_monitor != (MagickProgressMonitor) NULL)
294 #if defined(MAGICKCORE_OPENMP_SUPPORT)
295 #pragma omp critical (MagickCore_ChopImage)
297 proceed=SetImageProgress(image,ChopImageTag,progress++,image->rows);
298 if (proceed == MagickFalse)
302 chop_view=DestroyCacheView(chop_view);
303 image_view=DestroyCacheView(image_view);
304 chop_image->type=image->type;
309 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
313 + C o n s o l i d a t e C M Y K I m a g e %
317 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
319 % ConsolidateCMYKImage() consolidates separate C, M, Y, and K planes into a
322 % The format of the ConsolidateCMYKImage method is:
324 % Image *ConsolidateCMYKImage(const Image *image,ExceptionInfo *exception)
326 % A description of each parameter follows:
328 % o image: the image sequence.
330 % o exception: return any errors or warnings in this structure.
333 MagickExport Image *ConsolidateCMYKImages(const Image *images,
334 ExceptionInfo *exception)
351 Consolidate separate C, M, Y, and K planes into a single image.
353 assert(images != (Image *) NULL);
354 assert(images->signature == MagickSignature);
355 if (images->debug != MagickFalse)
356 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
357 assert(exception != (ExceptionInfo *) NULL);
358 assert(exception->signature == MagickSignature);
359 cmyk_images=NewImageList();
360 for (j=0; j < (ssize_t) GetImageListLength(images); j+=4)
365 cmyk_image=CloneImage(images,images->columns,images->rows,MagickTrue,
367 if (cmyk_image == (Image *) NULL)
369 if (SetImageStorageClass(cmyk_image,DirectClass,exception) == MagickFalse)
371 (void) SetImageColorspace(cmyk_image,CMYKColorspace,exception);
372 for (i=0; i < 4; i++)
374 image_view=AcquireVirtualCacheView(images,exception);
375 cmyk_view=AcquireAuthenticCacheView(cmyk_image,exception);
376 for (y=0; y < (ssize_t) images->rows; y++)
378 register const Quantum
387 p=GetCacheViewVirtualPixels(image_view,0,y,images->columns,1,exception);
388 q=QueueCacheViewAuthenticPixels(cmyk_view,0,y,cmyk_image->columns,1,
390 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
392 for (x=0; x < (ssize_t) images->columns; x++)
397 pixel=QuantumRange-GetPixelIntensity(images,p);
400 case 0: SetPixelCyan(cmyk_image,pixel,q); break;
401 case 1: SetPixelMagenta(cmyk_image,pixel,q); break;
402 case 2: SetPixelYellow(cmyk_image,pixel,q); break;
403 case 3: SetPixelBlack(cmyk_image,pixel,q); break;
406 p+=GetPixelChannels(images);
407 q+=GetPixelChannels(cmyk_image);
409 if (SyncCacheViewAuthenticPixels(cmyk_view,exception) == MagickFalse)
412 cmyk_view=DestroyCacheView(cmyk_view);
413 image_view=DestroyCacheView(image_view);
414 images=GetNextImageInList(images);
415 if (images == (Image *) NULL)
418 AppendImageToList(&cmyk_images,cmyk_image);
424 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
428 % C r o p I m a g e %
432 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
434 % CropImage() extracts a region of the image starting at the offset defined
435 % by geometry. Region must be fully defined, and no special handling of
436 % geometry flags is performed.
438 % The format of the CropImage method is:
440 % Image *CropImage(const Image *image,const RectangleInfo *geometry,
441 % ExceptionInfo *exception)
443 % A description of each parameter follows:
445 % o image: the image.
447 % o geometry: Define the region of the image to crop with members
448 % x, y, width, and height.
450 % o exception: return any errors or warnings in this structure.
453 MagickExport Image *CropImage(const Image *image,const RectangleInfo *geometry,
454 ExceptionInfo *exception)
456 #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) >= (ssize_t) page.width) ||
503 ((bounding_box.y-page.y) >= (ssize_t) page.height) ||
504 ((page.x-bounding_box.x) > (ssize_t) image->columns) ||
505 ((page.y-bounding_box.y) > (ssize_t) 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.alpha=(Quantum) TransparentAlpha;
516 (void) SetImageBackgroundColor(crop_image,exception);
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 ((size_t) (page.x+page.width) > image->columns)
549 page.width=image->columns-page.x;
550 if ((geometry->width != 0) && (page.width > geometry->width))
551 page.width=geometry->width;
552 if ((size_t) (page.y+page.height) > image->rows)
553 page.height=image->rows-page.y;
554 if ((geometry->height != 0) && (page.height > geometry->height))
555 page.height=geometry->height;
556 bounding_box.x+=page.x;
557 bounding_box.y+=page.y;
558 if ((page.width == 0) || (page.height == 0))
560 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
561 "GeometryDoesNotContainImage","'%s'",image->filename);
562 return((Image *) NULL);
565 Initialize crop image attributes.
567 crop_image=CloneImage(image,page.width,page.height,MagickTrue,exception);
568 if (crop_image == (Image *) NULL)
569 return((Image *) NULL);
570 crop_image->page.width=image->page.width;
571 crop_image->page.height=image->page.height;
572 offset.x=(ssize_t) (bounding_box.x+bounding_box.width);
573 offset.y=(ssize_t) (bounding_box.y+bounding_box.height);
574 if ((offset.x > (ssize_t) image->page.width) ||
575 (offset.y > (ssize_t) 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=AcquireVirtualCacheView(image,exception);
588 crop_view=AcquireAuthenticCacheView(crop_image,exception);
589 #if defined(MAGICKCORE_OPENMP_SUPPORT)
590 #pragma omp parallel for schedule(static) shared(progress,status) \
591 dynamic_number_threads(image,image->columns,image->rows,1)
593 for (y=0; y < (ssize_t) crop_image->rows; y++)
595 register const Quantum
604 if (status == MagickFalse)
606 p=GetCacheViewVirtualPixels(image_view,page.x,page.y+y,crop_image->columns,
608 q=QueueCacheViewAuthenticPixels(crop_view,0,y,crop_image->columns,1,
610 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
615 for (x=0; x < (ssize_t) crop_image->columns; x++)
620 if (GetPixelMask(image,p) != 0)
622 p+=GetPixelChannels(image);
623 q+=GetPixelChannels(crop_image);
626 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
635 channel=GetPixelChannelMapChannel(image,i);
636 traits=GetPixelChannelMapTraits(image,channel);
637 crop_traits=GetPixelChannelMapTraits(crop_image,channel);
638 if ((traits == UndefinedPixelTrait) ||
639 (crop_traits == UndefinedPixelTrait))
641 SetPixelChannel(crop_image,channel,p[i],q);
643 p+=GetPixelChannels(image);
644 q+=GetPixelChannels(crop_image);
646 if (SyncCacheViewAuthenticPixels(crop_view,exception) == MagickFalse)
648 if (image->progress_monitor != (MagickProgressMonitor) NULL)
653 #if defined(MAGICKCORE_OPENMP_SUPPORT)
654 #pragma omp critical (MagickCore_CropImage)
656 proceed=SetImageProgress(image,CropImageTag,progress++,image->rows);
657 if (proceed == MagickFalse)
661 crop_view=DestroyCacheView(crop_view);
662 image_view=DestroyCacheView(image_view);
663 crop_image->type=image->type;
664 if (status == MagickFalse)
665 crop_image=DestroyImage(crop_image);
670 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
674 % C r o p I m a g e T o T i l e s %
678 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
680 % CropImageToTiles() crops a single image, into a possible list of tiles.
681 % This may include a single sub-region of the image. This basically applies
682 % all the normal geometry flags for Crop.
684 % Image *CropImageToTiles(const Image *image,
685 % const RectangleInfo *crop_geometry, ExceptionInfo *exception)
687 % A description of each parameter follows:
689 % o image: the image The transformed image is returned as this parameter.
691 % o crop_geometry: A crop geometry string.
693 % o exception: return any errors or warnings in this structure.
697 static inline ssize_t MagickRound(MagickRealType x)
700 Round the fraction to nearest integer.
703 return((ssize_t) (x+0.5));
704 return((ssize_t) (x-0.5));
707 MagickExport Image *CropImageToTiles(const Image *image,
708 const char *crop_geometry,ExceptionInfo *exception)
720 assert(image != (Image *) NULL);
721 assert(image->signature == MagickSignature);
722 if (image->debug != MagickFalse)
723 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
724 crop_image=NewImageList();
726 flags=ParseGravityGeometry(image,crop_geometry,&geometry,exception);
727 if ((flags & AreaValue) != 0)
741 Crop into NxM tiles (@ flag).
743 width=image->columns;
745 if (geometry.width == 0)
747 if (geometry.height == 0)
749 if ((flags & AspectValue) == 0)
751 width-=(geometry.x < 0 ? -1 : 1)*geometry.x;
752 height-=(geometry.y < 0 ? -1 : 1)*geometry.y;
756 width+=(geometry.x < 0 ? -1 : 1)*geometry.x;
757 height+=(geometry.y < 0 ? -1 : 1)*geometry.y;
759 delta.x=(double) width/geometry.width;
760 delta.y=(double) height/geometry.height;
765 for (offset.y=0; offset.y < (double) height; )
767 if ((flags & AspectValue) == 0)
769 crop.y=(ssize_t) MagickRound((MagickRealType) (offset.y-
770 (geometry.y > 0 ? 0 : geometry.y)));
771 offset.y+=delta.y; /* increment now to find width */
772 crop.height=(size_t) MagickRound((MagickRealType) (offset.y+
773 (geometry.y < 0 ? 0 : geometry.y)));
777 crop.y=(ssize_t) MagickRound((MagickRealType) (offset.y-
778 (geometry.y > 0 ? geometry.y : 0)));
779 offset.y+=delta.y; /* increment now to find width */
780 crop.height=(size_t) MagickRound((MagickRealType)
781 (offset.y+(geometry.y < -1 ? geometry.y : 0)));
784 crop.y+=image->page.y;
785 for (offset.x=0; offset.x < (double) width; )
787 if ((flags & AspectValue) == 0)
789 crop.x=(ssize_t) MagickRound((MagickRealType) (offset.x-
790 (geometry.x > 0 ? 0 : geometry.x)));
791 offset.x+=delta.x; /* increment now to find height */
792 crop.width=(size_t) MagickRound((MagickRealType) (offset.x+
793 (geometry.x < 0 ? 0 : geometry.x)));
797 crop.x=(ssize_t) MagickRound((MagickRealType) (offset.x-
798 (geometry.x > 0 ? geometry.x : 0)));
799 offset.x+=delta.x; /* increment now to find height */
800 crop.width=(size_t) MagickRound((MagickRealType) (offset.x+
801 (geometry.x < 0 ? geometry.x : 0)));
804 crop.x+=image->page.x;
805 next=CropImage(image,&crop,exception);
806 if (next == (Image *) NULL)
808 AppendImageToList(&crop_image,next);
810 if (next == (Image *) NULL)
813 ClearMagickException(exception);
816 if (((geometry.width == 0) && (geometry.height == 0)) ||
817 ((flags & XValue) != 0) || ((flags & YValue) != 0))
820 Crop a single region at +X+Y.
822 crop_image=CropImage(image,&geometry,exception);
823 if ((crop_image != (Image *) NULL) && ((flags & AspectValue) != 0))
825 crop_image->page.width=geometry.width;
826 crop_image->page.height=geometry.height;
827 crop_image->page.x-=geometry.x;
828 crop_image->page.y-=geometry.y;
832 if ((image->columns > geometry.width) || (image->rows > geometry.height))
846 Crop into tiles of fixed size WxH.
850 page.width=image->columns;
851 if (page.height == 0)
852 page.height=image->rows;
853 width=geometry.width;
856 height=geometry.height;
860 for (y=0; y < (ssize_t) page.height; y+=(ssize_t) height)
862 for (x=0; x < (ssize_t) page.width; x+=(ssize_t) width)
864 geometry.width=width;
865 geometry.height=height;
868 next=CropImage(image,&geometry,exception);
869 if (next == (Image *) NULL)
871 AppendImageToList(&crop_image,next);
873 if (next == (Image *) NULL)
878 return(CloneImage(image,0,0,MagickTrue,exception));
882 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
886 % E x c e r p t I m a g e %
890 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
892 % ExcerptImage() returns a excerpt of the image as defined by the geometry.
894 % The format of the ExcerptImage method is:
896 % Image *ExcerptImage(const Image *image,const RectangleInfo *geometry,
897 % ExceptionInfo *exception)
899 % A description of each parameter follows:
901 % o image: the image.
903 % o geometry: Define the region of the image to extend with members
904 % x, y, width, and height.
906 % o exception: return any errors or warnings in this structure.
909 MagickExport Image *ExcerptImage(const Image *image,
910 const RectangleInfo *geometry,ExceptionInfo *exception)
912 #define ExcerptImageTag "Excerpt/Image"
931 Allocate excerpt image.
933 assert(image != (const Image *) NULL);
934 assert(image->signature == MagickSignature);
935 if (image->debug != MagickFalse)
936 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
937 assert(geometry != (const RectangleInfo *) NULL);
938 assert(exception != (ExceptionInfo *) NULL);
939 assert(exception->signature == MagickSignature);
940 excerpt_image=CloneImage(image,geometry->width,geometry->height,MagickTrue,
942 if (excerpt_image == (Image *) NULL)
943 return((Image *) NULL);
949 image_view=AcquireVirtualCacheView(image,exception);
950 excerpt_view=AcquireAuthenticCacheView(excerpt_image,exception);
951 #if defined(MAGICKCORE_OPENMP_SUPPORT)
952 #pragma omp parallel for schedule(static,4) shared(progress,status) \
953 dynamic_number_threads(image,image->columns,image->rows,1)
955 for (y=0; y < (ssize_t) excerpt_image->rows; y++)
957 register const Quantum
966 if (status == MagickFalse)
968 p=GetCacheViewVirtualPixels(image_view,geometry->x,geometry->y+y,
969 geometry->width,1,exception);
970 q=GetCacheViewAuthenticPixels(excerpt_view,0,y,excerpt_image->columns,1,
972 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
977 for (x=0; x < (ssize_t) excerpt_image->columns; x++)
982 if (GetPixelMask(image,p) != 0)
984 p+=GetPixelChannels(image);
985 q+=GetPixelChannels(excerpt_image);
988 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
997 channel=GetPixelChannelMapChannel(image,i);
998 traits=GetPixelChannelMapTraits(image,channel);
999 excerpt_traits=GetPixelChannelMapTraits(excerpt_image,channel);
1000 if ((traits == UndefinedPixelTrait) ||
1001 (excerpt_traits == UndefinedPixelTrait))
1003 SetPixelChannel(excerpt_image,channel,p[i],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,exception);
1089 (void) CompositeImage(extent_image,image,image->compose,MagickTrue,
1090 -geometry->x,-geometry->y,exception);
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=AcquireVirtualCacheView(image,exception);
1158 flip_view=AcquireAuthenticCacheView(flip_image,exception);
1159 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1160 #pragma omp parallel for schedule(static) shared(progress,status) \
1161 dynamic_number_threads(image,image->columns,image->rows,1)
1163 for (y=0; y < (ssize_t) flip_image->rows; y++)
1165 register const Quantum
1174 if (status == MagickFalse)
1176 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1177 q=QueueCacheViewAuthenticPixels(flip_view,0,(ssize_t) (flip_image->rows-y-
1178 1),flip_image->columns,1,exception);
1179 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1184 for (x=0; x < (ssize_t) flip_image->columns; x++)
1189 if (GetPixelMask(image,p) != 0)
1191 p+=GetPixelChannels(image);
1192 q+=GetPixelChannels(flip_image);
1195 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1204 channel=GetPixelChannelMapChannel(image,i);
1205 traits=GetPixelChannelMapTraits(image,channel);
1206 flip_traits=GetPixelChannelMapTraits(flip_image,channel);
1207 if ((traits == UndefinedPixelTrait) ||
1208 (flip_traits == UndefinedPixelTrait))
1210 SetPixelChannel(flip_image,channel,p[i],q);
1212 p+=GetPixelChannels(image);
1213 q+=GetPixelChannels(flip_image);
1215 if (SyncCacheViewAuthenticPixels(flip_view,exception) == MagickFalse)
1217 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1222 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1223 #pragma omp critical (MagickCore_FlipImage)
1225 proceed=SetImageProgress(image,FlipImageTag,progress++,image->rows);
1226 if (proceed == MagickFalse)
1230 flip_view=DestroyCacheView(flip_view);
1231 image_view=DestroyCacheView(image_view);
1232 flip_image->type=image->type;
1233 if (page.height != 0)
1234 page.y=(ssize_t) (page.height-flip_image->rows-page.y);
1235 flip_image->page=page;
1236 if (status == MagickFalse)
1237 flip_image=DestroyImage(flip_image);
1242 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1246 % F l o p I m a g e %
1250 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1252 % FlopImage() creates a horizontal mirror image by reflecting the pixels
1253 % around the central y-axis.
1255 % The format of the FlopImage method is:
1257 % Image *FlopImage(const Image *image,ExceptionInfo *exception)
1259 % A description of each parameter follows:
1261 % o image: the image.
1263 % o exception: return any errors or warnings in this structure.
1266 MagickExport Image *FlopImage(const Image *image,ExceptionInfo *exception)
1268 #define FlopImageTag "Flop/Image"
1289 assert(image != (const Image *) NULL);
1290 assert(image->signature == MagickSignature);
1291 if (image->debug != MagickFalse)
1292 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1293 assert(exception != (ExceptionInfo *) NULL);
1294 assert(exception->signature == MagickSignature);
1295 flop_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
1296 if (flop_image == (Image *) NULL)
1297 return((Image *) NULL);
1304 image_view=AcquireVirtualCacheView(image,exception);
1305 flop_view=AcquireAuthenticCacheView(flop_image,exception);
1306 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1307 #pragma omp parallel for schedule(static) shared(progress,status) \
1308 dynamic_number_threads(image,image->columns,image->rows,1)
1310 for (y=0; y < (ssize_t) flop_image->rows; y++)
1312 register const Quantum
1321 if (status == MagickFalse)
1323 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1324 q=QueueCacheViewAuthenticPixels(flop_view,0,y,flop_image->columns,1,
1326 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1331 q+=GetPixelChannels(flop_image)*flop_image->columns;
1332 for (x=0; x < (ssize_t) flop_image->columns; x++)
1337 q-=GetPixelChannels(flop_image);
1338 if (GetPixelMask(image,p) != 0)
1340 p+=GetPixelChannels(image);
1343 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1352 channel=GetPixelChannelMapChannel(image,i);
1353 traits=GetPixelChannelMapTraits(image,channel);
1354 flop_traits=GetPixelChannelMapTraits(flop_image,channel);
1355 if ((traits == UndefinedPixelTrait) ||
1356 (flop_traits == UndefinedPixelTrait))
1358 SetPixelChannel(flop_image,channel,p[i],q);
1360 p+=GetPixelChannels(image);
1362 if (SyncCacheViewAuthenticPixels(flop_view,exception) == MagickFalse)
1364 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1369 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1370 #pragma omp critical (MagickCore_FlopImage)
1372 proceed=SetImageProgress(image,FlopImageTag,progress++,image->rows);
1373 if (proceed == MagickFalse)
1377 flop_view=DestroyCacheView(flop_view);
1378 image_view=DestroyCacheView(image_view);
1379 flop_image->type=image->type;
1380 if (page.width != 0)
1381 page.x=(ssize_t) (page.width-flop_image->columns-page.x);
1382 flop_image->page=page;
1383 if (status == MagickFalse)
1384 flop_image=DestroyImage(flop_image);
1389 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1393 % R o l l I m a g e %
1397 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1399 % RollImage() offsets an image as defined by x_offset and y_offset.
1401 % The format of the RollImage method is:
1403 % Image *RollImage(const Image *image,const ssize_t x_offset,
1404 % const ssize_t y_offset,ExceptionInfo *exception)
1406 % A description of each parameter follows:
1408 % o image: the image.
1410 % o x_offset: the number of columns to roll in the horizontal direction.
1412 % o y_offset: the number of rows to roll in the vertical direction.
1414 % o exception: return any errors or warnings in this structure.
1418 static inline MagickBooleanType CopyImageRegion(Image *destination,
1419 const Image *source,const size_t columns,const size_t rows,
1420 const ssize_t sx,const ssize_t sy,const ssize_t dx,const ssize_t dy,
1421 ExceptionInfo *exception)
1434 source_view=AcquireVirtualCacheView(source,exception);
1435 destination_view=AcquireAuthenticCacheView(destination,exception);
1436 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1437 #pragma omp parallel for schedule(static) shared(status) \
1438 dynamic_number_threads(source,columns,rows,1)
1440 for (y=0; y < (ssize_t) rows; y++)
1445 register const Quantum
1457 if (status == MagickFalse)
1459 p=GetCacheViewVirtualPixels(source_view,sx,sy+y,columns,1,exception);
1460 q=GetCacheViewAuthenticPixels(destination_view,dx,dy+y,columns,1,exception);
1461 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1466 for (x=0; x < (ssize_t) columns; x++)
1471 if (GetPixelMask(source,p) != 0)
1473 p+=GetPixelChannels(source);
1474 q+=GetPixelChannels(destination);
1477 for (i=0; i < (ssize_t) GetPixelChannels(source); i++)
1486 channel=GetPixelChannelMapChannel(source,i);
1487 source_traits=GetPixelChannelMapTraits(source,channel);
1488 destination_traits=GetPixelChannelMapTraits(destination,channel);
1489 if ((source_traits == UndefinedPixelTrait) ||
1490 (destination_traits == UndefinedPixelTrait))
1492 SetPixelChannel(destination,channel,p[i],q);
1494 p+=GetPixelChannels(source);
1495 q+=GetPixelChannels(destination);
1497 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
1498 if (sync == MagickFalse)
1501 destination_view=DestroyCacheView(destination_view);
1502 source_view=DestroyCacheView(source_view);
1506 MagickExport Image *RollImage(const Image *image,const ssize_t x_offset,
1507 const ssize_t y_offset,ExceptionInfo *exception)
1509 #define RollImageTag "Roll/Image"
1521 Initialize roll image attributes.
1523 assert(image != (const Image *) NULL);
1524 assert(image->signature == MagickSignature);
1525 if (image->debug != MagickFalse)
1526 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1527 assert(exception != (ExceptionInfo *) NULL);
1528 assert(exception->signature == MagickSignature);
1529 roll_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
1530 if (roll_image == (Image *) NULL)
1531 return((Image *) NULL);
1534 while (offset.x < 0)
1535 offset.x+=(ssize_t) image->columns;
1536 while (offset.x >= (ssize_t) image->columns)
1537 offset.x-=(ssize_t) image->columns;
1538 while (offset.y < 0)
1539 offset.y+=(ssize_t) image->rows;
1540 while (offset.y >= (ssize_t) image->rows)
1541 offset.y-=(ssize_t) image->rows;
1545 status=CopyImageRegion(roll_image,image,(size_t) offset.x,
1546 (size_t) offset.y,(ssize_t) image->columns-offset.x,(ssize_t) image->rows-
1547 offset.y,0,0,exception);
1548 (void) SetImageProgress(image,RollImageTag,0,3);
1549 status|=CopyImageRegion(roll_image,image,image->columns-offset.x,
1550 (size_t) offset.y,0,(ssize_t) image->rows-offset.y,offset.x,0,
1552 (void) SetImageProgress(image,RollImageTag,1,3);
1553 status|=CopyImageRegion(roll_image,image,(size_t) offset.x,image->rows-
1554 offset.y,(ssize_t) image->columns-offset.x,0,0,offset.y,exception);
1555 (void) SetImageProgress(image,RollImageTag,2,3);
1556 status|=CopyImageRegion(roll_image,image,image->columns-offset.x,image->rows-
1557 offset.y,0,0,offset.x,offset.y,exception);
1558 (void) SetImageProgress(image,RollImageTag,3,3);
1559 roll_image->type=image->type;
1560 if (status == MagickFalse)
1561 roll_image=DestroyImage(roll_image);
1566 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1570 % S h a v e I m a g e %
1574 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1576 % ShaveImage() shaves pixels from the image edges. It allocates the memory
1577 % necessary for the new Image structure and returns a pointer to the new
1580 % The format of the ShaveImage method is:
1582 % Image *ShaveImage(const Image *image,const RectangleInfo *shave_info,
1583 % ExceptionInfo *exception)
1585 % A description of each parameter follows:
1587 % o shave_image: Method ShaveImage returns a pointer to the shaved
1588 % image. A null image is returned if there is a memory shortage or
1589 % if the image width or height is zero.
1591 % o image: the image.
1593 % o shave_info: Specifies a pointer to a RectangleInfo which defines the
1594 % region of the image to crop.
1596 % o exception: return any errors or warnings in this structure.
1599 MagickExport Image *ShaveImage(const Image *image,
1600 const RectangleInfo *shave_info,ExceptionInfo *exception)
1608 assert(image != (const Image *) NULL);
1609 assert(image->signature == MagickSignature);
1610 if (image->debug != MagickFalse)
1611 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1612 if (((2*shave_info->width) >= image->columns) ||
1613 ((2*shave_info->height) >= image->rows))
1614 ThrowImageException(OptionWarning,"GeometryDoesNotContainImage");
1615 SetGeometry(image,&geometry);
1616 geometry.width-=2*shave_info->width;
1617 geometry.height-=2*shave_info->height;
1618 geometry.x=(ssize_t) shave_info->width+image->page.x;
1619 geometry.y=(ssize_t) shave_info->height+image->page.y;
1620 shave_image=CropImage(image,&geometry,exception);
1621 if (shave_image == (Image *) NULL)
1622 return((Image *) NULL);
1623 shave_image->page.width-=2*shave_info->width;
1624 shave_image->page.height-=2*shave_info->height;
1625 shave_image->page.x-=(ssize_t) shave_info->width;
1626 shave_image->page.y-=(ssize_t) shave_info->height;
1627 return(shave_image);
1631 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1635 % S p l i c e I m a g e %
1639 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1641 % SpliceImage() splices a solid color into the image as defined by the
1644 % The format of the SpliceImage method is:
1646 % Image *SpliceImage(const Image *image,const RectangleInfo *geometry,
1647 % ExceptionInfo *exception)
1649 % A description of each parameter follows:
1651 % o image: the image.
1653 % o geometry: Define the region of the image to splice with members
1654 % x, y, width, and height.
1656 % o exception: return any errors or warnings in this structure.
1659 MagickExport Image *SpliceImage(const Image *image,
1660 const RectangleInfo *geometry,ExceptionInfo *exception)
1662 #define SpliceImageTag "Splice/Image"
1684 Allocate splice image.
1686 assert(image != (const Image *) NULL);
1687 assert(image->signature == MagickSignature);
1688 if (image->debug != MagickFalse)
1689 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1690 assert(geometry != (const RectangleInfo *) NULL);
1691 assert(exception != (ExceptionInfo *) NULL);
1692 assert(exception->signature == MagickSignature);
1693 splice_geometry=(*geometry);
1694 splice_image=CloneImage(image,image->columns+splice_geometry.width,
1695 image->rows+splice_geometry.height,MagickTrue,exception);
1696 if (splice_image == (Image *) NULL)
1697 return((Image *) NULL);
1698 if (SetImageStorageClass(splice_image,DirectClass,exception) == MagickFalse)
1700 splice_image=DestroyImage(splice_image);
1701 return((Image *) NULL);
1703 (void) SetImageBackgroundColor(splice_image,exception);
1705 Respect image geometry.
1707 switch (image->gravity)
1710 case UndefinedGravity:
1711 case NorthWestGravity:
1715 splice_geometry.x+=(ssize_t) splice_geometry.width/2;
1718 case NorthEastGravity:
1720 splice_geometry.x+=(ssize_t) splice_geometry.width;
1725 splice_geometry.y+=(ssize_t) splice_geometry.width/2;
1730 splice_geometry.x+=(ssize_t) splice_geometry.width/2;
1731 splice_geometry.y+=(ssize_t) splice_geometry.height/2;
1736 splice_geometry.x+=(ssize_t) splice_geometry.width;
1737 splice_geometry.y+=(ssize_t) splice_geometry.height/2;
1740 case SouthWestGravity:
1742 splice_geometry.y+=(ssize_t) splice_geometry.height;
1747 splice_geometry.x+=(ssize_t) splice_geometry.width/2;
1748 splice_geometry.y+=(ssize_t) splice_geometry.height;
1751 case SouthEastGravity:
1753 splice_geometry.x+=(ssize_t) splice_geometry.width;
1754 splice_geometry.y+=(ssize_t) splice_geometry.height;
1763 image_view=AcquireVirtualCacheView(image,exception);
1764 splice_view=AcquireAuthenticCacheView(splice_image,exception);
1765 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1766 #pragma omp parallel for schedule(static,4) shared(progress,status) \
1767 dynamic_number_threads(image,image->columns,image->rows,1)
1769 for (y=0; y < (ssize_t) splice_geometry.y; y++)
1771 register const Quantum
1780 if (status == MagickFalse)
1782 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1783 q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1,
1785 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1790 for (x=0; x < splice_geometry.x; x++)
1795 if (GetPixelMask(image,p) != 0)
1797 p+=GetPixelChannels(image);
1798 q+=GetPixelChannels(splice_image);
1801 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1810 channel=GetPixelChannelMapChannel(image,i);
1811 traits=GetPixelChannelMapTraits(image,channel);
1812 splice_traits=GetPixelChannelMapTraits(splice_image,channel);
1813 if ((traits == UndefinedPixelTrait) ||
1814 (splice_traits == UndefinedPixelTrait))
1816 SetPixelChannel(splice_image,channel,p[i],q);
1818 p+=GetPixelChannels(image);
1819 q+=GetPixelChannels(splice_image);
1821 for ( ; x < (ssize_t) (splice_geometry.x+splice_geometry.width); x++)
1822 q+=GetPixelChannels(splice_image);
1823 for ( ; x < (ssize_t) splice_image->columns; x++)
1828 if (GetPixelMask(image,p) != 0)
1830 p+=GetPixelChannels(image);
1831 q+=GetPixelChannels(splice_image);
1834 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1843 channel=GetPixelChannelMapChannel(image,i);
1844 traits=GetPixelChannelMapTraits(image,channel);
1845 splice_traits=GetPixelChannelMapTraits(splice_image,channel);
1846 if ((traits == UndefinedPixelTrait) ||
1847 (splice_traits == UndefinedPixelTrait))
1849 SetPixelChannel(splice_image,channel,p[i],q);
1851 p+=GetPixelChannels(image);
1852 q+=GetPixelChannels(splice_image);
1854 if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse)
1856 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1861 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1862 #pragma omp critical (MagickCore_TransposeImage)
1864 proceed=SetImageProgress(image,SpliceImageTag,progress++,
1865 splice_image->rows);
1866 if (proceed == MagickFalse)
1870 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1871 #pragma omp parallel for schedule(static,4) shared(progress,status) \
1872 dynamic_number_threads(image,image->columns,image->rows,1)
1874 for (y=(ssize_t) (splice_geometry.y+splice_geometry.height);
1875 y < (ssize_t) splice_image->rows; y++)
1877 register const Quantum
1886 if (status == MagickFalse)
1888 p=GetCacheViewVirtualPixels(image_view,0,y-(ssize_t) splice_geometry.height,
1889 image->columns,1,exception);
1890 if ((y < 0) || (y >= (ssize_t) splice_image->rows))
1892 q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1,
1894 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1899 for (x=0; x < splice_geometry.x; x++)
1904 if (GetPixelMask(image,q) != 0)
1906 p+=GetPixelChannels(image);
1907 q+=GetPixelChannels(splice_image);
1910 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1919 channel=GetPixelChannelMapChannel(image,i);
1920 traits=GetPixelChannelMapTraits(image,channel);
1921 splice_traits=GetPixelChannelMapTraits(splice_image,channel);
1922 if ((traits == UndefinedPixelTrait) ||
1923 (splice_traits == UndefinedPixelTrait))
1925 SetPixelChannel(splice_image,channel,p[i],q);
1927 p+=GetPixelChannels(image);
1928 q+=GetPixelChannels(splice_image);
1930 for ( ; x < (ssize_t) (splice_geometry.x+splice_geometry.width); x++)
1931 q+=GetPixelChannels(splice_image);
1932 for ( ; x < (ssize_t) splice_image->columns; x++)
1937 if (GetPixelMask(image,q) != 0)
1939 p+=GetPixelChannels(image);
1940 q+=GetPixelChannels(splice_image);
1943 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1952 channel=GetPixelChannelMapChannel(image,i);
1953 traits=GetPixelChannelMapTraits(image,channel);
1954 splice_traits=GetPixelChannelMapTraits(splice_image,channel);
1955 if ((traits == UndefinedPixelTrait) ||
1956 (splice_traits == UndefinedPixelTrait))
1958 SetPixelChannel(splice_image,channel,p[i],q);
1960 p+=GetPixelChannels(image);
1961 q+=GetPixelChannels(splice_image);
1963 if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse)
1965 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1970 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1971 #pragma omp critical (MagickCore_TransposeImage)
1973 proceed=SetImageProgress(image,SpliceImageTag,progress++,
1974 splice_image->rows);
1975 if (proceed == MagickFalse)
1979 splice_view=DestroyCacheView(splice_view);
1980 image_view=DestroyCacheView(image_view);
1981 if (status == MagickFalse)
1982 splice_image=DestroyImage(splice_image);
1983 return(splice_image);
1987 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1991 % T r a n s f o r m I m a g e %
1995 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1997 % TransformImage() is a convenience method that behaves like ResizeImage() or
1998 % CropImage() but accepts scaling and/or cropping information as a region
1999 % geometry specification. If the operation fails, the original image handle
2002 % This should only be used for single images.
2004 % This function destroys what it assumes to be a single image list.
2005 % If the input image is part of a larger list, all other images in that list
2006 % will be simply 'lost', not destroyed.
2008 % Also if the crop generates a list of images only the first image is resized.
2009 % And finally if the crop succeeds and the resize failed, you will get a
2010 % cropped image, as well as a 'false' or 'failed' report.
2012 % This function and should probably be depreciated in favor of direct calls
2013 % to CropImageToTiles() or ResizeImage(), as appropriate.
2015 % The format of the TransformImage method is:
2017 % MagickBooleanType TransformImage(Image **image,const char *crop_geometry,
2018 % const char *image_geometry,ExceptionInfo *exception)
2020 % A description of each parameter follows:
2022 % o image: the image The transformed image is returned as this parameter.
2024 % o crop_geometry: A crop geometry string. This geometry defines a
2025 % subregion of the image to crop.
2027 % o image_geometry: An image geometry string. This geometry defines the
2028 % final size of the image.
2030 % o exception: return any errors or warnings in this structure.
2033 MagickExport MagickBooleanType TransformImage(Image **image,
2034 const char *crop_geometry,const char *image_geometry,ExceptionInfo *exception)
2046 assert(image != (Image **) NULL);
2047 assert((*image)->signature == MagickSignature);
2048 if ((*image)->debug != MagickFalse)
2049 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
2050 transform_image=(*image);
2051 if (crop_geometry != (const char *) NULL)
2057 Crop image to a user specified size.
2059 crop_image=CropImageToTiles(*image,crop_geometry,exception);
2060 if (crop_image == (Image *) NULL)
2061 transform_image=CloneImage(*image,0,0,MagickTrue,exception);
2064 transform_image=DestroyImage(transform_image);
2065 transform_image=GetFirstImageInList(crop_image);
2067 *image=transform_image;
2069 if (image_geometry == (const char *) NULL)
2073 Scale image to a user specified size.
2075 flags=ParseRegionGeometry(transform_image,image_geometry,&geometry,exception);
2077 if ((transform_image->columns == geometry.width) &&
2078 (transform_image->rows == geometry.height))
2080 resize_image=ResizeImage(transform_image,geometry.width,geometry.height,
2081 transform_image->filter,exception);
2082 if (resize_image == (Image *) NULL)
2083 return(MagickFalse);
2084 transform_image=DestroyImage(transform_image);
2085 transform_image=resize_image;
2086 *image=transform_image;
2091 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2095 % T r a n s f o r m I m a g e s %
2099 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2101 % TransformImages() calls TransformImage() on each image of a sequence.
2103 % The format of the TransformImage method is:
2105 % MagickBooleanType TransformImages(Image **image,
2106 % const char *crop_geometry,const char *image_geometry,
2107 % ExceptionInfo *exception)
2109 % A description of each parameter follows:
2111 % o image: the image The transformed image is returned as this parameter.
2113 % o crop_geometry: A crop geometry string. This geometry defines a
2114 % subregion of the image to crop.
2116 % o image_geometry: An image geometry string. This geometry defines the
2117 % final size of the image.
2119 % o exception: return any errors or warnings in this structure.
2122 MagickExport MagickBooleanType TransformImages(Image **images,
2123 const char *crop_geometry,const char *image_geometry,ExceptionInfo *exception)
2136 assert(images != (Image **) NULL);
2137 assert((*images)->signature == MagickSignature);
2138 if ((*images)->debug != MagickFalse)
2139 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2140 (*images)->filename);
2141 image_list=ImageListToArray(*images,exception);
2142 if (image_list == (Image **) NULL)
2143 return(MagickFalse);
2145 transform_images=NewImageList();
2146 for (i=0; image_list[i] != (Image *) NULL; i++)
2148 image=image_list[i];
2149 status|=TransformImage(&image,crop_geometry,image_geometry,exception);
2150 AppendImageToList(&transform_images,image);
2152 *images=transform_images;
2153 image_list=(Image **) RelinquishMagickMemory(image_list);
2154 return(status != 0 ? MagickTrue : MagickFalse);
2158 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2162 % T r a n s p o s e I m a g e %
2166 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2168 % TransposeImage() creates a horizontal mirror image by reflecting the pixels
2169 % around the central y-axis while rotating them by 90 degrees.
2171 % The format of the TransposeImage method is:
2173 % Image *TransposeImage(const Image *image,ExceptionInfo *exception)
2175 % A description of each parameter follows:
2177 % o image: the image.
2179 % o exception: return any errors or warnings in this structure.
2182 MagickExport Image *TransposeImage(const Image *image,ExceptionInfo *exception)
2184 #define TransposeImageTag "Transpose/Image"
2205 assert(image != (const Image *) NULL);
2206 assert(image->signature == MagickSignature);
2207 if (image->debug != MagickFalse)
2208 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2209 assert(exception != (ExceptionInfo *) NULL);
2210 assert(exception->signature == MagickSignature);
2211 transpose_image=CloneImage(image,image->rows,image->columns,MagickTrue,
2213 if (transpose_image == (Image *) NULL)
2214 return((Image *) NULL);
2220 image_view=AcquireVirtualCacheView(image,exception);
2221 transpose_view=AcquireAuthenticCacheView(transpose_image,exception);
2222 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2223 #pragma omp parallel for schedule(static,4) shared(progress,status) \
2224 dynamic_number_threads(image,image->columns,image->rows,1)
2226 for (y=0; y < (ssize_t) image->rows; y++)
2228 register const Quantum
2237 if (status == MagickFalse)
2239 p=GetCacheViewVirtualPixels(image_view,0,(ssize_t) image->rows-y-1,
2240 image->columns,1,exception);
2241 q=QueueCacheViewAuthenticPixels(transpose_view,(ssize_t) (image->rows-y-1),
2242 0,1,transpose_image->rows,exception);
2243 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2248 for (x=0; x < (ssize_t) image->columns; x++)
2253 if (GetPixelMask(image,q) != 0)
2255 p+=GetPixelChannels(image);
2256 q+=GetPixelChannels(transpose_image);
2259 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2268 channel=GetPixelChannelMapChannel(image,i);
2269 traits=GetPixelChannelMapTraits(image,channel);
2270 transpose_traits=GetPixelChannelMapTraits(transpose_image,channel);
2271 if ((traits == UndefinedPixelTrait) ||
2272 (transpose_traits == UndefinedPixelTrait))
2274 SetPixelChannel(transpose_image,channel,p[i],q);
2276 p+=GetPixelChannels(image);
2277 q+=GetPixelChannels(transpose_image);
2279 if (SyncCacheViewAuthenticPixels(transpose_view,exception) == MagickFalse)
2281 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2286 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2287 #pragma omp critical (MagickCore_TransposeImage)
2289 proceed=SetImageProgress(image,TransposeImageTag,progress++,
2291 if (proceed == MagickFalse)
2295 transpose_view=DestroyCacheView(transpose_view);
2296 image_view=DestroyCacheView(image_view);
2297 transpose_image->type=image->type;
2298 page=transpose_image->page;
2299 Swap(page.width,page.height);
2300 Swap(page.x,page.y);
2301 transpose_image->page=page;
2302 if (status == MagickFalse)
2303 transpose_image=DestroyImage(transpose_image);
2304 return(transpose_image);
2308 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2312 % T r a n s v e r s e I m a g e %
2316 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2318 % TransverseImage() creates a vertical mirror image by reflecting the pixels
2319 % around the central x-axis while rotating them by 270 degrees.
2321 % The format of the TransverseImage method is:
2323 % Image *TransverseImage(const Image *image,ExceptionInfo *exception)
2325 % A description of each parameter follows:
2327 % o image: the image.
2329 % o exception: return any errors or warnings in this structure.
2332 MagickExport Image *TransverseImage(const Image *image,ExceptionInfo *exception)
2334 #define TransverseImageTag "Transverse/Image"
2355 assert(image != (const Image *) NULL);
2356 assert(image->signature == MagickSignature);
2357 if (image->debug != MagickFalse)
2358 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2359 assert(exception != (ExceptionInfo *) NULL);
2360 assert(exception->signature == MagickSignature);
2361 transverse_image=CloneImage(image,image->rows,image->columns,MagickTrue,
2363 if (transverse_image == (Image *) NULL)
2364 return((Image *) NULL);
2370 image_view=AcquireVirtualCacheView(image,exception);
2371 transverse_view=AcquireAuthenticCacheView(transverse_image,exception);
2372 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2373 #pragma omp parallel for schedule(static,4) shared(progress,status) \
2374 dynamic_number_threads(image,image->columns,image->rows,1)
2376 for (y=0; y < (ssize_t) image->rows; y++)
2381 register const Quantum
2390 if (status == MagickFalse)
2392 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2393 q=QueueCacheViewAuthenticPixels(transverse_view,(ssize_t) (image->rows-y-1),
2394 0,1,transverse_image->rows,exception);
2395 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2400 q+=GetPixelChannels(transverse_image)*image->columns;
2401 for (x=0; x < (ssize_t) image->columns; x++)
2406 q-=GetPixelChannels(transverse_image);
2407 if (GetPixelMask(image,p) != 0)
2409 p+=GetPixelChannels(image);
2412 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2421 channel=GetPixelChannelMapChannel(image,i);
2422 traits=GetPixelChannelMapTraits(image,channel);
2423 transverse_traits=GetPixelChannelMapTraits(transverse_image,channel);
2424 if ((traits == UndefinedPixelTrait) ||
2425 (transverse_traits == UndefinedPixelTrait))
2427 SetPixelChannel(transverse_image,channel,p[i],q);
2429 p+=GetPixelChannels(image);
2431 sync=SyncCacheViewAuthenticPixels(transverse_view,exception);
2432 if (sync == MagickFalse)
2434 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2439 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2440 #pragma omp critical (MagickCore_TransverseImage)
2442 proceed=SetImageProgress(image,TransverseImageTag,progress++,
2444 if (proceed == MagickFalse)
2448 transverse_view=DestroyCacheView(transverse_view);
2449 image_view=DestroyCacheView(image_view);
2450 transverse_image->type=image->type;
2451 page=transverse_image->page;
2452 Swap(page.width,page.height);
2453 Swap(page.x,page.y);
2454 if (page.width != 0)
2455 page.x=(ssize_t) (page.width-transverse_image->columns-page.x);
2456 if (page.height != 0)
2457 page.y=(ssize_t) (page.height-transverse_image->rows-page.y);
2458 transverse_image->page=page;
2459 if (status == MagickFalse)
2460 transverse_image=DestroyImage(transverse_image);
2461 return(transverse_image);
2465 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2469 % T r i m I m a g e %
2473 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2475 % TrimImage() trims pixels from the image edges. It allocates the memory
2476 % necessary for the new Image structure and returns a pointer to the new
2479 % The format of the TrimImage method is:
2481 % Image *TrimImage(const Image *image,ExceptionInfo *exception)
2483 % A description of each parameter follows:
2485 % o image: the image.
2487 % o exception: return any errors or warnings in this structure.
2490 MagickExport Image *TrimImage(const Image *image,ExceptionInfo *exception)
2495 assert(image != (const Image *) NULL);
2496 assert(image->signature == MagickSignature);
2497 if (image->debug != MagickFalse)
2498 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2499 geometry=GetImageBoundingBox(image,exception);
2500 if ((geometry.width == 0) || (geometry.height == 0))
2505 crop_image=CloneImage(image,1,1,MagickTrue,exception);
2506 if (crop_image == (Image *) NULL)
2507 return((Image *) NULL);
2508 crop_image->background_color.alpha=(Quantum) TransparentAlpha;
2509 (void) SetImageBackgroundColor(crop_image,exception);
2510 crop_image->page=image->page;
2511 crop_image->page.x=(-1);
2512 crop_image->page.y=(-1);
2515 geometry.x+=image->page.x;
2516 geometry.y+=image->page.y;
2517 return(CropImage(image,&geometry,exception));