2017-12-28 31 views
0

私はiOS 11、XCode 9、Metal 2で作業しています。ピクセル形式がbgra8UnormMTLTextureです。bgra8Unorm iOS-Metalテクスチャをrgba8Unormテクスチャに変換するには?

金属層のためのピクセルフォーマットはbgra8Unorm、bgra8Unorm_srgb、rgba16Float、BGRA10_XR、又はbgra10_XR_sRGBなければならない:pixelFormat documentationにかかるので、私は、このピクセルのフォーマットを変更することはできません。

他のピクセル形式は私のアプリケーションには適していません。

テクスチャからUIImageを作成します。

getBytes(_:bytesPerRow:bytesPerImage:from:mipmapLevel:slice:) 

私は UIImage得るためにこれらのバイトを処理しています:私は、テクスチャ( doc)からのピクセルバイトを抽出することによってそうすることができる午前

func getUIImageForRGBAData(data: Data) -> UIImage? { 
    let d = (data as NSData) 

    let width = GlobalConfiguration.textureWidth 
    let height = GlobalConfiguration.textureHeight 
    let rowBytes = width * 4 
    let size = rowBytes * height 

    let pointer = malloc(size) 
    memcpy(pointer, d.bytes, d.length) 

    let colorSpace = CGColorSpaceCreateDeviceRGB() 
    let context = CGContext(data: pointer, width: width, height: height, bitsPerComponent: 8, bytesPerRow: rowBytes, space: colorSpace, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)! 

    let imgRef = context.makeImage() 
    let image = UIImage(cgImage: imgRef!) 
    return image 
} 

をしかし、CGContextは画素であることを前提としていrgba8形式のものです。たとえば、最終的なUIImageでは赤いテクスチャピクセルが青色になります。このプロセスでpixelFormatを変更して適切な色を得る方法はありますか?

+0

Accelerate frameworkメソッドをチェックしましたか? https://developer.apple.com/documentation/accelerate/vimage/conversion – Adamsor

+0

Metalレイヤー以外のテクスチャを使用することは許可されています。その制限があるからといって、異なるフォーマットのテクスチャに描画できないわけではありません。描画可能なテクスチャへの描画と並行して、または順番に(テクスチャを最初に描画し、そのテクスチャを描画可能なテクスチャに描画して) 。 –

+0

ヒントのおかげで、それを試してみましょう! – 1awuesterose

答えて

1

この関数は、RGBAの順に.bgra8Unormテクスチャのバイトをスウィズルし、データからUIImageを作成します。

func makeImage(from texture: MTLTexture) -> UIImage? { 
    let width = texture.width 
    let height = texture.height 
    let bytesPerRow = width * 4 

    let data = UnsafeMutableRawPointer.allocate(bytes: bytesPerRow * height, alignedTo: 4) 
    defer { 
     data.deallocate(bytes: bytesPerRow * height, alignedTo: 4) 
    } 

    let region = MTLRegionMake2D(0, 0, width, height) 
    texture.getBytes(data, bytesPerRow: bytesPerRow, from: region, mipmapLevel: 0) 

    var buffer = vImage_Buffer(data: data, height: UInt(height), width: UInt(width), rowBytes: bytesPerRow) 

    let map: [UInt8] = [2, 1, 0, 3] 
    vImagePermuteChannels_ARGB8888(&buffer, &buffer, map, 0) 

    guard let colorSpace = CGColorSpace(name: CGColorSpace.genericRGBLinear) else { return nil } 
    guard let context = CGContext(data: data, width: width, height: height, bitsPerComponent: 8, bytesPerRow: bytesPerRow, 
            space: colorSpace, bitmapInfo: CGImageAlphaInfo.noneSkipLast.rawValue) else { return nil } 
    guard let cgImage = context.makeImage() else { return nil } 

    return UIImage(cgImage: cgImage) 
} 

警告:この機能は、非常に高価です。メタルテクスチャからフレームごとにイメージを作成することは、決してあなたがしたいことではありません。

+0

ありがとう!その間に私が解決した方法とほぼ同じです。この関数は、テクスチャをエクスポートするために使用されるだけなので、フレームごとには使用されません。 – 1awuesterose

関連する問題