要截屏,需要获取帧缓冲区的MTLTexture。
1.如果你使用MTKView:
let texture = view.currentDrawable!.texture
2。如果你不使用MTKView
这就是我要做的——我会有一个属性来保存最后一个呈现在屏幕上的可绘制对象:
let lastDrawableDisplayed: CAMetalDrawable?
然后当你在屏幕上展示drawable时,我会更新它:
let commandBuffer = commandQueue.commandBuffer()
commandBuffer.addCompletedHandler { buffer in
self.lastDrawableDisplayed = drawable
}
现在你只要需要截图,就可以得到这样的纹理:
let texture = lastDrawableDisplayed.texture
好的,现在当您拥有MTLTexture 时,您可以将其转换为CGImage,然后再转换为UIImage 或NSImage。
这是 OS X 游乐场的代码(MetalKit.MTLTextureLoader 不适用于 iOS 游乐场),其中我将 MTLTexture 转换为 CGImage
为此,我在MTLTexture 上做了一个小扩展。
import Metal
import MetalKit
import Cocoa
let device = MTLCreateSystemDefaultDevice()!
let textureLoader = MTKTextureLoader(device: device)
let path = "path/to/your/image.jpg"
let data = NSData(contentsOfFile: path)!
let texture = try! textureLoader.newTextureWithData(data, options: nil)
extension MTLTexture {
func bytes() -> UnsafeMutablePointer<Void> {
let width = self.width
let height = self.height
let rowBytes = self.width * 4
let p = malloc(width * height * 4)
self.getBytes(p, bytesPerRow: rowBytes, fromRegion: MTLRegionMake2D(0, 0, width, height), mipmapLevel: 0)
return p
}
func toImage() -> CGImage? {
let p = bytes()
let pColorSpace = CGColorSpaceCreateDeviceRGB()
let rawBitmapInfo = CGImageAlphaInfo.NoneSkipFirst.rawValue | CGBitmapInfo.ByteOrder32Little.rawValue
let bitmapInfo:CGBitmapInfo = CGBitmapInfo(rawValue: rawBitmapInfo)
let selftureSize = self.width * self.height * 4
let rowBytes = self.width * 4
let provider = CGDataProviderCreateWithData(nil, p, selftureSize, nil)
let cgImageRef = CGImageCreate(self.width, self.height, 8, 32, rowBytes, pColorSpace, bitmapInfo, provider, nil, true, CGColorRenderingIntent.RenderingIntentDefault)!
return cgImageRef
}
}
if let imageRef = texture.toImage() {
let image = NSImage(CGImage: imageRef, size: NSSize(width: texture.width, height: texture.height))
}