How Can I Rotate A UIImage and Image Data By 90 Degrees
Asked Answered
A

6

6

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 user can click to rotate the UIImageView and also rotate the UImage within the view so that when the image is saved it keeps the new rotation.

At the minute I have

- (IBAction)rotateImage:(id)sender {

float degrees = 90; //the value in degrees
self.imagePreview.transform = CGAffineTransformMakeRotation(degrees * M_PI/180);

}

Can someone point me in the right direction regarding keeping the current rotation.

Thanks

Allanadale answered 28/7, 2013 at 14:31 Comment(2)
If you want the rotation to persist after the image is saved, you should be rotating the UIImage, not the UIImageView.Favour
possible duplicate of How to rotate UIImageLeatherman
A
12

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
  }

}
Alic answered 28/7, 2013 at 14:46 Comment(4)
why is this switching the images direction?Natasha
For 180 degrees, this flips the image.Contempt
@Contempt It's not the same rotating 180 degrees (upside down), than flipping it (front side back).Reareace
Looks like Objective-C code had issue with applying scale. Now it should be fixed.Alic
A
5

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;
}
Arenas answered 23/4, 2015 at 14:56 Comment(1)
This works perfectly, however I replaced CGFloat radians = DegreesToRadians(degrees); with CGFloat radians = degrees * (M_PI / 180.0); for a bit more of a 'contained' solutionRenayrenckens
D
2

In Swift 4

imageView.transform = CGAffineTransform(rotationAngle: CGFloat(Double.pi/2))

Donndonna answered 29/1, 2019 at 6:51 Comment(0)
M
1

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
    }
}
Milliary answered 17/6, 2016 at 16:9 Comment(0)
E
0

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
  }
Enumeration answered 20/12, 2018 at 22:47 Comment(1)
I was getting an increase in image size after rotation, so I've to add this: let rotatedSize = rotatedViewBox.frame.size; let roundedSize = CGSize(width: Int(rotatedSize.width), height: Int(rotatedSize.height)); UIGraphicsBeginImageContextWithOptions(roundedSize, false, self.scale);Enumeration
N
-1

self.imageview.transform = CGAffineTransformMakeRotation(M_PI/2);

Neume answered 28/7, 2013 at 14:37 Comment(3)
This is equivalent to what the OP has already done seeing as 90 * pi / 180 is equal to M_PI/2.Favour
Or the M_PI_2 constantTaraxacum
This doesn't rotate the image data itselfYoumans

© 2022 - 2024 — McMap. All rights reserved.