/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % S h e a r I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % ShearImage() creates a new image that is a shear_image copy of an existing % one. Shearing slides one edge of an image along the X or Y axis, creating % a parallelogram. An X direction shear slides an edge along the X axis, % while a Y direction shear slides an edge along the Y axis. The amount of % the shear is controlled by a shear angle. For X direction shears, x_shear % is measured relative to the Y axis, and similarly, for Y direction shears % y_shear is measured relative to the X axis. Empty triangles left over from % shearing the image are filled with the background color defined by member % 'background_color' of the image.. ShearImage() allocates the memory % necessary for the new Image structure and returns a pointer to the new image. % % ShearImage() is based on the paper "A Fast Algorithm for General Raster % Rotatation" by Alan W. Paeth. % % The format of the ShearImage method is: % % Image *ShearImage(const Image *image,const double x_shear, % const double y_shear,ExceptionInfo *exception) % % A description of each parameter follows. % % o image: the image. % % o x_shear, y_shear: Specifies the number of degrees to shear the image. % % o exception: Return any errors or warnings in this structure. % % */ MagickExport Image *ShearImage(const Image *image,const double x_shear, const double y_shear,ExceptionInfo *exception) { Image *integral_image, *shear_image; long x_offset, y_offset; PointInfo shear; RectangleInfo border_info; unsigned long y_width; assert(image != (Image *) NULL); assert(image->signature == MagickSignature); if (image->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); assert(exception != (ExceptionInfo *) NULL); assert(exception->signature == MagickSignature); if ((x_shear != 0.0) && (fmod(x_shear,90.0) == 0.0)) ThrowImageException(ImageError,"AngleIsDiscontinuous"); if ((y_shear != 0.0) && (fmod(y_shear,90.0) == 0.0)) ThrowImageException(ImageError,"AngleIsDiscontinuous"); /* Initialize shear angle. */ integral_image=CloneImage(image,0,0,MagickTrue,exception); if (integral_image == (Image *) NULL) ThrowImageException(ResourceLimitError,"MemoryAllocationFailed"); shear.x=(-tan(DegreesToRadians(x_shear))); shear.y=tan(DegreesToRadians(y_shear)); if ((shear.x == 0.0) && (shear.y == 0.0)) return(integral_image); if (SetImageStorageClass(integral_image,DirectClass) == MagickFalse) { InheritException(exception,&integral_image->exception); integral_image=DestroyImage(integral_image); return(integral_image); } if (integral_image->matte == MagickFalse) (void) SetImageOpacity(integral_image,OpaqueOpacity); /* Compute image size. */ y_width=image->columns+(long) (fabs(shear.x)*image->rows+0.5); x_offset=(long) (image->columns+((fabs(shear.x)*image->rows)- image->columns)/2.0+0.5); y_offset=(long) (image->rows+((fabs(shear.y)*y_width+0.5)-image->rows)/2.0+ 0.5); /* Surround image with border. */ integral_image->border_color=integral_image->background_color; integral_image->compose=CopyCompositeOp; border_info.width=(unsigned long) x_offset; border_info.height=(unsigned long) y_offset; shear_image=BorderImage(integral_image,&border_info,exception); if (shear_image == (Image *) NULL) ThrowImageException(ResourceLimitError,"MemoryAllocationFailed"); integral_image=DestroyImage(integral_image); /* Shear the image. */ if (shear_image->matte == MagickFalse) (void) SetImageOpacity(shear_image,OpaqueOpacity); XShearImage(shear_image,shear.x,image->columns,image->rows,x_offset, ((long) shear_image->rows-image->rows)/2); YShearImage(shear_image,shear.y,y_width,image->rows, ((long) shear_image->columns-y_width)/2,y_offset); CropToFitImage(&shear_image,shear.x,shear.y,(MagickRealType) image->columns, (MagickRealType) image->rows,MagickFalse,exception); shear_image->compose=image->compose; shear_image->page.width=0; shear_image->page.height=0; return(shear_image); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % S h e a r I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Method ShearImage creates a new image that is a shear_image copy of an % existing one. Shearing slides one edge of an image along the X or Y % axis, creating a parallelogram. An X direction shear slides an edge % along the X axis, while a Y direction shear slides an edge along the Y % axis. The amount of the shear is controlled by a shear angle. For X % direction shears, x_shear is measured relative to the Y axis, and % similarly, for Y direction shears y_shear is measured relative to the % X axis. Empty triangles left over from shearing the image are filled % with the color defined by the pixel at location (0,0). ShearImage % allocates the memory necessary for the new Image structure and returns % a pointer to the new image. % % Method ShearImage is based on the paper "A Fast Algorithm for General % Raster Rotatation" by Alan W. Paeth. % % The format of the ShearImage method is: % % Image *ShearImage(const Image *image,const double x_shear, % const double y_shear,ExceptionInfo *exception) % % A description of each parameter follows. % % o status: Method ShearImage returns a pointer to the image after % rotating. A null image is returned if there is a memory shortage. % % o image: The image; returned from % ReadImage. % % o x_shear, y_shear: Specifies the number of degrees to shear the image. % % o exception: Return any errors or warnings in this structure. % % */ MagickExport Image *ShearImage(const Image *image,const double x_shear, const double y_shear,ExceptionInfo *exception) { Image *integral_image, *shear_image; long x_offset, y_offset; PointInfo shear; RectangleInfo border_info; unsigned long y_width; assert(image != (Image *) NULL); assert(image->signature == MagickSignature); assert(exception != (ExceptionInfo *) NULL); assert(exception->signature == MagickSignature); if ((x_shear == 180.0) || (y_shear == 180.0)) ThrowImageException3(ImageError,UnableToShearImage,AngleIsDiscontinuous); /* Initialize shear angle. */ integral_image=IntegralRotateImage(image,0,exception); if (integral_image == (Image *) NULL) ThrowImageException3(ResourceLimitError,MemoryAllocationFailed, UnableToShearImage); shear.x=(-tan(DegreesToRadians(x_shear)/2.0)); shear.y=sin(DegreesToRadians(y_shear)); if ((shear.x == 0.0) || (shear.y == 0.0)) return(integral_image); /* Compute image size. */ x_offset=(long) ceil(fabs(2.0*image->rows*shear.x)-0.5); y_width=(unsigned long) floor(fabs(image->rows*shear.x)+image->columns+0.5); y_offset=(long) ceil(fabs(y_width*shear.y)-0.5); /* Surround image with border. */ integral_image->border_color=integral_image->background_color; border_info.width=x_offset; border_info.height=y_offset; shear_image=BorderImage(integral_image,&border_info,exception); if (shear_image == (Image *) NULL) ThrowImageException3(ResourceLimitError,MemoryAllocationFailed, UnableToShearImage); DestroyImage(integral_image); /* Shear the image. */ shear_image->storage_class=DirectClass; shear_image->matte|=shear_image->background_color.opacity != OpaqueOpacity; XShearImage(shear_image,shear.x,image->columns,image->rows,x_offset, (long) (shear_image->rows-image->rows)/2); YShearImage(shear_image,shear.y,y_width,image->rows, (long) (shear_image->columns-y_width)/2,y_offset); CropToFitImage(&shear_image,shear.x,shear.y,image->columns,image->rows, False,exception); shear_image->page.width=0; shear_image->page.height=0; return(shear_image); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % R o t a t e I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % RotateImage() creates a new image that is a rotated copy of an existing % one. Positive angles rotate counter-clockwise (right-hand rule), while % negative angles rotate clockwise. Rotated images are usually larger than % the originals and have 'empty' triangular corners. X axis. Empty % triangles left over from shearing the image are filled with the background % color defined by member 'background_color' of the image. RotateImage % allocates the memory necessary for the new Image structure and returns a % pointer to the new image. % % RotateImage() is based on the paper "A Fast Algorithm for General % Raster Rotatation" by Alan W. Paeth. RotateImage is adapted from a similar % method based on the Paeth paper written by Michael Halle of the Spatial % Imaging Group, MIT Media Lab. % % The format of the RotateImage method is: % % Image *RotateImage(const Image *image,const double degrees, % ExceptionInfo *exception) % % A description of each parameter follows. % % o image: the image. % % o degrees: Specifies the number of degrees to rotate the image. % % o exception: Return any errors or warnings in this structure. % % */ MagickExport Image *RotateImage(const Image *image,const double degrees, ExceptionInfo *exception) { Image *integral_image, *rotate_image; long x_offset, y_offset; MagickRealType angle; PointInfo shear; RectangleInfo border_info; unsigned long height, rotations, width, y_width; /* Adjust rotation angle. */ assert(image != (Image *) NULL); assert(image->signature == MagickSignature); if (image->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); assert(exception != (ExceptionInfo *) NULL); assert(exception->signature == MagickSignature); angle=degrees; while (angle < -45.0) angle+=360.0; for (rotations=0; angle > 45.0; rotations++) angle-=90.0; rotations%=4; /* Calculate shear equations. */ integral_image=IntegralRotateImage(image,rotations,exception); if (integral_image == (Image *) NULL) ThrowImageException(ResourceLimitError,"MemoryAllocationFailed"); shear.x=(-tan((double) DegreesToRadians(angle)/2.0)); shear.y=sin((double) DegreesToRadians(angle)); if ((shear.x == 0.0) && (shear.y == 0.0)) return(integral_image); if (SetImageStorageClass(integral_image,DirectClass) == MagickFalse) { InheritException(exception,&integral_image->exception); integral_image=DestroyImage(integral_image); return(integral_image); } if (integral_image->matte == MagickFalse) (void) SetImageOpacity(integral_image,OpaqueOpacity); /* Compute image size. */ width=image->columns; height=image->rows; if ((rotations == 1) || (rotations == 3)) { width=image->rows; height=image->columns; } y_width=width+(long) (fabs(shear.x)*height+0.5); x_offset=(long) (width+((fabs(shear.y)*height+0.5)-width)/2.0+0.5); y_offset=(long) (height+((fabs(shear.y)*y_width+0.5)-height)/2.0+0.5); /* Surround image with a border. */ integral_image->border_color=integral_image->background_color; integral_image->compose=CopyCompositeOp; border_info.width=(unsigned long) x_offset; border_info.height=(unsigned long) y_offset; rotate_image=BorderImage(integral_image,&border_info,exception); integral_image=DestroyImage(integral_image); if (rotate_image == (Image *) NULL) ThrowImageException(ResourceLimitError,"MemoryAllocationFailed"); /* Rotate the image. */ XShearImage(rotate_image,shear.x,width,height,x_offset, ((long) rotate_image->rows-height)/2); YShearImage(rotate_image,shear.y,y_width,height, ((long) rotate_image->columns-y_width)/2,y_offset); XShearImage(rotate_image,shear.x,y_width,rotate_image->rows, ((long) rotate_image->columns-y_width)/2,0); CropToFitImage(&rotate_image,shear.x,shear.y,(MagickRealType) width, (MagickRealType) height,MagickTrue,exception); rotate_image->compose=image->compose; rotate_image->page.width=0; rotate_image->page.height=0; return(rotate_image); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % R o t a t e I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Method RotateImage creates a new image that is a rotated copy of an % existing one. Positive angles rotate counter-clockwise (right-hand rule), % while negative angles rotate clockwise. Rotated images are usually larger % than the originals and have 'empty' triangular corners. X axis. Empty % triangles left over from shearing the image are filled with the color % specified by the image background_color. RotateImage allocates the memory % necessary for the new Image structure and returns a pointer to the new % image. % % Method RotateImage is based on the paper "A Fast Algorithm for General % Raster Rotatation" by Alan W. Paeth. RotateImage is adapted from a similar % method based on the Paeth paper written by Michael Halle of the Spatial % Imaging Group, MIT Media Lab. % % The format of the RotateImage method is: % % Image *RotateImage(const Image *image,const double degrees, % ExceptionInfo *exception) % % A description of each parameter follows. % % o status: Method RotateImage returns a pointer to the image after % rotating. A null image is returned if there is a memory shortage. % % o image: The image; returned from % ReadImage. % % o degrees: Specifies the number of degrees to rotate the image. % % o exception: Return any errors or warnings in this structure. % % */ MagickExport Image *RotateImage(const Image *image,const double degrees, ExceptionInfo *exception) { double angle; Image *integral_image, *rotate_image; long x_offset, y_offset; PointInfo shear; RectangleInfo border_info; unsigned long height, rotations, width, y_width; /* Adjust rotation angle. */ assert(image != (Image *) NULL); assert(image->signature == MagickSignature); assert(exception != (ExceptionInfo *) NULL); assert(exception->signature == MagickSignature); angle=degrees; while (angle < -45.0) angle+=360.0; for (rotations=0; angle > 45.0; rotations++) angle-=90.0; rotations%=4; /* Calculate shear equations. */ integral_image=IntegralRotateImage(image,rotations,exception); if (integral_image == (Image *) NULL) ThrowImageException3(ResourceLimitError,MemoryAllocationFailed, UnableToRotateImage); shear.x=(-tan(DegreesToRadians(angle)/2.0)); shear.y=sin(DegreesToRadians(angle)); if ((shear.x == 0.0) || (shear.y == 0.0)) return(integral_image); /* Compute image size. */ width=image->columns; height=image->rows; if ((rotations == 1) || (rotations == 3)) { width=image->rows; height=image->columns; } x_offset=(long) ceil(fabs(2.0*height*shear.y)-0.5); y_width=(unsigned long) floor(fabs(height*shear.x)+width+0.5); y_offset=(long) ceil(fabs(y_width*shear.y)-0.5); /* Surround image with a border. */ integral_image->border_color=integral_image->background_color; border_info.width=x_offset; border_info.height=y_offset; rotate_image=BorderImage(integral_image,&border_info,exception); DestroyImage(integral_image); if (rotate_image == (Image *) NULL) ThrowImageException3(ResourceLimitError,MemoryAllocationFailed, UnableToRotateImage); /* Rotate the image. */ rotate_image->storage_class=DirectClass; rotate_image->matte|=rotate_image->background_color.opacity != OpaqueOpacity; XShearImage(rotate_image,shear.x,width,height,x_offset, (long) (rotate_image->rows-height)/2); YShearImage(rotate_image,shear.y,y_width,height, (long) (rotate_image->columns-y_width)/2,y_offset); XShearImage(rotate_image,shear.x,y_width,rotate_image->rows, (long) (rotate_image->columns-y_width)/2,0); CropToFitImage(&rotate_image,shear.x,shear.y,width,height,True,exception); rotate_image->page.width=0; rotate_image->page.height=0; return(rotate_image); }