I have a UIImageView that contains an image. At the minute the user can click to save the image within the UIImageView to disk.
I would like to make it so that the the
I have such code in my old app. But this code can be simplified because you have no need to rotate it on non-90 degrees angle.
Objective-C
@implementation UIImage (Rotation)
- (UIImage *)imageRotatedOnDegrees:(CGFloat)degrees
{
// Follow ing code can only rotate images on 90, 180, 270.. degrees.
CGFloat roundedDegrees = (CGFloat)(round(degrees / 90.0) * 90.0);
BOOL sameOrientationType = ((NSInteger)roundedDegrees) % 180 == 0;
CGFloat radians = M_PI * roundedDegrees / 180.0;
CGSize newSize = sameOrientationType ? self.size : CGSizeMake(self.size.height, self.size.width);
UIGraphicsBeginImageContext(newSize);
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGImageRef cgImage = self.CGImage;
if (ctx == NULL || cgImage == NULL) {
UIGraphicsEndImageContext();
return self;
}
CGContextTranslateCTM(ctx, newSize.width / 2.0, newSize.height / 2.0);
CGContextRotateCTM(ctx, radians);
CGContextScaleCTM(ctx, 1, -1);
CGPoint origin = CGPointMake(-(self.size.width / 2.0), -(self.size.height / 2.0));
CGRect rect = CGRectZero;
rect.origin = origin;
rect.size = self.size;
CGContextDrawImage(ctx, rect, cgImage);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image ?: self;
}
@end
Swift
extension UIImage {
func imageRotated(on degrees: CGFloat) -> UIImage {
// Following code can only rotate images on 90, 180, 270.. degrees.
let degrees = round(degrees / 90) * 90
let sameOrientationType = Int(degrees) % 180 == 0
let radians = CGFloat.pi * degrees / CGFloat(180)
let newSize = sameOrientationType ? size : CGSize(width: size.height, height: size.width)
UIGraphicsBeginImageContext(newSize)
defer {
UIGraphicsEndImageContext()
}
guard let ctx = UIGraphicsGetCurrentContext(), let cgImage = cgImage else {
return self
}
ctx.translateBy(x: newSize.width / 2, y: newSize.height / 2)
ctx.rotate(by: radians)
ctx.scaleBy(x: 1, y: -1)
let origin = CGPoint(x: -(size.width / 2), y: -(size.height / 2))
let rect = CGRect(origin: origin, size: size)
ctx.draw(cgImage, in: rect)
let image = UIGraphicsGetImageFromCurrentImageContext()
return image ?? self
}
}
The highlighted state of a UIButton did not take the correct orientation of the normal inserted turned image. So I had to redraw the image like @RyanG showed. Here is the Swift 2.2 code for that:
extension UIImage
{
/// Rotate an image by any given radians.
/// Works for 2x and 3x retina as well.
func imageRotatedByDegrees(degrees: Double) -> UIImage
{
let radians = CGFloat(degrees * (M_PI / 180.0))
let rotatedViewBox = UIView(frame: CGRect(origin: CGPointZero, size: self.size))
let t: CGAffineTransform = CGAffineTransformMakeRotation(radians)
rotatedViewBox.transform = t
let rotatedSize = rotatedViewBox.frame.size
UIGraphicsBeginImageContextWithOptions(rotatedSize, false, self.scale)
let bitmap = UIGraphicsGetCurrentContext()
CGContextTranslateCTM(bitmap, rotatedSize.width / 2, rotatedSize.height / 2)
CGContextRotateCTM(bitmap, radians)
CGContextScaleCTM(bitmap, 1.0, -1.0)
CGContextDrawImage(bitmap, CGRect(origin: CGPoint(x: -self.size.width / 2, y: -self.size.height / 2), size: self.size), self.CGImage)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
}
This will rotate an image by any given radians.
Note this works 2x and 3x retina as well
- (UIImage *)imageRotatedByDegrees:(CGFloat)degrees {
CGFloat radians = DegreesToRadians(degrees);
UIView *rotatedViewBox = [[UIView alloc] initWithFrame:CGRectMake(0,0, self.size.width, self.size.height)];
CGAffineTransform t = CGAffineTransformMakeRotation(radians);
rotatedViewBox.transform = t;
CGSize rotatedSize = rotatedViewBox.frame.size;
UIGraphicsBeginImageContextWithOptions(rotatedSize, NO, [[UIScreen mainScreen] scale]);
CGContextRef bitmap = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(bitmap, rotatedSize.width / 2, rotatedSize.height / 2);
CGContextRotateCTM(bitmap, radians);
CGContextScaleCTM(bitmap, 1.0, -1.0);
CGContextDrawImage(bitmap, CGRectMake(-self.size.width / 2, -self.size.height / 2 , self.size.width, self.size.height), self.CGImage );
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
self.imageview.transform = CGAffineTransformMakeRotation(M_PI/2);
In Swift 4
imageView.transform = CGAffineTransform(rotationAngle: CGFloat(Double.pi/2))
Swift version made from answer of @RyanG with some fixes:
func rotated(by degrees: CGFloat) -> UIImage {
let radians : CGFloat = degrees * CGFloat(.pi / 180.0)
let rotatedViewBox = UIView(frame: CGRect(x: 0, y: 0, width: self.size.width, height: self.size.height))
let t = CGAffineTransform(rotationAngle: radians)
rotatedViewBox.transform = t
let rotatedSize = rotatedViewBox.frame.size
UIGraphicsBeginImageContextWithOptions(rotatedSize, false, self.scale)
defer { UIGraphicsEndImageContext() }
guard let bitmap = UIGraphicsGetCurrentContext(), let cgImage = self.cgImage else {
return self
}
bitmap.translateBy(x: rotatedSize.width / 2, y: rotatedSize.height / 2)
bitmap.rotate(by: radians)
bitmap.scaleBy(x: 1.0, y: -1.0)
bitmap.draw(cgImage, in: CGRect(x: -self.size.width / 2, y: -self.size.height / 2, width: self.size.width, height: self.size.height))
guard let newImage = UIGraphicsGetImageFromCurrentImageContext() else {
return self
}
return newImage
}