摘要
iOS 中图像的表现形式不只是 Image,还有更加底层的方式,比如
CVPixelBuffer
像素缓存形式,那么 CGImage 就可以转换为像素缓存的方式也是需要了解的。
CGImage 苹果官方解释是一张 bitmap 图像或者图像 mask。它是 UIImage 类中的一个属性,并可以通过 UIImage
的初始化函数称为一个 Image 对象。
CVPixelBuffer 是核心缓存像素对象的引用,这里存储着一张图像。
在需要 CVPixelBuffer
对象的应用场景中,可以把 CGImage
转换获得到。
CGImage
To CVPixelBuffer
这里使用 CGContext
对象中的函数将 CGImage
转换为 CVPixelBuffer
。需要提前导入 CoreGraphics
框架。
import CoreGraphics
然后将转换函数放在 CGImage
扩展中,就可以直接访问 CGImage
对象的 width
、height
,甚至可以通过 self
访问到自身。
extension CGImage {
// 转换函数
...
}
实现方法
接下来按照需求由少到多的情况来处理 CGImage
到 CVPixelBuffer
。首先就是直接获取到一个 ARGB 的像素缓存对象。
public func pixelBuffer() -> CVPixelBuffer? {
return pixelBuffer( width, height: height, orientation: .up)
}
函数中的 width
和 height
可以直接访问到,orientation
是图像的方向,这里默认是 .up
(竖直)。
那么可以调整图片的 width
和 height
转换成一个 ARGB 的像素缓存对象。
public func pixelBuffer( Int, height: Int,
orientation: CGImagePropertyOrientation) -> CVPixelBuffer? {
return pixelBuffer( width, height: height,
pixelFormatType: kCVPixelFormatType_32ARGB,
colorSpace: CGColorSpaceCreateDeviceRGB(),
alphaInfo: .noneSkipFirst,
orientation: orientation)
}
函数中多了一些参数,pixelFormatType
是像素格式类型,这里设置的就是 ARGB 格式,colorSpace
是颜色空间参数,alphaInfo
是 alpha
在内存中的位置,这几个参数如果不确定,就直接设置成这样。
这个函数可以设置这么多参数,从另外一个角度说,这个函数就是最终的实现,上面的几个函数都是对这个函数的封装处理。
这个函数的处理逻辑就是创建并配置 CGContext
对象,然后调用它的 draw
函数获取到 CBPixelBuffer
对象。如果对这些参数的意思,如何配置,还能做什么样的扩展感兴趣,给我留言。
public func pixelBuffer( Int, height: Int,
pixelFormatType: OSType,
colorSpace: CGColorSpace,
alphaInfo: CGImageAlphaInfo,
orientation: CGImagePropertyOrientation) -> CVPixelBuffer? {
assert(orientation == .up)
var maybePixelBuffer: CVPixelBuffer?
let attrs = [kCVPixelBufferCGImageCompatibilityKey: kCFBooleanTrue,
kCVPixelBufferCGBitmapContextCompatibilityKey: kCFBooleanTrue]
let status = CVPixelBufferCreate(kCFAllocatorDefault,
width,
height,
pixelFormatType,
attrs as CFDictionary,
&maybePixelBuffer)
guard status == kCVReturnSuccess, let pixelBuffer = maybePixelBuffer else {
return nil
}
let flags = CVPixelBufferLockFlags(rawValue: 0)
guard kCVReturnSuccess == CVPixelBufferLockBaseAddress(pixelBuffer, flags) else {
return nil
}
defer { CVPixelBufferUnlockBaseAddress(pixelBuffer, flags) }
guard let context = CGContext(data: CVPixelBufferGetBaseAddress(pixelBuffer),
width,
height: height,
bitsPerComponent: 8,
bytesPerRow: CVPixelBufferGetBytesPerRow(pixelBuffer),
space: colorSpace,
bitmapInfo: alphaInfo.rawValue)
else {
return nil
}
context.draw(self, in: CGRect(x: 0, y: 0, width, height: height))
return pixelBuffer
}
题外话
时间仓促,说的东西可能不全面,在你查看的过程中遇到什么问题,评论区给我留言,我会尽快回复。