首页 > 解决方案 > 使用 UIGraphicImageRenderer 的 CGContext 重绘图像,翻转图像。如何防止翻转?

问题描述

给定一个图像,当我想转换为标准 sRGB 时,我可以 CGContext 来帮助绘制它,如下所示。

给定原始图像

在此处输入图像描述

当我CGContext直接使用时,它会正确重绘

extension UIImage {
    func toSRGB() -> UIImage {        
        guard let cgImage = cgImage,
            let colorSpace = CGColorSpace(name: CGColorSpace.sRGB),
            let cgContext = CGContext(
                data: nil,
                width: Int(size.width),
                height: Int(size.height),
                bitsPerComponent: 8,
                bytesPerRow: 0,
                space: colorSpace,
                bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)
            else { return self }
        cgContext.draw(cgImage, in: CGRect(origin: .zero, size: size))

        guard let newCGImage = cgContext.makeImage()
            else { return self }

        return UIImage.init(cgImage: newCGImage)
    }
}

但是,如果我使用CGContextfromUIGraphicImageRenderer

extension UIImage {
    func toSRGB() -> UIImage {
        guard let cgImage = cgImage else { return self }

        let renderer = UIGraphicsImageRenderer(size: size)
        return renderer.image { ctx in
            ctx.cgContext.draw(cgImage, in: CGRect(origin: .zero, size: size))
        }
    }
}

图像被颠倒如下。为什么它被翻转了,我怎样才能避免翻转?

在此处输入图像描述

标签: iosswiftcgcontextcgcontextdrawimageuigraphicsimagerenderer

解决方案


无需获取 cgImage。你可以简单地绘制 UIImage:

extension UIImage {
    func toSRGB() -> UIImage {
        UIGraphicsImageRenderer(size: size).image { _ in
            draw(in: CGRect(origin: .zero, size: size))
        }
    }
}

图像翻转的原因是UIKit 和 Quartz 中的坐标系之间的差异。UIKit 垂直原点在顶部,而 Quartz 垂直原点在底部。解决此问题的最简单方法是应用 CGAffineTransform 将其缩放减一,然后将高度距离向后平移:

extension CGAffineTransform {
    static func flippingVerticaly(_ height: CGFloat) -> CGAffineTransform {
        var transform = CGAffineTransform(scaleX: 1, y: -1)
        transform = transform.translatedBy(x: 0, y: -height)
        return transform
    }
}

extension UIImage {
    func toSRGB() -> UIImage {
        guard let cgImage = cgImage else { return self }
        return UIGraphicsImageRenderer(size: size).image { ctx in
            ctx.cgContext.concatenate(.flippingVerticaly(size.height))
            ctx.cgContext.draw(cgImage, in: CGRect(origin: .zero, size: size))
        }
    }
}

编辑/更新:

要将比例保持在 1x,您可以传递图像渲染器格式:

extension UIImage {
    func toSRGB() -> UIImage {
        guard let cgImage = cgImage else { return self }
        let format = imageRendererFormat
        format.scale = 1
        return UIGraphicsImageRenderer(size: size, format: format).image { ctx in
            ctx.cgContext.concatenate(.flippingVerticaly(size.height))
            ctx.cgContext.draw(cgImage, in: CGRect(origin: .zero, size: size))
        }
    }
}

推荐阅读