2017-12-28 35 views
0

저는 iOS 11, XCode 9 및 Metal 2로 작업하고 있습니다. MTLTexture의 픽셀 형식은 bgra8Unorm입니다. I 인해 pixelFormat documentation에 따라, 픽셀 포맷을 변경할 수bgra8Unorm iOS-Metal 텍스처를 rgba8Unorm 텍스처로 변환하는 방법은 무엇입니까?

금속층에 대한 픽셀 형식 bgra8Unorm, bgra8Unorm_srgb, rgba16Float, BGRA10_XR 또는 bgra10_XR_sRGB이어야한다.

다른 픽셀 형식은 내 응용 프로그램에 적합하지 않습니다.

이제 질감에서 UIImage을 만들고 싶습니다. 나는 UIImage 얻을이 바이트를 처리하고

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

: 나는 질감 (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

프레임 워크 가속화 방법을 선택 했습니까? https://developer.apple.com/documentation/accelerate/vimage/conversion – Adamsor

+0

메탈 레이어와 다른 텍스처를 사용할 수 있습니다. 이 제한이 존재하기 만해도 드로어 블 텍스처에 그리기와 순차적으로 또는 다른 방법으로 다른 포맷의 텍스쳐로 그릴 수 없다는 것을 의미하지는 않습니다. (먼저 텍스처를 그린 다음 그 텍스처를 드로어 블 텍스쳐에 그리십시오) . –

+0

힌트를 보내 주셔서 감사합니다. – 1awuesterose

답변

1

이 함수는 RGBA 순서로 .bgra8Unorm 텍스처의 스위 즐링 (swizzle) 바이트의 데이터로부터 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