如何将UIImage和图像数据旋转90度

6
我有一个包含图片的UIImageView。目前用户可以点击保存UIImageView中的图像到磁盘中。
我想让用户能够点击旋转UIImageView并且旋转视图内的UImage,这样当图像被保存时它会保持新的旋转状态。
目前我的实现是:
- (IBAction)rotateImage:(id)sender {

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

}

有人能指点我关于如何保持当前的旋转方向吗。

谢谢


如果您想在保存图像后保持旋转状态,应该旋转UIImage而不是UIImageView。 - Mick MacCallum
可能是重复的问题:如何旋转UIImage - Suma
6个回答

12

我的旧应用中有这段代码。但是,由于你不需要在非90度角上旋转它,所以可以简化这段代码。

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
  }

}

3
为什么这会改变图像的方向? - Esqarrouth
对于180度,这将翻转图像。 - Nate
@Nate,将其旋转180度(倒置)与翻转(正面背面)不是同一回事。 - maganap
似乎 Objective-C 代码在应用缩放时出了问题。现在应该已经修复了。 - Timur Bernikovich

5

这将按任意给定的弧度旋转图像。

请注意,这也适用于2倍和3倍视网膜屏幕。

- (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;
}

1
这个方案完美地运作了,但是我用 CGFloat radians = degrees * (M_PI / 180.0); 替换了 CGFloat radians = DegreesToRadians(degrees);,以获得更加“封闭”的解决方案。 - mylogon

2
在Swift 4中,将图像视图旋转90度的代码是:imageView.transform = CGAffineTransform(rotationAngle: CGFloat(Double.pi/2)),其中"rotationAngle"表示旋转角度。

1

UIButton的高亮状态没有采用正常插入旋转图像的正确方向。因此,我不得不像@RyanG展示的那样重新绘制图像。这是Swift 2.2代码:

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
    }
}

0

基于 @RyanG 的答案进行了一些修正的 Swift 版本:

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
  }

旋转后,我的图像尺寸增加了,所以我不得不添加以下内容:let rotatedSize = rotatedViewBox.frame.size; let roundedSize = CGSize(width: Int(rotatedSize.width), height: Int(rotatedSize.height)); UIGraphicsBeginImageContextWithOptions(roundedSize, false, self.scale); - Alexander M.

-1

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

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


这相当于OP已经完成的操作,因为90 * pi / 180等于M_PI/2。 - Mick MacCallum
或者是 M_PI_2 常量。 - Sam Soffes
这并不会旋转图像数据本身。 - kompozer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接