From 9f4f03454372e98844a5bcd785267820f294a2ae Mon Sep 17 00:00:00 2001 From: anthony Date: Mon, 28 Mar 2011 11:47:22 +0000 Subject: [PATCH] Separated CropImageToTiles() from TransformImage() to allow better handling of a list of images. --- ChangeLog | 7 + magick/transform.c | 493 +++++++++++++++++++++++++++------------------ magick/transform.h | 1 + wand/mogrify.c | 27 +-- 4 files changed, 312 insertions(+), 216 deletions(-) diff --git a/ChangeLog b/ChangeLog index b6c0ef3de..b3f726112 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2011-03-28 6.6.9-0 Anthony Thyssen + * Separated complex cropping function from TransformImage() as a new + function CropImageToTiles(). This new function returns either the + new cropped image, or a list of tiles, according to geometry, without + replacing the source image. The Source image may be part of a larger list + of images, without the function 'loosing' the other images of the list. + 2011-03-27 6.6.8-10 Cristy * New version 6.6.8-10. diff --git a/magick/transform.c b/magick/transform.c index 62f9e889a..0b4dd88f8 100644 --- a/magick/transform.c +++ b/magick/transform.c @@ -496,7 +496,8 @@ MagickExport Image *ConsolidateCMYKImages(const Image *images, %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % CropImage() extracts a region of the image starting at the offset defined -% by geometry. +% by geometry. Region must be fully defined, and no special handling of +% geometry flags is performed. % % The format of the CropImage method is: % @@ -707,6 +708,282 @@ MagickExport Image *CropImage(const Image *image,const RectangleInfo *geometry, % % % % % % +% C r o p I m a g e T o T i l e s % +% % +% % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% CropImageToTiles() will crop a single image, into a posible list of tiles. +% This may include a single sub-region of the image. This basically applies +% all the normal geometry flags for Crop. +% +% Image *CropImageToTiles(const Image *image,const RectangleInfo +% *crop_geometry, ExceptionInfo *exception) +% +% A description of each parameter follows: +% +% o image: the image The transformed image is returned as this parameter. +% +% o crop_geometry: A crop geometry string. +% +% o exception: return any errors or warnings in this structure. +% +*/ +static inline ssize_t MagickRound(MagickRealType x) +{ + /* + Round the fraction to nearest integer. + */ + if (x >= 0.0) + return((ssize_t) (x+0.5)); + return((ssize_t) (x-0.5)); +} + +MagickExport Image *CropImageToTiles(const Image *image, + const char *crop_geometry, ExceptionInfo *exception) +{ + Image + *next, + *crop_image; + + MagickStatusType + flags; + + RectangleInfo + geometry; + + assert(image != (Image *) NULL); + assert(image->signature == MagickSignature); + if (image->debug != MagickFalse) + (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); + + crop_image=NewImageList(); + next=NewImageList(); + flags=ParseGravityGeometry(image,crop_geometry,&geometry,exception); + + if ((flags & AreaValue) != 0) + { + /* + MagickBooleanType + proceed; + + MagickProgressMonitor + progress_monitor; + + MagickOffsetType + i; + + MagickSizeType + number_images; + */ + size_t + height, + width; + + PointInfo + delta, + offset; + + RectangleInfo + crop; + + /* + Crop into NxM tiles (@ flag) + */ + width=image->columns; + height=image->rows; + if (geometry.width == 0) + geometry.width=1; + if (geometry.height == 0) + geometry.height=1; + if ((flags & AspectValue) == 0) + { + width-=(geometry.x < 0 ? -1 : 1)*geometry.x; + height-=(geometry.y < 0 ? -1 : 1)*geometry.y; + } + else + { + width+=(geometry.x < 0 ? -1 : 1)*geometry.x; + height+=(geometry.y < 0 ? -1 : 1)*geometry.y; + } + delta.x=(double) width/geometry.width; + delta.y=(double) height/geometry.height; + /*proceed=MagickTrue; + i=0; + number_images=geometry.width*geometry.height;*/ + for (offset.y=0; offset.y < (double) height; ) + { + if ((flags & AspectValue) == 0) + { + crop.y=(ssize_t) MagickRound((MagickRealType) + (offset.y-(geometry.y > 0 ? 0 : geometry.y))); + offset.y+=delta.y; /* increment now to find width */ + crop.height=(size_t) MagickRound((MagickRealType) + (offset.y+(geometry.y < 0 ? 0 : geometry.y))); + } + else + { + crop.y=(ssize_t) MagickRound((MagickRealType) + (offset.y-(geometry.y > 0 ? geometry.y : 0))); + offset.y+=delta.y; /* increment now to find width */ + crop.height=(size_t) MagickRound((MagickRealType) + (offset.y+(geometry.y < 0 ? geometry.y : 0))); + } + crop.height-=crop.y; + crop.y+=image->page.y; + for (offset.x=0; offset.x < (double) width; ) + { + /*progress_monitor=SetImageProgressMonitor(image, + (MagickProgressMonitor) NULL,image->client_data);*/ + if ((flags & AspectValue) == 0) + { + crop.x=(ssize_t) MagickRound((MagickRealType) + (offset.x-(geometry.x > 0 ? 0 : geometry.x))); + offset.x+=+delta.x; /* increment now to find height*/ + crop.width=(size_t) MagickRound((MagickRealType) + (offset.x+(geometry.x < 0 ? 0 : geometry.x))); + } + else + { + crop.x=(ssize_t) MagickRound((MagickRealType) (offset.x- + (geometry.x > 0 ? geometry.x : 0))); + offset.x+=+delta.x; /* increment now to find height */ + crop.width=(size_t) MagickRound((MagickRealType) + (offset.x+(geometry.x < 0 ? geometry.x : 0))); + } + crop.width-=crop.x; + crop.x+=image->page.x; + next=CropImage(image,&crop,exception); + /*(void) SetImageProgressMonitor(image,progress_monitor, + image->client_data); + proceed=SetImageProgress(image,CropImageTag,i++,number_images); + if (proceed == MagickFalse) + break; + */ + if (next == (Image *) NULL) + break; + /*(void) SetImageProgressMonitor(next,progress_monitor, + next->client_data);*/ + AppendImageToList(&crop_image,next); + } + if (next == (Image *) NULL) + break; + /*if (proceed == MagickFalse) + break;*/ + } + return(crop_image); + } + + if (((geometry.width == 0) && (geometry.height == 0)) || + ((flags & XValue) != 0) || ((flags & YValue) != 0)) + { + /* + Crop a single region at +X+Y. + */ + crop_image=CropImage(image,&geometry,exception); + if ((crop_image != (Image *) NULL) && ((flags & AspectValue) != 0)) + { + crop_image->page.width=geometry.width; + crop_image->page.height=geometry.height; + crop_image->page.x-=geometry.x; + crop_image->page.y-=geometry.y; + } + return(crop_image); + } + + if ((image->columns > geometry.width) || + (image->rows > geometry.height)) + { + /* + MagickBooleanType + proceed; + + MagickProgressMonitor + progress_monitor; + + MagickOffsetType + i; + + MagickSizeType + number_images; + */ + size_t + height, + width; + + ssize_t + x, + y; + + RectangleInfo + page; + + /* + Crop into tiles of fixed size WxH. + */ + width=geometry.width; + if (width == 0) + width=image->page.width; + height=geometry.height; + if (height == 0) + height=image->page.height; + page=image->page; + if (page.width == 0) + page.width=image->columns; + if (image->page.height == 0) + page.height=image->rows; + next=NewImageList(); + /*proceed=MagickTrue; + i=0; + number_images=0; + for (y=0; y < (ssize_t) page.height; y+=(ssize_t) height) + for (x=0; x < (ssize_t) page.width; x+=(ssize_t) width) + number_images++; + */ + for (y=0; y < (ssize_t) page.height; y+=(ssize_t) height) + { + for (x=0; x < (ssize_t) page.width; x+=(ssize_t) width) + { + /*progress_monitor=SetImageProgressMonitor(image, + (MagickProgressMonitor) NULL,image->client_data);*/ + geometry.width=width; + geometry.height=height; + geometry.x=x; + geometry.y=y; + next=CropImage(image,&geometry,exception); + /*(void) SetImageProgressMonitor(image,progress_monitor, + image->client_data); + proceed=SetImageProgress(image,CropImageTag,i++,number_images); + if (proceed == MagickFalse) + break; + */ + if (next == (Image *) NULL) + break; + /*(void) SetImageProgressMonitor(next,progress_monitor, + next->client_data);*/ + AppendImageToList(&crop_image,next); + } + if (next == (Image *) NULL) + break; + /*if (proceed == MagickFalse) + break;*/ + + } + return(crop_image); + } + /* + Action of crop results in no change in image! + This is not an error so return a clone of the image! + */ + return(CloneImage(image,0,0,MagickTrue,exception)); +} + +/* +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% % +% % +% % % E x c e r p t I m a g e % % % % % @@ -1684,7 +1961,9 @@ MagickExport Image *SpliceImage(const Image *image, % TransformImage() is a convenience method that behaves like ResizeImage() or % CropImage() but accepts scaling and/or cropping information as a region % geometry specification. If the operation fails, the original image handle -% is returned. +% is left as is. +% +% This should only be used for single images. % % The format of the TransformImage method is: % @@ -1702,22 +1981,23 @@ MagickExport Image *SpliceImage(const Image *image, % final size of the image. % */ +/* + DANGER: This function destroys what it assumes to be a single image list. + If the input image is part of a larger list, all other images in that list + will be simply 'lost', not destroyed. -static inline ssize_t MagickRound(MagickRealType x) -{ - /* - Round the fraction to nearest integer. - */ - if (x >= 0.0) - return((ssize_t) (x+0.5)); - return((ssize_t) (x-0.5)); -} + Also if the crop generates a list of images only the first image is resized. + And finally if the crop succeeds and the resize failed, you will get a + cropped image, as well as a 'false' or 'failed' report. + This function and should probably be depreciated in favor of direct calls + to CropImageToTiles() or ResizeImage(), as appropriate. + +*/ MagickExport MagickBooleanType TransformImage(Image **image, const char *crop_geometry,const char *image_geometry) { Image - *next, *resize_image, *transform_image; @@ -1727,14 +2007,6 @@ MagickExport MagickBooleanType TransformImage(Image **image, RectangleInfo geometry; - size_t - height, - width; - - ssize_t - x, - y; - assert(image != (Image **) NULL); assert((*image)->signature == MagickSignature); if ((*image)->debug != MagickFalse) @@ -1745,188 +2017,10 @@ MagickExport MagickBooleanType TransformImage(Image **image, Image *crop_image; - RectangleInfo - geometry; - /* Crop image to a user specified size. */ - crop_image=NewImageList(); - flags=ParseGravityGeometry(transform_image,crop_geometry,&geometry, - &(*image)->exception); - if ((flags & AreaValue) != 0) - { - PointInfo - delta, - offset; - - RectangleInfo - crop; - - /* - Crop into NxM tiles (@ flag) - AT. - */ - if (geometry.width == 0) - geometry.width=1; - if (geometry.height == 0) - geometry.height=1; - width=transform_image->columns; - height=transform_image->rows; - if ((flags & AspectValue) == 0) - { - width-=(geometry.x < 0 ? -1 : 1)*geometry.x; - height-=(geometry.y < 0 ? -1 : 1)*geometry.y; - } - else - { - width+=(geometry.x < 0 ? -1 : 1)*geometry.x; - height+=(geometry.y < 0 ? -1 : 1)*geometry.y; - } - delta.x=(double) width/geometry.width; - delta.y=(double) height/geometry.height; - next=NewImageList(); - for (offset.y=0; offset.y < (double) height; ) - { - if ((flags & AspectValue) == 0) - { - crop.y=(ssize_t) MagickRound((MagickRealType) (offset.y- - (geometry.y > 0 ? 0 : geometry.y))); - offset.y+=delta.y; - crop.height=(size_t) MagickRound((MagickRealType) - (offset.y+(geometry.y < 0 ? 0 : geometry.y))); - } - else - { - crop.y=(ssize_t) MagickRound((MagickRealType) (offset.y- - (geometry.y > 0 ? geometry.y : 0))); - offset.y+=delta.y; - crop.height=(size_t) MagickRound((MagickRealType) - (offset.y+(geometry.y < 0 ? geometry.y : 0))); - } - crop.height-=crop.y; - crop.y+=transform_image->page.y; - for (offset.x=0; offset.x < (double) width; ) - { - if ((flags & AspectValue) == 0) - { - crop.x=(ssize_t) MagickRound((MagickRealType) (offset.x- - (geometry.x > 0 ? 0 : geometry.x))); - offset.x+=+delta.x; - crop.width=(size_t) MagickRound((MagickRealType) - (offset.x+(geometry.x < 0 ? 0 : geometry.x))); - } - else - { - crop.x=(ssize_t) MagickRound((MagickRealType) (offset.x- - (geometry.x > 0 ? geometry.x : 0))); - offset.x+=+delta.x; - crop.width=(size_t) MagickRound((MagickRealType) - (offset.x+(geometry.x < 0 ? geometry.x : 0))); - } - crop.width-=crop.x; - crop.x+=transform_image->page.x; - next=CropImage(transform_image,&crop,&(*image)->exception); - if (next == (Image *) NULL) - break; - AppendImageToList(&crop_image,next); - } - if (next == (Image *) NULL) - break; - } - } - else - if (((geometry.width == 0) && (geometry.height == 0)) || - ((flags & XValue) != 0) || ((flags & YValue) != 0)) - { - /* - Crop a single region at +X+Y. - */ - crop_image=CropImage(transform_image,&geometry, - &(*image)->exception); - if ((crop_image != (Image *) NULL) && ((flags & AspectValue) != 0)) - { - crop_image->page.width=geometry.width; - crop_image->page.height=geometry.height; - crop_image->page.x-=geometry.x; - crop_image->page.y-=geometry.y; - } - } - else - if ((transform_image->columns > geometry.width) || - (transform_image->rows > geometry.height)) - { - MagickBooleanType - proceed; - - MagickProgressMonitor - progress_monitor; - - MagickOffsetType - i; - - MagickSizeType - number_images; - - RectangleInfo - page; - - /* - Crop into tiles of fixed size WxH. - */ - if (transform_image->page.width == 0) - transform_image->page.width=transform_image->columns; - if (transform_image->page.height == 0) - transform_image->page.height=transform_image->rows; - width=geometry.width; - if (width == 0) - width=transform_image->page.width; - height=geometry.height; - if (height == 0) - height=transform_image->page.height; - next=NewImageList(); - proceed=MagickTrue; - i=0; - number_images=0; - page=transform_image->page; - for (y=0; y < (ssize_t) page.height; y+=(ssize_t) height) - for (x=0; x < (ssize_t) page.width; x+=(ssize_t) width) - number_images++; - for (y=0; y < (ssize_t) page.height; y+=(ssize_t) height) - { - for (x=0; x < (ssize_t) page.width; x+=(ssize_t) width) - { - progress_monitor=SetImageProgressMonitor(transform_image, - (MagickProgressMonitor) NULL,transform_image->client_data); - geometry.width=width; - geometry.height=height; - geometry.x=x; - geometry.y=y; - next=CropImage(transform_image,&geometry,&(*image)->exception); - (void) SetImageProgressMonitor(transform_image, - progress_monitor,transform_image->client_data); - proceed=SetImageProgress(transform_image,CropImageTag,i++, - number_images); - if (proceed == MagickFalse) - break; - if (next == (Image *) NULL) - break; - (void) SetImageProgressMonitor(next,progress_monitor, - next->client_data); - if (crop_image == (Image *) NULL) - crop_image=next; - else - { - next->previous=crop_image; - crop_image->next=next; - crop_image=crop_image->next; - } - } - if (next == (Image *) NULL) - break; - if (proceed == MagickFalse) - break; - } - } + crop_image=CropImageToTiles(*image,crop_geometry,&(*image)->exception); if (crop_image == (Image *) NULL) transform_image=CloneImage(*image,0,0,MagickTrue,&(*image)->exception); else @@ -1938,6 +2032,7 @@ MagickExport MagickBooleanType TransformImage(Image **image, } if (image_geometry == (const char *) NULL) return(MagickTrue); + /* Scale image to a user specified size. */ diff --git a/magick/transform.h b/magick/transform.h index c31d1d176..07098aa7e 100644 --- a/magick/transform.h +++ b/magick/transform.h @@ -26,6 +26,7 @@ extern MagickExport Image *ChopImage(const Image *,const RectangleInfo *,ExceptionInfo *), *ConsolidateCMYKImages(const Image *,ExceptionInfo *), *CropImage(const Image *,const RectangleInfo *,ExceptionInfo *), + *CropImageToTiles(const Image *,const char *, ExceptionInfo *), *ExcerptImage(const Image *,const RectangleInfo *,ExceptionInfo *), *ExtentImage(const Image *,const RectangleInfo *,ExceptionInfo *), *FlipImage(const Image *,ExceptionInfo *), diff --git a/wand/mogrify.c b/wand/mogrify.c index 03161b0a8..7d31c8736 100644 --- a/wand/mogrify.c +++ b/wand/mogrify.c @@ -1225,27 +1225,22 @@ WandExport MagickBooleanType MogrifyImage(ImageInfo *image_info,const int argc, { /* Crop a image to a smaller size - NOTE that 'tile cropping' (no geometry offsets) is not - performed here but is applied in MogrifyImageList(). - In any case 'equal area sub-division' via the '@' flag can - and does generate multiple images here (if offset also given). - - We could easily remove "-crop" handling in MogrifyImageList() - simply by removing the next 'if' statement below. - - The special handling (Clone of current image) is needed as - TransformImage() will destory and replace the list the image is - located in. This should be fixed. */ (void) SyncImageSettings(mogrify_info,*image); +#if 0 flags=ParseGravityGeometry(*image,argv[i+1],&geometry,exception); if (((geometry.width != 0) || (geometry.height != 0)) && ((flags & XValue) == 0) && ((flags & YValue) == 0)) break; +#endif +#if 0 new_image=CloneImage(*image,0,0,MagickTrue,&(*image)->exception); new_image->next = new_image->previous = (Image *)NULL; (void) TransformImage(&new_image,argv[i+1],(char *) NULL); InheritException(exception,&new_image->exception); +#else + new_image=CropImageToTiles(*image,argv[i+1],exception); +#endif break; } if (LocaleCompare("cycle",option+1) == 0) @@ -7479,6 +7474,8 @@ WandExport MagickBooleanType MogrifyImageList(ImageInfo *image_info, *images=image; break; } +#if 0 +This has been merged completely into MogrifyImage() if (LocaleCompare("crop",option+1) == 0) { MagickStatusType @@ -7488,12 +7485,7 @@ WandExport MagickBooleanType MogrifyImageList(ImageInfo *image_info, geometry; /* - Crop Image (when offsets given - tile crop) - - Note this does not include 'equal area division' which is - flaged by a '@' symbol. - - This could be merged completely into MogrifyImage() + Crop Image. */ (void) SyncImagesSettings(mogrify_info,*images); flags=ParseGravityGeometry(*images,argv[i+1],&geometry,exception); @@ -7504,6 +7496,7 @@ WandExport MagickBooleanType MogrifyImageList(ImageInfo *image_info, InheritException(exception,&(*images)->exception); break; } +#endif break; } case 'd': -- 2.40.0