Skip to content

Instantly share code, notes, and snippets.

@sebjvidal
Forked from christianselig/CARendererMetal.swift
Last active March 1, 2024 16:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sebjvidal/7cf6e7a30bea14fcd117b287ad427d90 to your computer and use it in GitHub Desktop.
Save sebjvidal/7cf6e7a30bea14fcd117b287ad427d90 to your computer and use it in GitHub Desktop.
import UIKit
import MetalKit
class ViewController: UIViewController {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let imageView = UIImageView(image: UIImage(named: "landscape"))
imageView.frame = CGRect(x: 0, y: 200, width: 350, height: 197)
view.addSubview(imageView)
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(3)) {
// CARenderer outputs 350 🤕
let texture = imageView.snapshot(device: MTLCreateSystemDefaultDevice()!)!
print(texture.width)
let image = UIImage(ciImage: CIImage(mtlTexture: texture)!)
print(image.size.width * image.scale)
imageView.layer.setAffineTransform(.identity)
imageView.image = image
self.view.addSubview(imageView)
// UIView.drawHierarchy outputs 1,050 as expected 🥳
let rendererFormat = UIGraphicsImageRendererFormat.default()
rendererFormat.opaque = true
let renderer = UIGraphicsImageRenderer(size: imageView.bounds.size, format: rendererFormat)
let image2 = renderer.image { context in
imageView.drawHierarchy(in: imageView.bounds, afterScreenUpdates: false)
}
print(image2.size.width * image2.scale)
}
}
}
extension UIView {
func snapshot(device: MTLDevice) -> MTLTexture? {
let width = Int(bounds.width * 3)
let height = Int(bounds.height * 3)
let desc = MTLTextureDescriptor.texture2DDescriptor(pixelFormat: .rgba8Unorm, width: width, height: height, mipmapped: false)
desc.usage = [.renderTarget, .shaderRead, .shaderWrite]
let texture = device.makeTexture(descriptor: desc)!
let renderer = CARenderer(mtlTexture: texture)
renderer.layer = layer
renderer.bounds = CGRect(x: 0, y: 0, width: width, height: height)
renderer.layer?.setAffineTransform(
CGAffineTransform(scaleX: 3, y: 3)
.concatenating(
CGAffineTransform(translationX: 350, y: 0)
)
)
CATransaction.flush()
renderer.beginFrame(atTime: CACurrentMediaTime(), timeStamp: nil)
renderer.addUpdate(CGRect(x: 0, y: 0, width: width, height: height))
renderer.render()
renderer.endFrame()
return texture
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment