在将图像转换为CGImage时丢失图像方向

时间:2015-02-12 13:08:31

标签: ios swift uiimage cgimage

当从矩形原始图像中裁剪图像的正方形部分时,我面临图像方向问题。当图像处于风景中时,它很好。但是当它是纵向时,似乎不保留图像方向,这会导致图像方向错误且裁剪不良:

 func cropImage(cropRectangleCoordinates: CGRect) {

        let croppedImage = originalImage

        let finalCroppedImage : CGImageRef = CGImageCreateWithImageInRect(croppedImage.CGImage, cropRectangleCoordinates)

        finalImage =  UIImage(CGImage: finalCroppedImage)!


    }

我认为问题出在croppedImage.CGImage上。此处图像转换为CGImage,但似乎不保留方向。 仅使用UIImage可以轻松保留方向,但要制作裁剪,图像需要暂时CGImage,这就是问题所在。即使我在转换回UIImage时重定向图像,它也可能处于正确的方向,但在裁剪CGImage时损坏已经完成。

这是一个很快的问题,所以请快速回答,因为Objective-C中的解决方案可能有所不同。

7 个答案:

答案 0 :(得分:12)

SWIFT 3:

通过此方法将旋转的cgImage转换为UIImage

XIB

来源@David Berry回答

答案 1 :(得分:11)

这是我在查看其他人编写的几段旧代码后编写的UIImage扩展。它是用Swift 3编写的,使用iOS方向属性和CGAffineTransform以正确的方向重新绘制图像。

SWIFT 3:

var something2=require('../core/connection.js');
var connectionPool =  something2.something(); //notice here
exports.printHello= function(req, res, next){
    connectionPool.getConnection(function (err, connection) {
        if (err) {
            res.send({
                Error: err,
                Message: "Can't connect Database."
            });
        } else {
            //queries
            connection.query("SELECT * FROM book", function (err, rows, fields) {
                res.send({
                    json: rows
                });
            });
        }
    });
};

答案 2 :(得分:6)

我找到了一个解决方案....时间会告诉它是否足够强大,但它似乎适用于所有情况。这是一个需要修复的恶性错误。

所以问题是UIImage在某些情况下只在转换为CGImage时会丢失它的方向。它会影响人像图像,这些图像会自动进入横向模式。因此,默认情况下的横向图像不受影响。 但是虫子恶毒的地方是它不会影响所有肖像图像!!此外,imageorientation值对某些图像没有帮助。 那些有问题的图像是用户在其库中通过电子邮件,消息或从网络上保存的图像,因此不能使用相机拍摄。这些图像可能没有方向信息,因此在某些情况下,图像处于纵向状态....转换为CGImage时仍保留纵向图像。我真的陷入困境,直到我意识到我的设备库中的一些图像是从消息或电子邮件中保存的。

因此我发现猜测哪个图像将被重定向的唯一可靠方法是创建给定图像的两个版本:UIImage和CGImage,并比较它们的高度值。如果它们相等,那么CGImage版本将不会被旋转,您可以按预期使用它。 但如果它们的高度不同,您可以确定CGImageCreateWithImageInRect的CGImage转换将使图像美化。 仅在这种情况下,我交换原点的x / y坐标,我将其作为矩形坐标传递给裁剪,它正确处理这些特殊图像。

这是一个很长的帖子,但主要的想法是将CGImage高度与UIImage宽度进行比较,如果它们不同,则期望原点被反转。

答案 3 :(得分:5)

将您的UIImage创建调用更改为:

finalImage = UIImage(CGImage:finalCroppedImage, scale:originalImage.scale, orientation:originalImage.orientation)

保持图像的原始方向(和比例)。

答案 4 :(得分:3)

这是答案,归功于@awolf(Cropping an UIImage)。完美地处理比例和方向。只需在要裁剪的图像上调用此方法,然后传递裁剪CGRect,而不必担心缩放或方向。请随意检查cgImage是否为零,而不是像我在这里那样用力展开它。

