摘要
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: width, height: height, orientation: .up)
}
函數中的 width
和 height
可以直接訪問到,orientation
是圖像的方向,這里默認是 .up
(豎直)。
那么可以調整圖片的 width
和 height
轉換成一個 ARGB 的像素緩存對象。
public func pixelBuffer(width: Int, height: Int,
orientation: CGImagePropertyOrientation) -> CVPixelBuffer? {
return pixelBuffer(width: width, height: height,
pixelFormatType: kCVPixelFormatType_32ARGB,
colorSpace: CGColorSpaceCreateDeviceRGB(),
alphaInfo: .noneSkipFirst,
orientation: orientation)
}
函數中多了一些參數,pixelFormatType
是像素格式類型,這里設置的就是 ARGB 格式,colorSpace
是顏色空間參數,alphaInfo
是 alpha
在內存中的位置,這幾個參數如果不確定,就直接設置成這樣。
這個函數可以設置這么多參數,從另外一個角度說,這個函數就是最終的實現,上面的幾個函數都是對這個函數的封裝處理。
這個函數的處理邏輯就是創建並配置 CGContext
對象,然后調用它的 draw
函數獲取到 CBPixelBuffer
對象。如果對這些參數的意思,如何配置,還能做什么樣的擴展感興趣,給我留言。
public func pixelBuffer(width: 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: 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: width, height: height))
return pixelBuffer
}
題外話
時間倉促,說的東西可能不全面,在你查看的過程中遇到什么問題,評論區給我留言,我會盡快回復。