Hanushka Suren
Hanushka Suren

Reputation: 793

Issue in rotating UIImage - IOS/Swift

For rotating an UIImage I used an extension which is downloaded from the internet. There, rotating is working but there are some wired behaviours.

This is the extension code

import UIKit

extension UIImage {

    public func imageRotatedByDegrees(degrees: CGFloat, flip: Bool) -> UIImage {

        let radiansToDegrees: (CGFloat) -> CGFloat = {
            return $0 * (180.0 / CGFloat(M_PI));
        }
        let degreesToRadians: (CGFloat) -> CGFloat = {
            return $0 / 180.0 * CGFloat(M_PI);
        }

        // calculate the size of the rotated view's containing box for our drawing space
        let rotatedViewBox = UIView(frame: CGRect(origin: CGPointZero, size: size));
        let t = CGAffineTransformMakeRotation(degreesToRadians(degrees));
        rotatedViewBox.transform = t;
        let rotatedSize = rotatedViewBox.frame.size

        // Create the bitmap context
        UIGraphicsBeginImageContext(rotatedSize);
        let bitmap = UIGraphicsGetCurrentContext();

        // Move the origin to the middle of the image so we will rotate and scale around the center.
        CGContextTranslateCTM(bitmap, rotatedSize.width / 2.0, rotatedSize.height / 2.0);

        // Rotate the image context
        CGContextRotateCTM(bitmap, degreesToRadians(degrees));

        // Now, draw the rotated/scaled image into the context
        var yFlip: CGFloat;

        if(flip){
            yFlip = CGFloat(-1.0);
        } else {
            yFlip = CGFloat(1.0);
        }

        CGContextScaleCTM(bitmap, yFlip, -1.0);
        CGContextDrawImage(bitmap, CGRectMake(-size.width / 2, -size.height / 2, size.width, size.height), CGImage);

        let newImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();

        return newImage;
    }
}

This is how I call extension method and set returned image to the image view. image view's 'contentMode' property is set to 'Scale to Fill'

currentPagePreviewImageVew.image = currentPagePreviewImageVew.image!.imageRotatedByDegrees(90, flip: false);

This is how it looks before pressing rotate button

enter image description here

This is after pressing rotate button once.(See image is not rotated but it's size has been changed)

enter image description here

This is when the image rotation is 90 degrees.(Here after image is rotating but as you can see the other views get stretched when image is in 0 and 180 degrees as in the above screen(2))

enter image description here

Can some one please tell me what is wrong with my code and if there is a better solution please let me know. Any help would be highly appreciated.

Edited: Stretching views was because of an constraint issue. I got it solved by putting a height constraint to the tool bar above the imageview. But still couldn't find an answer for that first time thing.

Upvotes: 4

Views: 1975

Answers (3)

Hanushka Suren
Hanushka Suren

Reputation: 793

I used below extension and it worked fine. This is swift 3 actually.

import UIKit

extension UIImage {

    public func rotateImageByDegrees(_ degrees: CGFloat) -> UIImage {

        let degreesToRadians: (CGFloat) -> CGFloat = {
            return $0 / 180.0 * CGFloat(M_PI)
        }

        // calculate the size of the rotated view's containing box for our drawing space
        let rotatedViewBox = UIView(frame: CGRect(origin: CGPoint.zero, size: self.size))
        let t = CGAffineTransform(rotationAngle: degreesToRadians(degrees));
        rotatedViewBox.transform = t
        let rotatedSize = rotatedViewBox.frame.size

        // Create the bitmap context
        UIGraphicsBeginImageContext(rotatedSize)
        let bitmap = 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.0, y: rotatedSize.height / 2.0);

        // Rotate the image context
        bitmap?.rotate(by: degreesToRadians(degrees));

        // Now, draw the rotated/scaled image into the context
        bitmap?.scaleBy(x: 1.0, y: -1.0)
        bitmap?.draw(self.cgImage!, in: CGRect(x: -self.size.width / 2, y: -self.size.height / 2, width: self.size.width, height: self.size.height))

        let cgimage:CGImage  = bitmap!.makeImage()!
        return UIImage(cgImage: cgimage)
    }
}

