WKWebView Screenshots

前端 未结 4 919
天命终不由人
天命终不由人 2021-02-08 06:59

I am trying to capture the image that the webview is displaying to the user, so I can some color analysis of the web page. When I try to get the image from it\'s parent, I am ba

4条回答
  •  予麋鹿
    予麋鹿 (楼主)
    2021-02-08 07:30

    You will need to have access to a target writeable place - the snapshotURL ie.., such as the desktop, so we provide a handler for that:

    func registerSnaphotsURL(_ sender: NSMenuItem, handler: @escaping (URL) -> Void) {
        var targetURL : URL
    
        //  1st around authenticate and cache sandbox data if needed
        if isSandboxed, desktopData == nil {
            targetURL =
                UserSettings.SnapshotsURL.value.count == 0
                    ? getDesktopDirectory()
                    : URL.init(fileURLWithPath: UserSettings.SnapshotsURL.value, isDirectory: true)
            
            let openPanel = NSOpenPanel()
            openPanel.message = "Authorize access to "
            openPanel.prompt = "Authorize"
            openPanel.canChooseFiles = false
            openPanel.canChooseDirectories = true
            openPanel.canCreateDirectories = true
            openPanel.directoryURL = targetURL
            openPanel.begin() { (result) -> Void in
                if (result == .OK) {
                    targetURL = openPanel.url!
                    
                    //  Since we do not have data, clear any bookmark
                    
                    if self.storeBookmark(url: targetURL, options: self.rwOptions) {
                        self.desktopData = self.bookmarks[targetURL]
                        UserSettings.SnapshotsURL.value = targetURL.absoluteString
                        if !self.saveBookmarks() {
                            print("Yoink, unable to save snapshot bookmark")
                        }
    
                        self.desktopData = self.bookmarks[targetURL]
                        handler(targetURL)
                    }
                }
                else
                {
                    return
                }
            }
        }
        else
        {
            targetURL =
                UserSettings.SnapshotsURL.value.count == 0
                    ? getDesktopDirectory()
                    : URL.init(fileURLWithPath: UserSettings.SnapshotsURL.value, isDirectory: true)
            handler(targetURL)
        }
    }
    

    we wanted to allow single (view controller) and all current views (app delegate) so two actions in their respective files, both making use of the register handler.

    App Delegate

    @objc @IBAction func snapshotAllPress(_ sender: NSMenuItem) {
        registerSnaphotsURL(sender) { (snapshotURL) in
            //  If we have a return object just call them, else notify all
            if let wvc : WebViewController = sender.representedObject as? WebViewController {
                sender.representedObject = snapshotURL
                wvc.snapshot(sender)
            }
            else
            {
                sender.representedObject = snapshotURL
                let notif = Notification(name: Notification.Name(rawValue: "SnapshotAll"), object: sender)
                NotificationCenter.default.post(notif)
            }
        }
    }
    

    View Controller

    func viewDidLoad() {
        NotificationCenter.default.addObserver(
            self,
            selector: #selector(WebViewController.snapshotAll(_:)),
            name: NSNotification.Name(rawValue: "SnapshotAll"),
            object: nil)
    }
    
    @objc func snapshotAll(_ note: Notification) {
        snapshot(note.object as! NSMenuItem)
    }
    

    view singleton action

    @objc @IBAction func snapshotPress(_ sender: NSMenuItem) {
        guard let url = webView.url, url != webView.homeURL else { return }
        guard let snapshotURL = sender.representedObject as? URL else {
            //  Dispatch to app delegate to handle a singleton
            sender.representedObject = self
            appDelegate.snapshotAllPress(sender)
            return
        }
        
        sender.representedObject = snapshotURL
        snapshot(sender)
    }
    

    the webView interaction to capture an image

    @objc func snapshot(_ sender: NSMenuItem) {
        guard let url = webView.url, url != webView.homeURL else { return }
        guard var snapshotURL = sender.representedObject as? URL else { return }
        
        //  URL has only destination, so add name and extension
        let filename = String(format: "%@ Shapshot at %@",
                              (url.lastPathComponent as NSString).deletingPathExtension,
                              String.prettyStamp())
        snapshotURL.appendPathComponent(filename)
        snapshotURL = snapshotURL.appendingPathExtension("png")
        
        webView.takeSnapshot(with: nil) { image, error in
            if let image = image {
                self.webImageView.image = image
                DispatchQueue.main.async {
                    self.processSnapshotImage(image, to: snapshotURL)
                }
            }
            else
            {
                self.userAlertMessage("Failed taking snapshot", info: error?.localizedDescription)
                self.webImageView.image = nil
            }
        }
    }
    

    and the capture to the targeted area

    func processSnapshotImage(_ image: NSImage, to snapshotURL: URL) {
        guard let tiffData = image.tiffRepresentation else { NSSound(named: "Sosumi")?.play(); return }
        let bitmapImageRep = NSBitmapImageRep(data: tiffData)
    
        do
        {
            try bitmapImageRep?.representation(using: .png, properties: [:])?.write(to: snapshotURL)
            // 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.
                    let player = try AVAudioPlayer(data:asset.data, fileTypeHint:"caf")
                    // Play the above sound file.
                    player.play()
                } catch {
                    print("no sound for you")
                }
            }
            if snapshotURL.hideFileExtensionInPath(), let name = snapshotURL.lastPathComponent.removingPercentEncoding {
                print("snapshot => \(name)")
            }
        } catch let error {
            appDelegate.userAlertMessage("Snapshot failed", info: error.localizedDescription)
        }
    }
    

提交回复
热议问题