Webview截屏三种方式

作者: littleKang | 来源:发表于2016-03-19 10:55 被阅读7174次

    第一种方式

    通过调用webview.capturePicture(),得到一个picture对象,根据图像的宽和高创建一个Bitmap,再创建一个canvas,绑定bitmap,最后用picture去绘制。

    //获取Picture对象
    Picture picture = wv_capture.capturePicture();
    //得到图片的宽和高(没有reflect图片内容)
    int width = picture.getWidth();
    int height = picture.getHeight();
    if (width > 0 && height > 0) {
        //创建位图
        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        //绘制(会调用native方法,完成图形绘制)
        picture.draw(canvas);
     
    }
    

    这种方式可以获取webview中已加载的所有数据图像,也就是长截屏的效果。这种方式在Android 4.4以下是没有问题的,但是在5.0以上就行不通了。capturePicture()方法在4.4中废弃掉了,官方建议使用onDrow()方法来获取webview的bitmap快照。具体实现如下:

    //获取webview缩放率
    float scale = wv_capture.getScale();
    //得到缩放后webview内容的高度
    int webViewHeight = (int) (wv_capture.getContentHeight()*scale);
    Bitmap bitmap = Bitmap.createBitmap(wv_capture.getWidth(),webViewHeight, Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(bitmap);
    //绘制
    wv_capture.draw(canvas);
    

    但是此时在5.0+上会发现,截取的快照只显示了webview中显示出来的那部分,没有显示出来的部分是空白的。通过google找到了原因,在5.0+版本上,Android对webview做了优化,旨在减少内存占用以提高性能。因此在默认情况下会智能的绘制html中需要绘制的部分,其实就是当前屏幕展示的html内容,因此会出现未显示的图像是空白的。解决办法是调用enableSlowWholeDocumentDraw()方法。这个方法需要在webview创建之前调用,在Activity里就是在setContentView前去调用,此方法会有显著的性能开销。

    这里需要注意的是在传递webview的高度时,是通过缩放率计算的,这样就会算出绘制整个已加载的html内容所需的高度。如果没有这个缩放率,那么得到的快照就仅仅是这个html内容最上面的那一段。还有一个问题就是在5.0+系统上得到快照比较模糊,在其他版本上没有问题,不知道原因何在?

    第二种方式

    利用view的缓存功能。Android为了提高滚动等各方面的绘制速度,可以为每一个view建立一个缓存,使用 View.buildDrawingCache为自己的view建立相应的缓存, 这个cache就是一个bitmap对象。利用这个功能可以对整个屏幕视图进行截屏并生成Bitmap,也可以 获得指定的view的Bitmap对象。

    因此对于webview来说也可以使用这种方式,在使用getDrawingCache()方法获取bitmap对象前,先开启webview的缓存功能.

    webView.setDrawingCacheEnabled(true);
    ...
    Bitmap bitmap = webView.getDrawingCache();
    

    需要注意的是,在上述情况下,这个缓存bitmap对象只有一个,因此每次获取的bitmap指向的是同一块地址空间的缓存对象,如果在使用完bitmap后就立即回收掉这个对象,那么再次获取当前view的缓存对象时就会得到null。所以要在Activity销毁时进行回收,所以开启缓存的话会有性能开销。

    第三种方式

    比较简单,通过获取当前window的DecorView,然后绘制Bitmap对象。

    View view  = context.getWindow().getDecorView();
    Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(bitmap);
    view.draw(canvas);
    

    保存到文件

    try {
        String fileName = Environment.getExternalStorageDirectory().getPath()+"/webview_capture4.jpg";
        FileOutputStream fos = new FileOutputStream(fileName);
        //压缩bitmap到输出流中
        bitmap.compress(Bitmap.CompressFormat.JPEG, 70, fos);
        fos.close();
        Toast.makeText(WebviewFromGetDecorView.this, "截屏成功", Toast.LENGTH_LONG).show();
        } catch (Exception e) {
            Log.e(TAG, e.getMessage());
        }finally {
            if(bitmap!=null) {
                bitmap.recycle();
            }
    
        }
    

    具体demo猛戳这里:https://github.com/hsk256/WebviewCapture

    参考:

    http://developer.android.com/intl/zh-cn/reference/android/view/View.html

    http://blog.csdn.net/a443453087/article/details/8563037

    http://souly.cn/%E6%8A%80%E6%9C%AF%E5%8D%9A%E6%96%87/2016/01/05/DrawingCache%E8%A7%A3%E6%9E%90/

    相关文章

      网友评论

      • 想回老家了:enableSlowWholeDocumentDraw 有没有关闭的方法呢,因为一个页面的需求,动用整个app的性能开销,好像不太划算啊。
      • 猫KK:您好,假如webview 加载的网页可以横向滑动,用上面的方法都不能截下整个网页内容
      • fe425cd213fd:capturePicture() 和 getScale() 都已过期了。现在该用什么呢?求教。
      • Vanish136:对于某些网页特别长的,在调用bitmap.createBitmap()时会OOM,有没有更好的解决方案?
      • khunkk:那到底那种好呢?
      • Torang:楼主,你试试https://h5.m.taobao.com这个链接的截取是有问题的,你看看有没有解决方法呢?
      • hds2007:不觉明历!很有用!
        hds2007: @4e5c3aa3891d 不错啊,挺认真👍
        4e5c3aa3891d:是不明觉历
        4e5c3aa3891d:你打错了。
      • 57068ac23f65:感谢!解决我的大问题
      • 9d3520e9ca5a:不错
        littleKang: @OUYANGJIAN 😃谢谢

      本文标题:Webview截屏三种方式

      本文链接:https://www.haomeiwen.com/subject/oxehlttx.html