So here\'s where I\'ve made it so far. I am using a UIImage captured from the camera and can crop the center square when in landscape. For some reason this doesn\'t transl
Solution based on Swift 2 extension. Improvised from @Geoffrey and @Nirav Dangi. Note that we set newCropWidth and newCropHeight to image's width or height when they are lesser than the given width or height.
extension UIImage {
func imageByCroppingImage(size: CGSize) -> UIImage {
let newCropWidth, newCropHeight : CGFloat;
if(self.size.width < self.size.height) {
if (self.size.width < size.width) {
newCropWidth = self.size.width;
}
else {
newCropWidth = size.width;
}
newCropHeight = (newCropWidth * size.height)/size.width;
} else {
if (self.size.height < size.height) {
newCropHeight = self.size.height;
}
else {
newCropHeight = size.height;
}
newCropWidth = (newCropHeight * size.width)/size.height;
}
let x = self.size.width / 2 - newCropWidth / 2;
let y = self.size.height / 2 - newCropHeight / 2;
let cropRect = CGRectMake(x, y, newCropWidth, newCropHeight);
let imageRef = CGImageCreateWithImageInRect(self.CGImage, cropRect);
let croppedImage : UIImage = UIImage(CGImage: imageRef!, scale: 0, orientation: self.imageOrientation);
return croppedImage;
}
}
There is the swift version for the checked solution :
private func imageByCroppingImage(image : UIImage, size : CGSize) -> UIImage{
var refWidth : CGFloat = CGFloat(CGImageGetWidth(image.CGImage))
var refHeight : CGFloat = CGFloat(CGImageGetHeight(image.CGImage))
var x = (refWidth - size.width) / 2
var y = (refHeight - size.height) / 2
let cropRect = CGRectMake(x, y, size.height, size.width)
let imageRef = CGImageCreateWithImageInRect(image.CGImage, cropRect)
let cropped : UIImage = UIImage(CGImage: imageRef, scale: 0, orientation: image.imageOrientation)!
return cropped
}
This works with different orientations. Both portrait and landscape orientations works correctly.
- (UIImage *)imageByCroppingImage:(UIImage *)image toSize:(CGSize)size
{
// not equivalent to image.size (which depends on the imageOrientation)!
double refWidth = CGImageGetWidth(image.CGImage);
double refHeight = CGImageGetHeight(image.CGImage);
double x = (refWidth - size.width) / 2.0;
double y = (refHeight - size.height) / 2.0;
CGRect cropRect = CGRectMake(x, y, size.height, size.width);
CGImageRef imageRef = CGImageCreateWithImageInRect([image CGImage], cropRect);
UIImage *cropped = [UIImage imageWithCGImage:imageRef scale:0.0 orientation:self.imageOrientation];
CGImageRelease(imageRef);
return cropped;
}
func cropImage() -> UIImage? {
let size = min(self.size.width, self.size.height)
UIGraphicsBeginImageContextWithOptions(CGSize(width: size, height: size), true, 1.0)
defer { UIGraphicsEndImageContext() }
self.draw(in: CGRect(x: (size - self.size.width) / 2.0,
y: (size - self.size.height) / 2.0,
width: self.size.width,
height: self.size.height))
return UIGraphicsGetImageFromCurrentImageContext()
}
Here is the Swift 5 version of cropping the image according to given size from center.
extension UIImage {
func imageByCroppingImage(size : CGSize) -> UIImage{
let refWidth : CGFloat = CGFloat(self.cgImage!.width)
let refHeight : CGFloat = CGFloat(self.cgImage!.height)
let x = (refWidth - size.width) / 2
let y = (refHeight - size.height) / 2
let cropRect = CGRect(x: x, y: y, width: size.width, height: size.height)
let imageRef = self.cgImage!.cropping(to: cropRect)
let cropped : UIImage = UIImage(cgImage: imageRef!, scale: 0, orientation: self.imageOrientation)
return cropped
}
}
This is an old question, but none of the answers are really correct (even the accepted answer). The important thing to understand is that UIImageOrientation
(image.imageOrientation
) is actually correct, but it's definition of UP and our definition of UP are different. For us, UP is the top of the device (where the power button is). For UIImageOrientation
, UP is the side opposite of the volume control buttons. So if the device takes a picture with the volume controls down, this is UIImageOrientationUp
. If you take a picture in portrait mode (with the home button down), this is UIImageOrientationLeft
.
So you can calculate the center in portrait, then you can apply the following transform to the image so that the crop is in the correct place.
- (UIImage *)cropImage:(UIImage*)image toRect:(CGRect)rect {
CGFloat (^rad)(CGFloat) = ^CGFloat(CGFloat deg) {
return deg / 180.0f * (CGFloat) M_PI;
};
// determine the orientation of the image and apply a transformation to the crop rectangle to shift it to the correct position
CGAffineTransform rectTransform;
switch (image.imageOrientation) {
case UIImageOrientationLeft:
rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(rad(90)), 0, -image.size.height);
break;
case UIImageOrientationRight:
rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(rad(-90)), -image.size.width, 0);
break;
case UIImageOrientationDown:
rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(rad(-180)), -image.size.width, -image.size.height);
break;
default:
rectTransform = CGAffineTransformIdentity;
};
// adjust the transformation scale based on the image scale
rectTransform = CGAffineTransformScale(rectTransform, image.scale, image.scale);
// apply the transformation to the rect to create a new, shifted rect
CGRect transformedCropSquare = CGRectApplyAffineTransform(rect, rectTransform);
// use the rect to crop the image
CGImageRef imageRef = CGImageCreateWithImageInRect(image.CGImage, transformedCropSquare);
// create a new UIImage and set the scale and orientation appropriately
UIImage *result = [UIImage imageWithCGImage:imageRef scale:image.scale orientation:image.imageOrientation];
// memory cleanup
CGImageRelease(imageRef);
return result;
}
This code shifts the crop square so that it is in the correct relative position.