All the other things are same as in the question.

Upvotes: 0

Jayesh Miruliya
Jayesh Miruliya

Reputation: 3317

    func flipImageVertical(originalImage: UIImage) -> UIImage
    {
        let tempImageView:UIImageView = UIImageView(image: originalImage)
        UIGraphicsBeginImageContext(tempImageView.frame.size)
        let context:CGContextRef = UIGraphicsGetCurrentContext()!
        let flipVertical:CGAffineTransform = CGAffineTransformMake(1,0,0,-1,0,tempImageView.frame.size.height)
        CGContextConcatCTM(context, flipVertical)
        tempImageView.layer .renderInContext(context)

        let flippedImage:UIImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return flippedImage
    }

    func flipImageHorizontal(originalImage: UIImage) -> UIImage
    {
        let tempImageView:UIImageView = UIImageView(image: originalImage)
        UIGraphicsBeginImageContext(tempImageView.frame.size)
        let context:CGContextRef = UIGraphicsGetCurrentContext()!
        let flipHorizontal:CGAffineTransform = CGAffineTransformMake(-1,0,0,1,tempImageView.frame.size.width,0)

        CGContextConcatCTM(context, flipHorizontal)
        tempImageView.layer .renderInContext(context)

        let flippedImage:UIImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return flippedImage
    }

Upvotes: 4

Alessandro Ornano
Alessandro Ornano

Reputation: 35392

You must try this:

extension UIImage {
    public func imageRotatedByDegrees(degrees: Double, flip: Bool) -> UIImage {

        // calculate the size of the rotated view's containing box for our drawing space
        let rotatedViewBox = UIView(frame: CGRect(origin: CGPointZero, size: size))
        let t = CGAffineTransformMakeRotation(CGFloat(toRadian(degrees)))
        rotatedViewBox.transform = t
        let rotatedSize = rotatedViewBox.frame.size

        // Create the bitmap context
        UIGraphicsBeginImageContext(rotatedSize)
        let bitmap = UIGraphicsGetCurrentContext()

        CGContextSetAllowsAntialiasing(bitmap, true)
        CGContextSetShouldAntialias(bitmap, true)
        CGContextSetInterpolationQuality(bitmap, CGInterpolationQuality.High)

        // Move the origin to the middle of the image so we will rotate and scale around the center.
        CGContextTranslateCTM(bitmap, rotatedSize.width / 2.0, rotatedSize.height / 2.0)

        //   // Rotate the image context
        CGContextRotateCTM(bitmap, CGFloat(toRadian(degrees)))

        // Now, draw the rotated/scaled image into the context
        var yFlip: CGFloat

        if(flip){
            yFlip = CGFloat(-1.0)
        } else {
            yFlip = CGFloat(1.0)
        }

        CGContextScaleCTM(bitmap, yFlip, -1.0)
        CGContextDrawImage(bitmap, CGRectMake(-size.width / 2, -size.height / 2, size.width, size.height), CGImage)

        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        return newImage
    }

Then use this method to satisfy your new size:

extension UIImage {
    public func resizeImage(newSize:CGSize) -> UIImage {

        let newRect = CGRectIntegral(CGRectMake(0, 0, newSize.width, newSize.height))
        let imageRef:CGImageRef = self.CGImage!

        UIGraphicsBeginImageContextWithOptions(newSize, false, 0)
        let context:CGContextRef = UIGraphicsGetCurrentContext()!

        // Set the quality level to use when rescaling
        CGContextSetInterpolationQuality(context, CGInterpolationQuality.High)
        CGContextSetAllowsAntialiasing(context, true)
        CGContextSetShouldAntialias(context, true)

        let flipVertical:CGAffineTransform = CGAffineTransformMake(1, 0, 0, -1, 0, newSize.height)

        CGContextConcatCTM(context, flipVertical)
        // Draw into the context; this scales the image
        CGContextDrawImage(context, newRect, imageRef)

        // Get the resized image from the context and a UIImage
        let newImage:UIImage = UIImage(CGImage: CGBitmapContextCreateImage(context)!)

        UIGraphicsEndImageContext();
        return newImage
    }
}

Upvotes: 1

Related Questions