I know that you can turn an iOS SwiftUI View
into an image by following these steps, but this uses UIKit things in the SwiftUI extension which you cannot use in SwiftUI for macOS.
Does anyone know how to snapshot/screenshot a macOS SwiftUI View?
I know that you can turn an iOS SwiftUI View
into an image by following these steps, but this uses UIKit things in the SwiftUI extension which you cannot use in SwiftUI for macOS.
Does anyone know how to snapshot/screenshot a macOS SwiftUI View?
In macOS same approach can be used. NSHostingController
is analog of UIHostingController
. Also to get it drawn the view should be added to some window:
extension View {
func snapshot() -> NSImage? {
let controller = NSHostingController(rootView: self)
let targetSize = controller.view.intrinsicContentSize
let contentRect = NSRect(origin: .zero, size: targetSize)
let window = NSWindow(
contentRect: contentRect,
styleMask: [.borderless],
backing: .buffered,
defer: false
)
window.contentView = controller.view
guard
let bitmapRep = controller.view.bitmapImageRepForCachingDisplay(in: contentRect)
else { return nil }
controller.view.cacheDisplay(in: contentRect, to: bitmapRep)
let image = NSImage(size: bitmapRep.size)
image.addRepresentation(bitmapRep)
return image
}
}
Use SwiftUI's ImageRenderer object to rasterize a macOS View into a NSImage.
Here's the code:
import SwiftUI
@MainActor final class BitmapImage : ObservableObject {
@Published var images: [String: NSImage] = [:]
init() {
let view = SampleView()
let renderer = ImageRenderer(content: view)
#if os(macOS)
renderer.scale = NSApplication.shared
.mainWindow?
.backingScaleFactor ?? 2.0
if let nsImage = renderer.nsImage {
images["1"] = nsImage
}
#endif
}
}
struct SampleView : View {
var body: some View {
ZStack {
Image("picture")
VStack {
Divider()
Text("Lorem ipsum dolor sit amet")
.foregroundColor(.white)
.font(.custom("", size: 72))
Spacer()
}
}
}
}
@available(macOS 13.0, *) struct ContentView : View {
@StateObject private var bitmapImage = BitmapImage()
var body: some View {
ZStack {
if let nsImage = bitmapImage.images["1"] {
Image(nsImage: nsImage)
.resizable()
.frame(width: 500) // "Squeezed" Image test
}
}
}
}