【问题标题】:Replacing UIImageJPEGRepresentation with UIGraphicsImageRenderer's jpegData用 UIGraphicsImageRenderer 的 jpegData 替换 UIImageJPEGRepresentation
【发布时间】:2017-01-15 20:58:38
【问题描述】:

我正在努力在 iOS 10 中添加对广色域照片的支持。当用户从相机中拍照时,我需要使用支持新色彩空间的新 API 来保存照片数据 - UIGraphicsImageRenderer' s jpegData 而不是 UIImageJPEGRepresentation

我在图像方向方面遇到了一些问题。在我的 iPad 上以纵向拍摄照片,图像未正确绘制。请参阅下面的 cmets:

旧 API:

let image = info[UIImagePickerControllerOriginalImage] as! UIImage
let imageData = UIImageJPEGRepresentation(image, 1)

新 API:

let image = info[UIImagePickerControllerOriginalImage] as! UIImage
let cgImage = image.cgImage!
let ciImage = CIImage(cgImage: cgImage)

let format = UIGraphicsImageRendererFormat()
format.scale = 1
format.prefersExtendedRange = true

let renderer = UIGraphicsImageRenderer(bounds: ciImage.extent, format: format)
let imageData = renderer.jpegData(withCompressionQuality: 1, actions: { context in
    context.cgContext.draw(cgImage, in: ciImage.extent) //draws flipped horizontally
    //image.draw(at: .zero) //draws rotated 90 degrees leaving black at bottom
    //image.draw(in: ciImage.extent) //draws rotated 90 degrees stretching and compressing the image to fill the rect 
 })

UIGraphicsImageRendererjpegData替换UIImageJPEGRepresentation的正确方法是什么?

【问题讨论】:

  • 这真的是您使用的所有代码吗? image.draw 方法应该“在当前图形上下文中绘制整个图像,尊重图像的方向设置”。根据我的经验,在使用渲染器时,非向上方向的输入图像总是会被重新渲染为向上方向的图像数据,而无需额外的坐标变换。

标签: ios uikit cgcontext cgcontextdrawimage


【解决方案1】:

UIImage 可以根据相机旋转有不同的方向。 您可以根据该方向动态解析需要应用于图像的转换,如下所示:

let renderer = UIGraphicsImageRenderer(size: image.size, format: format)
let imageData = renderer.jpegData(withCompressionQuality: 1, actions: { context in
    var workSize = image.size;
    workSize.width = floor(workSize.width / image.scale)
    workSize.height = floor(workSize.height / image.scale)
    // No-op if the orientation is already correct
    // if image.imageOrientation == .up { draw image }

    // 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.identity

    switch image.imageOrientation
    {
        case .down, .downMirrored:
            transform = transform.translatedBy(x: workSize.width, y: workSize.height)
            transform = transform.rotated(by: CGFloat(Double.pi))
            break

        case .left, .leftMirrored:
            transform = transform.translatedBy(x: workSize.width, y: 0.0)
            transform = transform.rotated(by: CGFloat(Double.pi / 2.0))
            break

        case .right, .rightMirrored:
            transform = transform.translatedBy(x: 0.0, y: workSize.height)
            transform = transform.rotated(by: CGFloat(-Double.pi / 2.0))
            break

        case .up, .upMirrored:
            break
    }

    switch image.imageOrientation
    {
        case .upMirrored, .downMirrored:
            transform = transform.translatedBy(x: workSize.width, y: 0.0)
            transform = transform.scaledBy(x: -1.0, y: 1.0)
            break

        case .leftMirrored, .rightMirrored:
            transform = transform.translatedBy(x: workSize.height, y: 0.0);
            transform = transform.scaledBy(x: -1.0, y: 1.0);
            break

        case .up, .down, .left, .right:
            break
    }

    // Now we draw the underlying CGImage into a new context, applying the transform
    // calculated above.

    let ctx = context.cgContext

    ctx.concatenate(transform)

    switch image.imageOrientation {
        case .left, .leftMirrored, .right, .rightMirrored:
            ctx.draw(image.cgImage!, in: CGRect(x: 0.0, y:0.0, width: workSize.height, height: workSize.width))
            break;

        default:
            ctx.draw(image.cgImage!, in: CGRect(origin: .zero, size: workSize))
            break;
    } 
 })

根据UIImage+fixOrientation回答

【讨论】:

    【解决方案2】:

    image.draw() 方法应该为您提供correct the orientation automatically

    此方法在当前图形上下文中绘制整个图像,并尊重图像的方向设置。在默认坐标系中,图像位于指定矩形原点的右下方。但是,此方法尊重应用于当前图形上下文的任何变换。

    我不确定您为什么需要使用ci.extentextent 似乎是(我不声称自己是核心图像 API 方面的专家)“原始”图像数据的尺寸,它在没有任何图像方向校正的情况下存储。如果您的原始数据需要旋转(非向上方向,如LeftRight),范围仍将是存储数据的原始矩形。

    我将以下代码用于带有imageOrientation.rawValue = 3 的图像,并且当重新加载时,我的数据在正确的尺寸下完全没有问题,并且“更正”了imageOrientation.rawValue = 0

    let imageSize = image.Size
    let renderer = UIGraphicsImageRenderer(size: renderedSize, format: UIGraphicsImageRendererFormat())
    return renderer.jpegData(withCompressionQuality: 0.95) { (rendererContext) in
        let rect = CGRect(x: 0, y: 0, width: imageSize.width, height: imageSize.height)
        image.draw(in: rect)
    }
    

    考虑到图像方向,我的输入图像使用我的代码正确“呈现”其数据。在右边,我使用draw(in: extent)。图像没有旋转。只是拉伸。

    【讨论】:

      猜你喜欢
      • 2019-01-02
      • 2015-08-17
      • 2013-02-20
      • 2018-07-30
      • 2016-12-29
      • 1970-01-01
      • 2015-06-26
      • 1970-01-01
      • 2013-12-13
      相关资源
      最近更新 更多