简体   繁体   English

WKWebView CALayer to image 导出空白图片

[英]WKWebView CALayer to image exports blank image

I'm trying to take a screenshot of webpage but the image is always blank(white).我正在尝试截取网页的屏幕截图,但图像始终为空白(白色)。

I'm using this code to convert CALayer to Data (taken from here)我正在使用此代码将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)!
}

}

And then to write the data to file as .png然后将数据以.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)
}

But I'm getting a blank(white) png instead of what I expected但是我得到了一个空白(白色)png 而不是我所期望的

1). 1)。 What am I doing wrong?我究竟做错了什么?

2). 2)。 Is there any other possible ways to get the image representation of webpage(Using swift)?有没有其他可能的方法来获取网页的图像表示(使用 swift)?

Thank you!谢谢!

Latest Update:最新更新:

Now you can take screenshot of WKWebView just like WebView .现在您可以像WebView一样截取WKWebView屏幕截图。

Apple added new method for both iOS and macOS, Apple为 iOS 和 macOS 添加了新方法

func takeSnapshot(with snapshotConfiguration: WKSnapshotConfiguration?, 
completionHandler: @escaping (NSImage?, Error?) -> Void)

But its still in beta.但它仍处于测试阶段。


You can't take a screenshot of WKWebView .您无法截取WKWebView的屏幕截图。 It always returns a blank image.它总是返回一个空白图像。 Even if you try to include WKWebView inside another NSView and take a screenshot, it will give you blank image in place of WKWebView .即使您尝试将WKWebView包含在另一个NSView并截取屏幕截图,它也会为您提供空白图像代替WKWebView

You should use WebView instead of WKWebView for your purpose.您应该使用WebView而不是WKWebView来实现您的目的。 Check this question .检查这个问题

If you are ok with using private frameworks(apple doesn't allow your app in its store), check this GitHub .如果您可以使用私有框架(Apple 不允许在其商店中使用您的应用程序),请查看此GitHub Its written in Obj-C.它是用 Obj-C 编写的。 I don't know Obj-C so I can't explain what's happening in that code.我不知道 Obj-C,所以我无法解释该代码中发生了什么。 But it claims to do the work.但它声称可以完成这项工作。

Your best approach is to use WebView and use your mentioned extension data() on the WebView .你最好的方法是使用WebView和使用您提到的扩展data()WebView

Just a question: Why don't you use phantomJS?只是一个问题:你为什么不使用phantomJS?

PS.附注。 Sorry for the late reply.这么晚才回复很抱歉。 I didn't see your e-mail.我没有看到你的电子邮件。

Update: Swift 5 adding to prior.更新: Swift 5添加到之前。

I didn't want controls in the output, so I bound a key sequence to it (local key monitor):我不想在输出中使用控件,所以我将一个键序列绑定到它(本地键监视器):

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

and work within a sandbox environment.并在沙盒环境中工作。 We keep a bunch of user settings in the defaults like where they want snapshots to be captured (~/Desktop), so 1st time around we ask/authenticate, cache it, and the app delegate on subsequent invocations will restore sandbox bookmark(s).我们将一堆用户设置保留在默认值中,例如他们希望捕获快照的位置 (~/Desktop),因此第一次我们询问/验证、缓存它,随后调用的应用程序委托将恢复沙箱书签.

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()
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM