WKWebView CALayer 到图像导出空白图像
WKWebView CALayer to image exports blank image
我正在尝试对网页进行屏幕截图,但图像始终为空白(白色)。
我正在使用此代码将 CALayer
转换为 Data
extension CALayer {
/// Get `Data` representation of the layer.
///
/// - Parameters:
/// - fileType: The format of file. Defaults to PNG.
/// - properties: A dictionary that contains key-value pairs specifying image properties.
///
/// - Returns: `Data` for image.
func data(using fileType: NSBitmapImageFileType = .PNG, properties: [String : Any] = [:]) -> Data {
let width = Int(bounds.width * self.contentsScale)
let height = Int(bounds.height * self.contentsScale)
let imageRepresentation = NSBitmapImageRep(bitmapDataPlanes: nil, pixelsWide: width, pixelsHigh: height, bitsPerSample: 8, samplesPerPixel: 4, hasAlpha: true, isPlanar: false, colorSpaceName: NSDeviceRGBColorSpace, bytesPerRow: 0, bitsPerPixel: 0)!
imageRepresentation.size = bounds.size
let context = NSGraphicsContext(bitmapImageRep: imageRepresentation)!
render(in: context.cgContext)
return imageRepresentation.representation(using: fileType, properties: properties)!
}
}
然后将数据写入文件 .png
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!)
{
let d = web.layer?.data() as NSData? //web is the instance of WKWebView
d!.write(toFile: "/Users/mac/Desktop/web.png", atomically: true)
}
但我得到的是空白(白色)png 而不是我所期望的
1).我做错了什么?
2).是否有任何其他可能的方法来获取图像表示
网页(使用swift)?
谢谢!
最新更新:
现在您可以像 WebView
一样对 WKWebView
进行截图了。
Apple added new method 对于 iOS 和 macOS,
func takeSnapshot(with snapshotConfiguration: WKSnapshotConfiguration?,
completionHandler: @escaping (NSImage?, Error?) -> Void)
但它仍处于测试阶段。
您无法截取 WKWebView
的屏幕截图。它总是 returns 空白图像。即使您尝试将 WKWebView
包含在另一个 NSView
中并截取屏幕截图,它也会给您空白图像代替 WKWebView
.
您应该使用 WebView
而不是 WKWebView
来达到您的目的。检查这个 .
如果您可以使用私有框架(苹果不允许您的应用程序出现在其商店中),请检查此 GitHub。它是用 Obj-C 编写的。我不知道 Obj-C,所以我无法解释该代码中发生的事情。但它声称可以完成这项工作。
您最好的方法是使用 WebView
并在 WebView
上使用您提到的扩展程序 data()
。
只是一个问题:你为什么不使用 phantomJS?
PS。这么晚才回复很抱歉。我没有看到你的电子邮件。
更新:Swift 5 添加到先前。
我不想在输出中进行控制,所以我给它绑定了一个键序列(本地键监视器):
case [NSEvent.ModifierFlags.option, NSEvent.ModifierFlags.command]:
guard let window = NSApp.keyWindow, let wvc = window.contentViewController as? WebViewController else {
NSSound(named: "Sosumi")?.play()
return true
}
wvc.snapshot(self)
return true
并在沙盒环境中工作。我们在默认设置中保留了一堆用户设置,比如他们希望捕获快照的位置 (~/Desktop),所以第一次我们 ask/authenticate,缓存它,随后调用的应用程序委托将恢复沙箱书签( s).
var webImageView = NSImageView.init()
var player: AVAudioPlayer?
@IBAction func snapshot(_ sender: Any) {
webView.takeSnapshot(with: nil) {image, error in
if let image = image {
self.webImageView.image = image
} else {
print("Failed taking snapshot: \(error?.localizedDescription ?? "--")")
self.webImageView.image = nil
}
}
guard let image = webImageView.image else { return }
guard let tiffData = image.tiffRepresentation else { NSSound(named: "Sosumi")?.play(); return }
// 1st around authenticate and cache sandbox data if needed
if appDelegate.isSandboxed(), appDelegate.desktopData == nil {
let openPanel = NSOpenPanel()
openPanel.message = "Authorize access to Desktop"
openPanel.prompt = "Authorize"
openPanel.canChooseFiles = false
openPanel.canChooseDirectories = true
openPanel.canCreateDirectories = false
openPanel.directoryURL = appDelegate.getDesktopDirectory()
openPanel.begin() { (result) -> Void in
if (result == NSApplication.ModalResponse.OK) {
let desktop = openPanel.url!
_ = self.appDelegate.storeBookmark(url: desktop, options: self.appDelegate.rwOptions)
self.appDelegate.desktopData = self.appDelegate.bookmarks[desktop]
UserSettings.SnapshotsURL.value = desktop.absoluteString
}
}
}
// Form a filename: ~/"<app's name> View Shot <timestamp>"
let dateFMT = DateFormatter()
dateFMT.dateFormat = "yyyy-dd-MM"
let timeFMT = DateFormatter()
timeFMT.dateFormat = "h.mm.ss a"
let now = Date()
let path = URL.init(fileURLWithPath: UserSettings.SnapshotsURL.value).appendingPathComponent(
String(format: "%@ View Shot %@ at %@.png", appDelegate.appName, dateFMT.string(from: now), timeFMT.string(from: now)))
let bitmapImageRep = NSBitmapImageRep(data: tiffData)
// With sandbox clearance to the desktop...
do
{
try bitmapImageRep?.representation(using: .png, properties: [:])?.write(to: path)
// https://developer.apple.com/library/archive/qa/qa1913/_index.html
if let asset = NSDataAsset(name:"Grab") {
do {
// Use NSDataAsset's data property to access the audio file stored in Sound.
player = try AVAudioPlayer(data:asset.data, fileTypeHint:"caf")
// Play the above sound file.
player?.play()
} catch {
Swift.print("no sound for you")
}
}
} catch let error {
NSApp.presentError(error)
NSSound(named: "Sosumi")?.play()
}
}
我正在尝试对网页进行屏幕截图,但图像始终为空白(白色)。
我正在使用此代码将 CALayer
转换为 Data
extension CALayer {
/// Get `Data` representation of the layer.
///
/// - Parameters:
/// - fileType: The format of file. Defaults to PNG.
/// - properties: A dictionary that contains key-value pairs specifying image properties.
///
/// - Returns: `Data` for image.
func data(using fileType: NSBitmapImageFileType = .PNG, properties: [String : Any] = [:]) -> Data {
let width = Int(bounds.width * self.contentsScale)
let height = Int(bounds.height * self.contentsScale)
let imageRepresentation = NSBitmapImageRep(bitmapDataPlanes: nil, pixelsWide: width, pixelsHigh: height, bitsPerSample: 8, samplesPerPixel: 4, hasAlpha: true, isPlanar: false, colorSpaceName: NSDeviceRGBColorSpace, bytesPerRow: 0, bitsPerPixel: 0)!
imageRepresentation.size = bounds.size
let context = NSGraphicsContext(bitmapImageRep: imageRepresentation)!
render(in: context.cgContext)
return imageRepresentation.representation(using: fileType, properties: properties)!
}
}
然后将数据写入文件 .png
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!)
{
let d = web.layer?.data() as NSData? //web is the instance of WKWebView
d!.write(toFile: "/Users/mac/Desktop/web.png", atomically: true)
}
但我得到的是空白(白色)png 而不是我所期望的
1).我做错了什么?
2).是否有任何其他可能的方法来获取图像表示 网页(使用swift)?
谢谢!
最新更新:
现在您可以像 WebView
一样对 WKWebView
进行截图了。
Apple added new method 对于 iOS 和 macOS,
func takeSnapshot(with snapshotConfiguration: WKSnapshotConfiguration?,
completionHandler: @escaping (NSImage?, Error?) -> Void)
但它仍处于测试阶段。
您无法截取 WKWebView
的屏幕截图。它总是 returns 空白图像。即使您尝试将 WKWebView
包含在另一个 NSView
中并截取屏幕截图,它也会给您空白图像代替 WKWebView
.
您应该使用 WebView
而不是 WKWebView
来达到您的目的。检查这个
如果您可以使用私有框架(苹果不允许您的应用程序出现在其商店中),请检查此 GitHub。它是用 Obj-C 编写的。我不知道 Obj-C,所以我无法解释该代码中发生的事情。但它声称可以完成这项工作。
您最好的方法是使用 WebView
并在 WebView
上使用您提到的扩展程序 data()
。
只是一个问题:你为什么不使用 phantomJS?
PS。这么晚才回复很抱歉。我没有看到你的电子邮件。
更新:Swift 5 添加到先前。
我不想在输出中进行控制,所以我给它绑定了一个键序列(本地键监视器):
case [NSEvent.ModifierFlags.option, NSEvent.ModifierFlags.command]:
guard let window = NSApp.keyWindow, let wvc = window.contentViewController as? WebViewController else {
NSSound(named: "Sosumi")?.play()
return true
}
wvc.snapshot(self)
return true
并在沙盒环境中工作。我们在默认设置中保留了一堆用户设置,比如他们希望捕获快照的位置 (~/Desktop),所以第一次我们 ask/authenticate,缓存它,随后调用的应用程序委托将恢复沙箱书签( s).
var webImageView = NSImageView.init()
var player: AVAudioPlayer?
@IBAction func snapshot(_ sender: Any) {
webView.takeSnapshot(with: nil) {image, error in
if let image = image {
self.webImageView.image = image
} else {
print("Failed taking snapshot: \(error?.localizedDescription ?? "--")")
self.webImageView.image = nil
}
}
guard let image = webImageView.image else { return }
guard let tiffData = image.tiffRepresentation else { NSSound(named: "Sosumi")?.play(); return }
// 1st around authenticate and cache sandbox data if needed
if appDelegate.isSandboxed(), appDelegate.desktopData == nil {
let openPanel = NSOpenPanel()
openPanel.message = "Authorize access to Desktop"
openPanel.prompt = "Authorize"
openPanel.canChooseFiles = false
openPanel.canChooseDirectories = true
openPanel.canCreateDirectories = false
openPanel.directoryURL = appDelegate.getDesktopDirectory()
openPanel.begin() { (result) -> Void in
if (result == NSApplication.ModalResponse.OK) {
let desktop = openPanel.url!
_ = self.appDelegate.storeBookmark(url: desktop, options: self.appDelegate.rwOptions)
self.appDelegate.desktopData = self.appDelegate.bookmarks[desktop]
UserSettings.SnapshotsURL.value = desktop.absoluteString
}
}
}
// Form a filename: ~/"<app's name> View Shot <timestamp>"
let dateFMT = DateFormatter()
dateFMT.dateFormat = "yyyy-dd-MM"
let timeFMT = DateFormatter()
timeFMT.dateFormat = "h.mm.ss a"
let now = Date()
let path = URL.init(fileURLWithPath: UserSettings.SnapshotsURL.value).appendingPathComponent(
String(format: "%@ View Shot %@ at %@.png", appDelegate.appName, dateFMT.string(from: now), timeFMT.string(from: now)))
let bitmapImageRep = NSBitmapImageRep(data: tiffData)
// With sandbox clearance to the desktop...
do
{
try bitmapImageRep?.representation(using: .png, properties: [:])?.write(to: path)
// https://developer.apple.com/library/archive/qa/qa1913/_index.html
if let asset = NSDataAsset(name:"Grab") {
do {
// Use NSDataAsset's data property to access the audio file stored in Sound.
player = try AVAudioPlayer(data:asset.data, fileTypeHint:"caf")
// Play the above sound file.
player?.play()
} catch {
Swift.print("no sound for you")
}
}
} catch let error {
NSApp.presentError(error)
NSSound(named: "Sosumi")?.play()
}
}