使用 UIGraphicImageRenderer 的 CGContext 重绘图像,翻转图像。如何防止翻转?
Using CGContext of UIGraphicImageRenderer to redraw an image, flipped the image. How to prevent the flip?
给定一个图像,当我想转换为标准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)
}
}
但是,如果我使用 UIGraphicImageRenderer
中的 CGContext
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))
}
}
}
图像颠倒了,如下所示。为什么会翻转,如何避免翻转?
无需获取cgImage。你可以简单地绘制 UIImage:
extension UIImage {
func toSRGB() -> UIImage {
UIGraphicsImageRenderer(size: size).image { _ in
draw(in: CGRect(origin: .zero, size: size))
}
}
}
你的图片翻转的原因是difference between coordinate system in UIKit and 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))
}
}
}
edit/update:
要将比例保持在 1 倍,您可以传递图像渲染器格式:
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))
}
}
}
经过探索,只是为了澄清我注意到的它们之间的差异,如下所示。
原图5x3像素
直接使用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)
}
}
我们保留了相同的像素 (5x3)。这是此解决方案的优点,但它需要访问 CGContext 并直接对其进行操作。
第二种方法是UIGraphicsImageRenderer
并访问内部ctx
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))
}
}
}
使用这种方法,它
- 看起来 up-side 低头。
- Pixel 的宽度和高度都加倍 (10x6),使颜色边缘更平滑。
为了解决up-side的问题,我们需要按照@LeoDabus的回答翻转它,使用
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))
}
}
}
现在图像的方向正确了,但宽度和高度仍然加倍 (10x6)。
翻转结果与@LeoDabus提供的简化答案相同
extension UIImage {
func toSRGB() -> UIImage {
UIGraphicsImageRenderer(size: size).image { _ in
draw(in: CGRect(origin: .zero, size: size))
}
}
}
给定一个图像,当我想转换为标准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)
}
}
但是,如果我使用 UIGraphicImageRenderer
CGContext
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))
}
}
}
图像颠倒了,如下所示。为什么会翻转,如何避免翻转?
无需获取cgImage。你可以简单地绘制 UIImage:
extension UIImage {
func toSRGB() -> UIImage {
UIGraphicsImageRenderer(size: size).image { _ in
draw(in: CGRect(origin: .zero, size: size))
}
}
}
你的图片翻转的原因是difference between coordinate system in UIKit and 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))
}
}
}
edit/update:
要将比例保持在 1 倍,您可以传递图像渲染器格式:
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))
}
}
}
经过探索,只是为了澄清我注意到的它们之间的差异,如下所示。
原图5x3像素
直接使用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)
}
}
我们保留了相同的像素 (5x3)。这是此解决方案的优点,但它需要访问 CGContext 并直接对其进行操作。
第二种方法是UIGraphicsImageRenderer
并访问内部ctx
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))
}
}
}
使用这种方法,它
- 看起来 up-side 低头。
- Pixel 的宽度和高度都加倍 (10x6),使颜色边缘更平滑。
为了解决up-side的问题,我们需要按照@LeoDabus的回答翻转它,使用
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))
}
}
}
现在图像的方向正确了,但宽度和高度仍然加倍 (10x6)。
翻转结果与@LeoDabus提供的简化答案相同
extension UIImage {
func toSRGB() -> UIImage {
UIGraphicsImageRenderer(size: size).image { _ in
draw(in: CGRect(origin: .zero, size: size))
}
}
}