Swift-技巧(九)CGImage To CVPixelBuffer


摘要

iOS 中圖像的表現形式不只是 Image,還有更加底層的方式,比如 CVPixelBuffer 像素緩存形式,那么 CGImage 就可以轉換為像素緩存的方式也是需要了解的。

CGImage 蘋果官方解釋是一張 bitmap 圖像或者圖像 mask。它是 UIImage 類中的一個屬性,並可以通過 UIImage 的初始化函數稱為一個 Image 對象。

CVPixelBuffer 是核心緩存像素對象的引用,這里存儲着一張圖像。

在需要 CVPixelBuffer 對象的應用場景中,可以把 CGImage 轉換獲得到。

CGImage To CVPixelBuffer

這里使用 CGContext 對象中的函數將 CGImage 轉換為 CVPixelBuffer。需要提前導入 CoreGraphics 框架。

import CoreGraphics

然后將轉換函數放在 CGImage 擴展中,就可以直接訪問 CGImage 對象的 widthheight,甚至可以通過 self 訪問到自身。

extension CGImage {
	// 轉換函數
	...
}

實現方法

接下來按照需求由少到多的情況來處理 CGImageCVPixelBuffer 。首先就是直接獲取到一個 ARGB 的像素緩存對象。

public func pixelBuffer() -> CVPixelBuffer? {
	return pixelBuffer(width: width, height: height, orientation: .up)
}

函數中的 widthheight 可以直接訪問到,orientation 是圖像的方向,這里默認是 .up(豎直)。

那么可以調整圖片的 widthheight 轉換成一個 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 是顏色空間參數,alphaInfoalpha 在內存中的位置,這幾個參數如果不確定,就直接設置成這樣。

這個函數可以設置這么多參數,從另外一個角度說,這個函數就是最終的實現,上面的幾個函數都是對這個函數的封裝處理。

這個函數的處理邏輯就是創建並配置 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
  }

題外話

時間倉促,說的東西可能不全面,在你查看的過程中遇到什么問題,評論區給我留言,我會盡快回復。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM