iOS UIImagePickerController result image orientation after upload

后端 未结 20 1937
长发绾君心
长发绾君心 2020-11-22 00:44

I am testing my iPhone application on an iOS 3.1.3 iPhone. I am selecting/capturing an image using a UIImagePickerController:

UIImagePickerCont         


        
相关标签:
20条回答
  • 2020-11-22 01:01

    Here's UIImage extension for swift:

    extension UIImage {
    
        func fixOrientation() -> UIImage {
    
            // No-op if the orientation is already correct
            if ( self.imageOrientation == UIImageOrientation.Up ) {
                return self;
            }
    
            // We need to calculate the proper transformation to make the image upright.
            // We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirrored.
            var transform: CGAffineTransform = CGAffineTransformIdentity
    
            if ( self.imageOrientation == UIImageOrientation.Down || self.imageOrientation == UIImageOrientation.DownMirrored ) {
                transform = CGAffineTransformTranslate(transform, self.size.width, self.size.height)
                transform = CGAffineTransformRotate(transform, CGFloat(M_PI))
            }
    
            if ( self.imageOrientation == UIImageOrientation.Left || self.imageOrientation == UIImageOrientation.LeftMirrored ) {
                transform = CGAffineTransformTranslate(transform, self.size.width, 0)
                transform = CGAffineTransformRotate(transform, CGFloat(M_PI_2))
            }
    
            if ( self.imageOrientation == UIImageOrientation.Right || self.imageOrientation == UIImageOrientation.RightMirrored ) {
                transform = CGAffineTransformTranslate(transform, 0, self.size.height);
                transform = CGAffineTransformRotate(transform,  CGFloat(-M_PI_2));
            }
    
            if ( self.imageOrientation == UIImageOrientation.UpMirrored || self.imageOrientation == UIImageOrientation.DownMirrored ) {
                transform = CGAffineTransformTranslate(transform, self.size.width, 0)
                transform = CGAffineTransformScale(transform, -1, 1)
            }
    
            if ( self.imageOrientation == UIImageOrientation.LeftMirrored || self.imageOrientation == UIImageOrientation.RightMirrored ) {
                transform = CGAffineTransformTranslate(transform, self.size.height, 0);
                transform = CGAffineTransformScale(transform, -1, 1);
            }
    
            // Now we draw the underlying CGImage into a new context, applying the transform
            // calculated above.
            var ctx: CGContextRef = CGBitmapContextCreate(nil, Int(self.size.width), Int(self.size.height),
                CGImageGetBitsPerComponent(self.CGImage), 0,
                CGImageGetColorSpace(self.CGImage),
                CGImageGetBitmapInfo(self.CGImage));
    
            CGContextConcatCTM(ctx, transform)
    
            if ( self.imageOrientation == UIImageOrientation.Left ||
                self.imageOrientation == UIImageOrientation.LeftMirrored ||
                self.imageOrientation == UIImageOrientation.Right ||
                self.imageOrientation == UIImageOrientation.RightMirrored ) {
                    CGContextDrawImage(ctx, CGRectMake(0,0,self.size.height,self.size.width), self.CGImage)
            } else {
                CGContextDrawImage(ctx, CGRectMake(0,0,self.size.width,self.size.height), self.CGImage)
            }
    
            // And now we just create a new UIImage from the drawing context and return it
            return UIImage(CGImage: CGBitmapContextCreateImage(ctx))!
        }
    }
    

    Based on MetalHeart2003's earlier work..

    0 讨论(0)
  • 2020-11-22 01:02
    @an0, thanks for the answer!
    The only thing is autoreleasepool: 
    
    func fixOrientation(img: UIImage) -> UIImage? {
    
        let result: UIImage?
        if img.imageOrientation == .up {
            result = img
        } else {
    
            result = autoreleasepool { () -> UIImage? in
                UIGraphicsBeginImageContextWithOptions(img.size, false, img.scale)
                let rect = CGRect(x: 0, y: 0, width: img.size.width, height: img.size.height)
                img.draw(in: rect)
    
                let normalizedImage = UIGraphicsGetImageFromCurrentImageContext()
                UIGraphicsEndImageContext()
    
                return normalizedImage
            }
        }
    
        return result
    }
    
    0 讨论(0)
  • 2020-11-22 01:04

    I used this page when designing my app that takes pictures and I found that the following method will correct the orientation and use less memory and processor than previous answers:

    CGImageRef cgRef = image.CGImage;
    image = [[UIImage alloc] initWithCGImage:cgRef scale:1.0 orientation:UIImageOrientationUp];
    

    This basically just rewraps the actual image data with a new orientation. I was using @an0's code but it makes a new image in memory which can be taxing on a 3264x2448 image that you might get from a camera.

    0 讨论(0)
  • 2020-11-22 01:04

    Here’s a solution that doesn’t change the colorspace of the original image. If you want to normalize the orientation of a grayscale image, you are out of luck with all solutions based on UIGraphicsBeginImageContextWithOptions because it creates a context in the RGB colorspace. Instead, you have to create a context with the same properties as the original image and draw:

    extension UIImage {
        static let rotatedOrentations: [UIImage.Orientation] = [.left, .leftMirrored, .right, .rightMirrored]
    
        func normalizedImage() -> UIImage {
            if imageOrientation == .up {
                return self
            }
    
            let image = self.cgImage!
            let swapOrientation = UIImage.rotatedOrentations.contains(imageOrientation)
            let width = swapOrientation ? image.height : image.width
            let height = swapOrientation ? image.width : image.height
            let context = CGContext(data: nil, width: width, height: height, bitsPerComponent: image.bitsPerComponent, bytesPerRow: image.bytesPerRow, space: image.colorSpace!, bitmapInfo: image.bitmapInfo.rawValue)!
            let flipVertical = CGAffineTransform(a: 1, b: 0, c: 0, d: -1, tx: 0, ty: CGFloat(height));
            context.concatenate(flipVertical)
            UIGraphicsPushContext(context)
            self.draw(at: .zero)
            UIGraphicsPopContext()
    
            return UIImage(cgImage: context.makeImage()!)
        }
    }
    
    0 讨论(0)
  • 2020-11-22 01:05

    I figured out a much simpler one:

    - (UIImage *)normalizedImage {
        if (self.imageOrientation == UIImageOrientationUp) return self; 
    
        UIGraphicsBeginImageContextWithOptions(self.size, NO, self.scale);
        [self drawInRect:(CGRect){0, 0, self.size}];
        UIImage *normalizedImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        return normalizedImage;
    }
    

    BTW: @Anomie's code does not take scale into account, so will not work for 2x images.

    0 讨论(0)
  • 2020-11-22 01:06

    Update for Swift 3.1 based on Sourabh Sharma's answer, with code clean up.

    extension UIImage {
        func fixedOrientation() -> UIImage {
            if imageOrientation == .up { return self }
    
            var transform:CGAffineTransform = .identity
            switch imageOrientation {
            case .down, .downMirrored:
                transform = transform.translatedBy(x: size.width, y: size.height).rotated(by: .pi)
            case .left, .leftMirrored:
                transform = transform.translatedBy(x: size.width, y: 0).rotated(by: .pi/2)
            case .right, .rightMirrored:
                transform = transform.translatedBy(x: 0, y: size.height).rotated(by: -.pi/2)
            default: break
            }
    
            switch imageOrientation {
            case .upMirrored, .downMirrored:
                transform = transform.translatedBy(x: size.width, y: 0).scaledBy(x: -1, y: 1)
            case .leftMirrored, .rightMirrored:
                transform = transform.translatedBy(x: size.height, y: 0).scaledBy(x: -1, y: 1)
            default: break
            }
    
            let ctx = CGContext(data: nil, width: Int(size.width), height: Int(size.height),
                                           bitsPerComponent: cgImage!.bitsPerComponent, bytesPerRow: 0,
                                           space: cgImage!.colorSpace!, bitmapInfo: cgImage!.bitmapInfo.rawValue)!
            ctx.concatenate(transform)
    
            switch imageOrientation {
            case .left, .leftMirrored, .right, .rightMirrored:
                ctx.draw(cgImage!, in: CGRect(x: 0, y: 0, width: size.height,height: size.width))
            default:
                ctx.draw(cgImage!, in: CGRect(x: 0, y: 0, width: size.width,height: size.height))
            }
            return UIImage(cgImage: ctx.makeImage()!)
        }
    }
    

    Picker delegate method example:

    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
        guard let originalImage = info[UIImagePickerControllerOriginalImage] as? UIImage else { return }
        let fixedImage = originalImage.fixedOrientation()
        // do your work
    }
    
    0 讨论(0)
提交回复
热议问题