• 用WKWebView 截取整个Html页面


    以前使用UIWebview时,想截取整个页面,可以调整内部scrollView的frame,之后调用 scrollView的layer的 render 方法,很方便。

    但是在WKWebView上,行不通。

    我觉得以前的UIWebview其实是把整个页面都渲染在内存中,只是我们看不到。而WKWebView为了优化内存,只渲染WKWebView的Frame大小的内容。

    所以想用WKWebview截取整个页面,必须放大WKWebview的frame。

     webView.frame = CGRect(x: 0, y: 0,  webView.scrollView.frame.size.width, height: webView.scrollView.contentSize.height);

    改变了frame之后,我们就可以利用scrollView.layer.render 去渲染整个页面了。

    但是这时候又出现了另一个问题:  渲染网页是需要时间的,把webview的frame扩大后,我们不知道什么时候,系统完成了渲染。比如下面这个例子:

    @IBAction func takeScreenshot(){
            
            webView.frame = CGRect(x: 0, y: 0,  webView.scrollView.frame.size.width, height: webView.scrollView.contentSize.height);
            
    
                let scrollView = self.webView.scrollView
                
                UIGraphicsBeginImageContextWithOptions(self.webView.scrollView.contentSize,false, UIScreen.main.scale)
                
                scrollView.layer.render(in: UIGraphicsGetCurrentContext()!)
                
                let image = UIGraphicsGetImageFromCurrentImageContext()
                
                let pngData = UIImagePNGRepresentation(image!);
                
                
                let dstPath = NSHomeDirectory()+"/Documents/test.png"
                let dstUrl = URL(fileURLWithPath: dstPath)
                do{
                    try  pngData?.write(to: dstUrl, options: .atomicWrite)
                }catch{
                    
                    
                }
                
                print("dest is %@",dstUrl);
                
                
                UIGraphicsEndImageContext()
        }
        

    由于立即调用了截图函数,webView没有足够的时间渲染,只多渲染了一小部分。

    之后,我用下面的代码进行测试,注意,这里延时了0.3s,给了webview一定的渲染时间:

        @IBAction func takeScreenshot(){
            
            webView.frame = CGRect(x: 0, y: 0,  webView.scrollView.frame.size.width, height: webView.scrollView.contentSize.height);
            
            
            DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()+0.3) {
                let scrollView = self.webView.scrollView
                
                UIGraphicsBeginImageContextWithOptions(self.webView.scrollView.contentSize,false, UIScreen.main.scale)
                
                scrollView.layer.render(in: UIGraphicsGetCurrentContext()!)
                
                let image = UIGraphicsGetImageFromCurrentImageContext()
                
                let pngData = UIImagePNGRepresentation(image!);
                
                
                let dstPath = NSHomeDirectory()+"/Documents/test.png"
                let dstUrl = URL(fileURLWithPath: dstPath)
                do{
                    try  pngData?.write(to: dstUrl, options: .atomicWrite)
                }catch{
                    
                    
                }
                
                print("dest is %@",dstUrl);
                
                
                UIGraphicsEndImageContext()
           }
            
        }
        

    下面是结果的截图,一切正常:

    那么,如果网页更长,0.3秒一定也不够用,我们怎么知道该延时多少呢?

    这时候我又发现了一个函数,是属于UIView的,drawHierarchy,根据api描述,第二个参数好像和渲染有关,能不能解决我们的问题呢,继续测试:

     @IBAction func takeScreenshot(){
            
            webView.frame = CGRect(x: 0, y: 0,  webView.scrollView.frame.size.width, height: webView.scrollView.contentSize.height);
            
       
                let scrollView = self.webView.scrollView
                
                UIGraphicsBeginImageContextWithOptions(self.webView.scrollView.contentSize,false, UIScreen.main.scale)
                
    
                self.webView.drawHierarchy(in: CGRect(x: 0, y: 0,  self.webView.scrollView.frame.size.width, height: self.webView.scrollView.contentSize.height), afterScreenUpdates: true)
                
        
                let image = UIGraphicsGetImageFromCurrentImageContext()
                
                let pngData = UIImagePNGRepresentation(image!);
                
                
                let dstPath = NSHomeDirectory()+"/Documents/test.png"
                let dstUrl = URL(fileURLWithPath: dstPath)
                do{
                    try  pngData?.write(to: dstUrl, options: .atomicWrite)
                }catch{
                    
                    
                }
                
                print("dest is %@",dstUrl);
                
                
                UIGraphicsEndImageContext()
           
            
        }

    结果还是不行,效果和使用layer的render方法一样!看来afterScreenUpdates这个参数跟网页的渲染无关了。

    那么把Webview frame直接扩大为html内容的大小并截图的方式其实是很有问题的,截图时机不好掌握, 内存和cpu的占用也会很大。

    这里要推荐一个github上的项目,https://github.com/startry/SwViewCapture, 它的解决思路如下:

    1. 截图时机的掌握:每次通过调整视图frame,只渲染一屏的截图,速度很快,只需稍为延迟,即可保证完美截图。

    2.内存和cpu:由于每次只处理一屏幕的截图,内容很少,对cpu和内存的冲击都很小。

    下面贴出其中的关键代码:

     fileprivate func swContentPageDraw (_ targetView: UIView, index: Int, maxIndex: Int, drawCallback: @escaping () -> Void) {
            
            // set up split frame of super view
            let splitFrame = CGRect(x: 0, y: CGFloat(index) * targetView.frame.size.height,  targetView.bounds.size.width, height: targetView.frame.size.height)
            // set up webview frame
            var myFrame = self.frame
            myFrame.origin.y = -(CGFloat(index) * targetView.frame.size.height)
            self.frame = myFrame
            
            DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + Double(Int64(0.3 * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)) { () -> Void in
                
                targetView.drawHierarchy(in: splitFrame, afterScreenUpdates: true)
                
                if index < maxIndex {
                    self.swContentPageDraw(targetView, index: index + 1, maxIndex: maxIndex, drawCallback: drawCallback)
                }else{
                    drawCallback()
                }
            }
        }
  • 相关阅读:
    Miniconda 虚拟环境安装及应用
    python random使用方法
    MyQR库自动为网址生成二维码
    setResult()的调用时机
    Eclipse里选中一个变量后,这个类里的该变量不变色了?
    Android开发的技术层次
    最封闭的开源系统,话说Android的八宗罪
    制度是绝情的,管理是无情的,执行是合情的
    windows下eclipse搭建android_ndk开发环境
    UI/GUI/UE/UX/ID/UED/UCD的区别
  • 原文地址:https://www.cnblogs.com/breezemist/p/7569798.html
Copyright © 2020-2023  润新知