简体   繁体   中英

Swift - Image rotation in degrees - deformed result

I found several methods to rotate image by degrees in Swift but noone that works allright all the time. I want to rotate image by 90 degrees left or right. I think the best one is this:

  class func imageRotated(_ oldImage: UIImage, byDegrees degrees: CGFloat) -> UIImage {
    //Calculate the size of the rotated view's containing box for our drawing space
    let rotatedViewBox: UIView = UIView(frame: CGRect(x: 0, y: 0, width: oldImage.size.width, height: oldImage.size.height))
    let t: CGAffineTransform = CGAffineTransform(rotationAngle: degrees * CGFloat(M_PI / 180))
    rotatedViewBox.transform = t
    let rotatedSize: CGSize = rotatedViewBox.frame.size
    //Create the bitmap context
    UIGraphicsBeginImageContext(rotatedSize)
    let bitmap: CGContext = UIGraphicsGetCurrentContext()!
    //Move the origin to the middle of the image so we will rotate and scale around the center.
    bitmap.translateBy(x: rotatedSize.width / 2, y: rotatedSize.height / 2)
    //Rotate the image context
    bitmap.rotate(by: (degrees * CGFloat(M_PI / 180)))
    //Now, draw the rotated/scaled image into the context
    bitmap.scaleBy(x: 1.0, y: -1.0)
    bitmap.draw(oldImage.cgImage!, in: CGRect(x: -oldImage.size.width / 2, y: -oldImage.size.height / 2, width: oldImage.size.width, height: oldImage.size.height))
    let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
    UIGraphicsEndImageContext()
    return newImage
  }

It works and do what I want but there are few times when it deformes result so it's not rotated and just image size is changed or it's rotated by 180 degrees and image size is changed.

Before rotation:

旋转前的图像

Afteer rotation (menu is missing because it's automatically hidden):

旋转后的图像

What's weird is that this happens when I take photo in portrait. When I take photo in landscape the rotation works fine (even if I try to rotate several times and even if I rotate from landscape to portrait and than again to landscape, it's still works fine).

I saw some discussion about auto layout constraints problem but I am not sure if it's my problem and why it would for some cases work and for some won't. I have photos in collection cells and each cell has first UIScrollView and than in UIScrollView there is UIImageView with photo. All constraints are set to bounds.

If it helps I want only rotate by 90 or -90 degrees. This could maybe make method more simple andn fix easier.

Thanks for any help.

Actually the easiest and probably the best way is to create a view, put an image view on it, rotate the image view, resize the superview and create a screenshot of that view.

You do not actually add these views in the view hierarchy, you just use them to easily generate an image.

Why this is a good procedure is because the UIView already has all the code written in it to fully support the core graphics. So there is no downside at all and you can be sure these procedures have already been polished by Apple.

So try this:

    func transformImage(image: UIImage?, transform: CGAffineTransform) -> UIImage? {

        guard let image = image else {
            return nil
        }

        let view = UIView(frame: CGRect.zero)
        let imageView = UIImageView(image: image)
        imageView.transform = transform
        view.addSubview(imageView)
        imageView.frame.origin = CGPoint.zero
        view.frame = CGRect(x: 0.0, y: 0.0, width: imageView.frame.size.width, height: imageView.frame.size.height)


        UIGraphicsBeginImageContext(view.frame.size)
        view.layer.render(in: UIGraphicsGetCurrentContext()!)
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        if let cgImage = newImage?.cgImage {
            return UIImage(cgImage: cgImage)
        } else {
            return nil
        }

    }

As for issue in your procedure it is most likely because you discard the transform from the UIImage . The CGImage is basically a raw image representation and it has no idea about the rotations. The UIImage does have imageOrientation though. So what you would need to do to fix that is you need to generate the transformation matrix from the image orientation and use it.

So when you take an image with your device the CGImage will always have the same orientation (landscape left or right). But the UIImage will change the image orientation which is then used for representation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM