从浏览器内核chromium34的代码移植到39的时候,发现之前做的截图接口不好用了,仔细分析,发现两个截图实现的机制不一样,又去分析了一下39的相关代码,现在把34和39的截图的实现方式和大家分享一下。这期间的版本,到底是哪个版本进行了修改,就不去一一查看了。
众所周知,chromium展示网页是通过一个surfaceView不断刷新来展示的网页的。那么截图就成为一个问题,按照传统的截图方式不可以,baidu搜索onDraw方法中进行处理。chromium34在java层的代码中就是使用这种方法进行处理的,下面分别说下chromium34和39在实现截图功能上的方式。
chromium34:
在ContentViewRenderView中创建一个surfaceView,重写onDraw方法,在onDraw方法中调用nativeCompositeToBitmap(mNativeContentViewRenderView, bitmap),将createbitmap后的bitmap对象传进去,然后再调用canvas.drawBitmap(bitmap, 0, 0, null);就得到了webview网页的截图。(此webView并非系统webkit包下的webview,系统webView的截图方式并非如此,大家可以直接在eclipse里面F3查看源码就可以了)
chromium39:
ContentReadbackHandler中有一个方法:
@CalledByNative
private void notifyGetBitmapFinished(int readbackId, Bitmap bitmap) {
GetBitmapCallback callback = mGetBitmapRequests.get(readbackId);
if (callback != null) {
mGetBitmapRequests.delete(readbackId);
callback.onFinishGetBitmap(bitmap);
} else {
// readback Id is unregistered.
assert false : "Readback finished for unregistered Id: " + readbackId;
}
}
很明显这是一个c++层调用java层的回调函数,我明确的告诉你,传回来的bitmap就是截图。
我们在需要的类中自己写一个函数,传入一个callBack,需要截图的时候发送一个消息,就可以从回调中拿到bitmap对象啦
public void getWebViewBitmap(float scale, Rect srcRect, final WebView.GetBitmapCallback callback) {
if (null == mContentViewRenderView || null == mContentViewCore) {
callback.onFinishGetBitmap(null);
return;
}
ContentReadbackHandler.GetBitmapCallback content_read_callback = new ContentReadbackHandler.GetBitmapCallback() {
public void onFinishGetBitmap(Bitmap bitmap) {
if (null == callback) return;
callback.onFinishGetBitmap(bitmap);
}
};
ContentReadbackHandler handler = mContentViewRenderView.getContentReadbackHandler();
handler.getContentBitmapAsync(scale, srcRect, mContentViewCore, content_read_callback);
}
另外:
关于chromium34的更多详细的讲解,以及详细的代码,可以查看下面的博客文章:
http://blog.csdn.net/u011882998/article/details/32708811
至于从哪个版本修改的底层实现方式,我也不再去查了。小伙伴们可以看一下ContentViewRenderView这个类对应的c ++文件 content_view_render_view.cc中是否有下面的方法:jboolean ContentViewRenderView::CompositeToBitmap(JNIEnv* env, jobject obj,
jobject java_bitmap) {
gfx::JavaBitmap bitmap(java_bitmap);
if (!compositor_ || bitmap.format() != ANDROID_BITMAP_FORMAT_RGBA_8888)
return false;
return compositor_->CompositeAndReadback(bitmap.pixels(),
gfx::Rect(bitmap.size()));
}
关于bitmap图片保存成文件的代码实现(java和c++),大家可以看下下面的博客文章:
http://blog.csdn.net/fingding/article/details/44242687
最后,说下在完成这个功能来的感悟吧。在从chromium34迁移代码到39的时候,发现原来chromium实现截图的native方法不见了,怎么办呢?把native方法移植过来吗?仔细查了一圈,代码量太庞大,牵扯太多不靠谱。在c++代码中实现截图,回调给java层,当然没问题。但是我们小看了谷歌,我们竟然没有发现上面的接口,后来回想起来,也觉得自己傻傻的,有很多东西,我们根本不需要自己去实现,人家都已经弄好了的代码,直接用就行了。
在修改chromium源码的时候,我们很多时候都不是代码的创造者,而是代码的搬运工。我们甚至很清楚的知道,不管是上层还是底层,java代码还是c++代码,更多的改动或者新增就意味可能带来更多的问题或者潜伏着的地雷,说不定哪天带来灾难性的后果。
用有限的资源、简单的方式实现可靠的功能,才是王道!