extension UIImage {
    func croppedInRect(rect: CGRect) -> UIImage {
        func rad(_ degree: Double) -> CGFloat {
            return CGFloat(degree / 180.0 * .pi)
        }

        var rectTransform: CGAffineTransform
        switch imageOrientation {
        case .left:
            rectTransform = CGAffineTransform(rotationAngle: rad(90)).translatedBy(x: 0, y: -self.size.height)
        case .right:
            rectTransform = CGAffineTransform(rotationAngle: rad(-90)).translatedBy(x: -self.size.width, y: 0)
        case .down:
            rectTransform = CGAffineTransform(rotationAngle: rad(-180)).translatedBy(x: -self.size.width, y: -self.size.height)
        default:
            rectTransform = .identity
        }
        rectTransform = rectTransform.scaledBy(x: self.scale, y: self.scale)

        let imageRef = self.cgImage!.cropping(to: rect.applying(rectTransform))
        let result = UIImage(cgImage: imageRef!, scale: self.scale, orientation: self.imageOrientation)
        return result
    }
}

另一个注意事项:如果您使用imageView中嵌入的scrollView,还有一个额外步骤,您必须考虑缩放系数。假设您的imageView跨越scrollView的整个内容视图,并使用scrollView的边界作为裁剪框,则可以获得裁剪后的图像

let ratio = imageView.image!.size.height / scrollView.contentSize.height
let origin = CGPoint(x: scrollView.contentOffset.x * ratio, y: scrollView.contentOffset.y * ratio)
let size = CGSize(width: scrollView.bounds.size.width * ratio, let height: scrollView.bounds.size.height * ratio)
let cropFrame = CGRect(origin: origin, size: size)
let croppedImage = imageView.image!.croppedInRect(rect: cropFrame)

答案 5 :(得分:1)

@JGuo是唯一有效的答案。我只更新了一点点,以返回可选的UIImage?并使用了更快的语法。我宁愿永远不要隐式解包。

extension UIImage {

    func crop(to rect: CGRect) -> UIImage? {
        func rad(_ degree: Double) -> CGFloat {
            return CGFloat(degree / 180.0 * .pi)
        }

        var rectTransform: CGAffineTransform
        switch imageOrientation {
        case .left:
            rectTransform = CGAffineTransform(rotationAngle: rad(90)).translatedBy(x: 0, y: -self.size.height)
        case .right:
            rectTransform = CGAffineTransform(rotationAngle: rad(-90)).translatedBy(x: -self.size.width, y: 0)
        case .down:
            rectTransform = CGAffineTransform(rotationAngle: rad(-180)).translatedBy(x: -self.size.width, y: -self.size.height)
        default:
            rectTransform = .identity
        }
        rectTransform = rectTransform.scaledBy(x: self.scale, y: self.scale)

        guard let imageRef = self.cgImage?.cropping(to: rect.applying(rectTransform)) else { return nil }
        let result = UIImage(cgImage: imageRef, scale: self.scale, orientation: self.imageOrientation)
        return result
    }
}

这是其在ViewController中作为计算属性的实现。

var croppedImage: UIImage? {
    guard let image = self.image else { return nil }

    let ratio = image.size.height / self.contentSize.height
    let origin = CGPoint(x: self.contentOffset.x * ratio, y: self.contentOffset.y * ratio)
    let size = CGSize(width: self.bounds.size.width * ratio, height: self.bounds.size.height * ratio)
    let cropFrame = CGRect(origin: origin, size: size)
    let croppedImage = image.crop(to: cropFrame)

    return croppedImage
}

答案 6 :(得分:0)

SWIFT5。我添加了以下内容作为UIImage的扩展。想法是强制UIImage内部的图像与UIImage方向的图像匹配(这仅在UI上的显示方式中起作用!)。在UIImage“容器”中重绘实际图像数据将使对应的CGImage具有相同的方向

func forceSameOrientation() -> UIImage {
    UIGraphicsBeginImageContext(self.size)
    self.draw(in: CGRect(origin: CGPoint.zero, size: self.size))
    guard let image = UIGraphicsGetImageFromCurrentImageContext() else {
        UIGraphicsEndImageContext()
        return self
    }
    UIGraphicsEndImageContext()
    return image
}