首页 文章

iOS - UIImageView - 如何处理UIImage图像方向

提问于
浏览
71

是否可以设置 UIImageView 来处理图像方向?当我将 UIImageView 设置为方向为RIGHT的图像(它是来自相机胶卷的照片)时,图像会向右旋转,但我想以正确的方向显示它 .

我知道我可以旋转图像数据,但它可以做得更优雅吗?

谢谢

13 回答

  • 2

    Swift 3.1

    func fixImageOrientation(_ image: UIImage)->UIImage {
        UIGraphicsBeginImageContext(image.size)
        image.draw(at: .zero)
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return newImage ?? image
    }
    
  • 42

    如果我明白,你想要做的是忽视UIImage的方向?如果是这样,那么你可以这样做:

    UIImage *originalImage = [... whatever ...];
    
    UIImage *imageToDisplay =
         [UIImage imageWithCGImage:[originalImage CGImage]
                  scale:[originalImage scale]
                  orientation: UIImageOrientationUp];
    

    因此,您创建的新UIImage具有与原始像素数据相同的像素数据(通过其CGImage属性引用),但您指定的方向不会旋转数据 .

  • 23

    您可以完全避免手动进行变换和自我缩放,如本答案_2579901中的an0所示:

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

    UIImage方法sizedrawInRect的文档明确指出它们考虑了方向 .

  • 1

    我将Anomie's answer here中的代码(由suvish valsan复制粘贴)转换为 Swift

    func fixOrientation() -> UIImage {
        if self.imageOrientation == UIImageOrientation.Up {
            return self
        }
    
        var transform = CGAffineTransformIdentity
    
        switch self.imageOrientation {
        case .Down, .DownMirrored:
            transform = CGAffineTransformTranslate(transform, self.size.width, self.size.height)
            transform = CGAffineTransformRotate(transform, CGFloat(M_PI));
    
        case .Left, .LeftMirrored:
            transform = CGAffineTransformTranslate(transform, self.size.width, 0);
            transform = CGAffineTransformRotate(transform, CGFloat(M_PI_2));
    
        case .Right, .RightMirrored:
            transform = CGAffineTransformTranslate(transform, 0, self.size.height);
            transform = CGAffineTransformRotate(transform, CGFloat(-M_PI_2));
    
        case .Up, .UpMirrored:
            break
        }
    
        switch self.imageOrientation {
    
        case .UpMirrored, .DownMirrored:
            transform = CGAffineTransformTranslate(transform, self.size.width, 0)
            transform = CGAffineTransformScale(transform, -1, 1)
    
        case .LeftMirrored, .RightMirrored:
            transform = CGAffineTransformTranslate(transform, self.size.height, 0)
            transform = CGAffineTransformScale(transform, -1, 1);
    
        default:
            break;
        }
    
        // Now we draw the underlying CGImage into a new context, applying the transform
        // calculated above.
        let ctx = CGBitmapContextCreate(
            nil,
            Int(self.size.width),
            Int(self.size.height),
            CGImageGetBitsPerComponent(self.CGImage),
            0,
            CGImageGetColorSpace(self.CGImage),
            UInt32(CGImageGetBitmapInfo(self.CGImage).rawValue)
        )
    
        CGContextConcatCTM(ctx, transform);
    
        switch self.imageOrientation {
        case .Left, .LeftMirrored, .Right, .RightMirrored:
            // Grr...
            CGContextDrawImage(ctx, CGRectMake(0, 0, self.size.height,self.size.width), self.CGImage);
    
        default:
            CGContextDrawImage(ctx, CGRectMake(0, 0, self.size.width,self.size.height), self.CGImage);
            break;
        }
    
        // And now we just create a new UIImage from the drawing context
        let cgimg = CGBitmapContextCreateImage(ctx)
    
        let img = UIImage(CGImage: cgimg!)
    
        return img;
    }
    

    (我用 self 替换了参数 image 的所有出现,因为我的代码是 UIImage 的扩展名) .


    EDIT: Swift 3版本 .

    该方法返回一个可选项,因为许多中间调用可能会失败,我不喜欢使用 ! .

    func fixOrientation() -> UIImage? {
    
        guard let cgImage = self.cgImage else {
            return nil
        }
    
        if self.imageOrientation == UIImageOrientation.up {
            return self
        }
    
        let width  = self.size.width
        let height = self.size.height
    
        var transform = CGAffineTransform.identity
    
        switch self.imageOrientation {
        case .down, .downMirrored:
            transform = transform.translatedBy(x: width, y: height)
            transform = transform.rotated(by: CGFloat.pi)
    
        case .left, .leftMirrored:
            transform = transform.translatedBy(x: width, y: 0)
            transform = transform.rotated(by: 0.5*CGFloat.pi)
    
        case .right, .rightMirrored:
            transform = transform.translatedBy(x: 0, y: height)
            transform = transform.rotated(by: -0.5*CGFloat.pi)
    
        case .up, .upMirrored:
            break
        }
    
        switch self.imageOrientation {
        case .upMirrored, .downMirrored:
            transform = transform.translatedBy(x: width, y: 0)
            transform = transform.scaledBy(x: -1, y: 1)
    
        case .leftMirrored, .rightMirrored:
            transform = transform.translatedBy(x: height, y: 0)
            transform = transform.scaledBy(x: -1, y: 1)
    
        default:
            break;
        }
    
        // Now we draw the underlying CGImage into a new context, applying the transform
        // calculated above.
        guard let colorSpace = cgImage.colorSpace else {
            return nil
        }
    
        guard let context = CGContext(
            data: nil,
            width: Int(width),
            height: Int(height),
            bitsPerComponent: cgImage.bitsPerComponent,
            bytesPerRow: 0,
            space: colorSpace,
            bitmapInfo: UInt32(cgImage.bitmapInfo.rawValue)
            ) else {
                return nil
        }
    
        context.concatenate(transform);
    
        switch self.imageOrientation {
    
        case .left, .leftMirrored, .right, .rightMirrored:
            // Grr...
            context.draw(cgImage, in: CGRect(x: 0, y: 0, width: height, height: width))
    
        default:
            context.draw(cgImage, in: CGRect(x: 0, y: 0, width: width, height: height))
        }
    
        // And now we just create a new UIImage from the drawing context
        guard let newCGImg = context.makeImage() else {
            return nil
        }
    
        let img = UIImage(cgImage: newCGImg)
    
        return img;
    }
    

    (注意:Swift 3版本颂歌在Xcode 8.1下编译,但尚未测试它实际上有效 . 可能在某处有拼写错误,混合宽度/高度等 . 随意指出/修复任何错误) .

  • 8

    此方法首先检查UIImage的当前方向,然后以顺时针方式更改方向并返回UIImage . 您可以将此图像显示为

    self.imageView.image = rotateImage(currentUIImage)

    func rotateImage(image:UIImage)->UIImage
        {
            var rotatedImage = UIImage();
            switch image.imageOrientation
            {
                case UIImageOrientation.Right:
                rotatedImage = UIImage(CGImage:image.CGImage!, scale: 1, orientation:UIImageOrientation.Down);
    
               case UIImageOrientation.Down:
                rotatedImage = UIImage(CGImage:image.CGImage!, scale: 1, orientation:UIImageOrientation.Left);
    
                case UIImageOrientation.Left:
                rotatedImage = UIImage(CGImage:image.CGImage!, scale: 1, orientation:UIImageOrientation.Up);
    
                 default:
                rotatedImage = UIImage(CGImage:image.CGImage!, scale: 1, orientation:UIImageOrientation.Right);
            }
            return rotatedImage;
        }
    

    Swift 4版

    func rotateImage(image:UIImage) -> UIImage
        {
            var rotatedImage = UIImage()
            switch image.imageOrientation
            {
            case .right:
                rotatedImage = UIImage(cgImage: image.cgImage!, scale: 1.0, orientation: .down)
    
            case .down:
                rotatedImage = UIImage(cgImage: image.cgImage!, scale: 1.0, orientation: .left)
    
            case .left:
                rotatedImage = UIImage(cgImage: image.cgImage!, scale: 1.0, orientation: .up)
    
            default:
                rotatedImage = UIImage(cgImage: image.cgImage!, scale: 1.0, orientation: .right)
            }
    
            return rotatedImage
        }
    
  • 6

    这是一个可行的样本鳕鱼,考虑到图像方向:

    #define rad(angle) ((angle) / 180.0 * M_PI)
    - (CGAffineTransform)orientationTransformedRectOfImage:(UIImage *)img
    {
        CGAffineTransform rectTransform;
        switch (img.imageOrientation)
        {
            case UIImageOrientationLeft:
                rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(rad(90)), 0, -img.size.height);
                break;
            case UIImageOrientationRight:
                rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(rad(-90)), -img.size.width, 0);
                break;
            case UIImageOrientationDown:
                rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(rad(-180)), -img.size.width, -img.size.height);
                break;
            default:
                rectTransform = CGAffineTransformIdentity;
        };
    
        return CGAffineTransformScale(rectTransform, img.scale, img.scale);
    }
    
    
    - (UIImage *)croppedImage:(UIImage*)orignialImage InRect:(CGRect)visibleRect{
        //transform visible rect to image orientation
        CGAffineTransform rectTransform = [self orientationTransformedRectOfImage:orignialImage];
        visibleRect = CGRectApplyAffineTransform(visibleRect, rectTransform);
    
        //crop image
        CGImageRef imageRef = CGImageCreateWithImageInRect([orignialImage CGImage], visibleRect);
        UIImage *result = [UIImage imageWithCGImage:imageRef scale:orignialImage.scale orientation:orignialImage.imageOrientation];
        CGImageRelease(imageRef);
        return result;
    }
    
  • 7

    Swift中的UIImage扩展 . 你根本不需要做任何翻转,真的 . Objective-C original is here,但我添加了一个尊重原始图像的alpha的位(粗略地说,但它可以区分不透明图像和透明图像) .

    // from https://github.com/mbcharbonneau/UIImage-Categories/blob/master/UIImage%2BAlpha.m
    // Returns true if the image has an alpha layer
        private func hasAlpha() -> Bool {
            guard let cg = self.cgImage else { return false }
            let alpha = cg.alphaInfo
            let retVal = (alpha == .first || alpha == .last || alpha == .premultipliedFirst || alpha == .premultipliedLast)
            return retVal
        }
    
        func normalizedImage() -> UIImage? {
            if self.imageOrientation == .up {
                return self
            }
            UIGraphicsBeginImageContextWithOptions(self.size, !self.hasAlpha(), self.scale)
            var rect = CGRect.zero
            rect.size = self.size
            self.draw(in: rect)
            let retVal = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
            return retVal
        }
    
  • 12

    我将代码从@Nicolas Miari的答案转换为Swift 3,万一有人需要它

    func fixOrientation() -> UIImage
    {
    
        if self.imageOrientation == UIImageOrientation.up {
            return self
        }
    
        var transform = CGAffineTransform.identity
    
        switch self.imageOrientation {
        case .down, .downMirrored:
            transform = transform.translatedBy(x: self.size.width, y: self.size.height)
            transform = transform.rotated(by: CGFloat(M_PI));
    
        case .left, .leftMirrored:
            transform = transform.translatedBy(x: self.size.width, y: 0);
            transform = transform.rotated(by: CGFloat(M_PI_2));
    
        case .right, .rightMirrored:
            transform = transform.translatedBy(x: 0, y: self.size.height);
            transform = transform.rotated(by: CGFloat(-M_PI_2));
    
        case .up, .upMirrored:
            break
        }
    
    
        switch self.imageOrientation {
    
        case .upMirrored, .downMirrored:
            transform = transform.translatedBy(x: self.size.width, y: 0)
            transform = transform.scaledBy(x: -1, y: 1)
    
        case .leftMirrored, .rightMirrored:
            transform = transform.translatedBy(x: self.size.height, y: 0)
            transform = transform.scaledBy(x: -1, y: 1);
    
        default:
            break;
        }
    
        // Now we draw the underlying CGImage into a new context, applying the transform
        // calculated above.
        let ctx = CGContext(
            data: nil,
            width: Int(self.size.width),
            height: Int(self.size.height),
            bitsPerComponent: self.cgImage!.bitsPerComponent,
            bytesPerRow: 0,
            space: self.cgImage!.colorSpace!,
            bitmapInfo: UInt32(self.cgImage!.bitmapInfo.rawValue)
        )
    
    
    
        ctx!.concatenate(transform);
    
        switch self.imageOrientation {
    
        case .left, .leftMirrored, .right, .rightMirrored:
            // Grr...
            ctx?.draw(self.cgImage!, in: CGRect(x:0 ,y: 0 ,width: self.size.height ,height:self.size.width))
    
        default:
            ctx?.draw(self.cgImage!, in: CGRect(x:0 ,y: 0 ,width: self.size.width ,height:self.size.height))
            break;
        }
    
        // And now we just create a new UIImage from the drawing context
        let cgimg = ctx!.makeImage()
    
        let img = UIImage(cgImage: cgimg!)
    
        return img;
    
    }
    
  • 132

    感谢Waseem05的Swift 3翻译,但是当我将它包装在UIImage的扩展中并将其放在父类的外部/下方时,他的方法只适用于我:

    extension UIImage {
    
            func fixOrientation() -> UIImage
            {
    
                if self.imageOrientation == UIImageOrientation.up {
                return self
            }
    
            var transform = CGAffineTransform.identity
    
            switch self.imageOrientation {
            case .down, .downMirrored:
                transform = transform.translatedBy(x: self.size.width, y: self.size.height)
                transform = transform.rotated(by: CGFloat(M_PI));
    
            case .left, .leftMirrored:
                transform = transform.translatedBy(x: self.size.width, y: 0);
                transform = transform.rotated(by: CGFloat(M_PI_2));
    
            case .right, .rightMirrored:
                transform = transform.translatedBy(x: 0, y: self.size.height);
                transform = transform.rotated(by: CGFloat(-M_PI_2));
    
            case .up, .upMirrored:
                break
            }
    
    
            switch self.imageOrientation {
    
            case .upMirrored, .downMirrored:
                transform = transform.translatedBy(x: self.size.width, y: 0)
                transform = transform.scaledBy(x: -1, y: 1)
    
            case .leftMirrored, .rightMirrored:
                transform = transform.translatedBy(x: self.size.height, y: 0)
                transform = transform.scaledBy(x: -1, y: 1);
    
            default:
                break;
            }
    
            // Now we draw the underlying CGImage into a new context, applying the transform
            // calculated above.
            let ctx = CGContext(
                data: nil,
                width: Int(self.size.width),
                height: Int(self.size.height),
                bitsPerComponent: self.cgImage!.bitsPerComponent,
                bytesPerRow: 0,
                space: self.cgImage!.colorSpace!,
                bitmapInfo: UInt32(self.cgImage!.bitmapInfo.rawValue)
            )
    
    
    
            ctx!.concatenate(transform);
    
            switch self.imageOrientation {
    
            case .left, .leftMirrored, .right, .rightMirrored:
                // Grr...
                ctx?.draw(self.cgImage!, in: CGRect(x:0 ,y: 0 ,width: self.size.height ,height:self.size.width))
    
            default:
                ctx?.draw(self.cgImage!, in: CGRect(x:0 ,y: 0 ,width: self.size.width ,height:self.size.height))
                break;
            }
    
            // And now we just create a new UIImage from the drawing context
            let cgimg = ctx!.makeImage()
    
            let img = UIImage(cgImage: cgimg!)
    
            return img;
    
        }
    }
    

    然后调用它:

    let correctedImage:UIImage = wonkyImage.fixOrientation()
    

    一切都很顺利!当我们不需要前/后摄像头和上/下/左/右设备方向元数据时,Apple应该更容易丢弃方向 .

  • 18

    如果您需要旋转并固定下方的图像方向,则扩展将非常有用 .

    extension UIImage {
    
    public func imageRotatedByDegrees(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: self.size.width, height: self.size.height))
        let t: CGAffineTransform = CGAffineTransform(rotationAngle: degrees * CGFloat.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.pi / 180))
        //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 newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()
        return newImage
    }
    
    
    public func fixedOrientation() -> UIImage {
        if imageOrientation == UIImageOrientation.up {
            return self
        }
    
        var transform: CGAffineTransform = CGAffineTransform.identity
    
        switch imageOrientation {
        case UIImageOrientation.down, UIImageOrientation.downMirrored:
            transform = transform.translatedBy(x: size.width, y: size.height)
            transform = transform.rotated(by: CGFloat.pi)
            break
        case UIImageOrientation.left, UIImageOrientation.leftMirrored:
            transform = transform.translatedBy(x: size.width, y: 0)
            transform = transform.rotated(by: CGFloat.pi/2)
            break
        case UIImageOrientation.right, UIImageOrientation.rightMirrored:
            transform = transform.translatedBy(x: 0, y: size.height)
            transform = transform.rotated(by: -CGFloat.pi/2)
            break
        case UIImageOrientation.up, UIImageOrientation.upMirrored:
            break
        }
    
        switch imageOrientation {
        case UIImageOrientation.upMirrored, UIImageOrientation.downMirrored:
            transform.translatedBy(x: size.width, y: 0)
            transform.scaledBy(x: -1, y: 1)
            break
        case UIImageOrientation.leftMirrored, UIImageOrientation.rightMirrored:
            transform.translatedBy(x: size.height, y: 0)
            transform.scaledBy(x: -1, y: 1)
        case UIImageOrientation.up, UIImageOrientation.down, UIImageOrientation.left, UIImageOrientation.right:
            break
        }
    
        let ctx: CGContext = CGContext(data: nil,
                                       width: Int(size.width),
                                       height: Int(size.height),
                                       bitsPerComponent: self.cgImage!.bitsPerComponent,
                                       bytesPerRow: 0,
                                       space: self.cgImage!.colorSpace!,
                                       bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)!
    
        ctx.concatenate(transform)
    
        switch imageOrientation {
        case UIImageOrientation.left, UIImageOrientation.leftMirrored, UIImageOrientation.right, UIImageOrientation.rightMirrored:
            ctx.draw(self.cgImage!, in: CGRect(x: 0, y: 0, width: size.height, height: size.width))
        default:
            ctx.draw(self.cgImage!, in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
            break
        }
    
        let cgImage: CGImage = ctx.makeImage()!
    
        return UIImage(cgImage: cgImage)
    }
    

    }

  • 3

    Swift 3.0版的Tommy的回答

    let imageToDisplay = UIImage.init(cgImage: originalImage.cgImage!, scale: originalImage.scale, orientation: UIImageOrientation.up)
    
  • 1
    extension UIImage {
        func fixImageOrientation() -> UIImage {
            UIGraphicsBeginImageContext(self.size)
            self.draw(at: .zero)
            let newImage = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
            return newImage ?? self
        }
    }
    
    • 像顶部示例一样创建扩展 .

    • 称之为: imageView.image?.fixImageOrientation()UIImage(named: "someImage").fixImageOrientation()

    • 祝你好运!

  • 0

    灵感来自@Aqua答案......

    in Objective C

    - (UIImage *)fixImageOrientation:(UIImage *)img {
    
       UIGraphicsBeginImageContext(img.size);
       [img drawAtPoint:CGPointZero];
    
       UIImage *newImg = UIGraphicsGetImageFromCurrentImageContext();
       UIGraphicsEndImageContext();
    
       if (newImg) {
           return newImg;
       }
    
       return img;
    }
    

相关问题