

Android之高效率截图
source link: https://studygolang.com/articles/15101?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

本文来自网易云社区
作者:孙圣翔
在一张Android手机上截图有好多办法,为了能够高效率的截图,我几乎把所有的方法都尝试了一般。走了好多路,也遇到了好多的问题。
只是想记录下这其中的不容易。
下面所有的测试都是用的我的三星 S4.
屏幕分辨率 1080x1920
androidviewclient
截图速度: 4.5s
最开始截图用的是 google官方提供的纯python库androidviewclient,代码的地址在 https://github.com/dtmilano/AndroidViewClient
基于adb协议,只能在电脑上用。最初被我用在的一个手游自动化测试工具 airtest 上面。使用它很简单,我写个简单的例子
from com.dtmilano.android.viewclient import ViewClient c, _ = ViewClient.connectToDeviceOrExit(verbose=False, serialno='10.242.74.241:5555') s = c.takeSnapshot() s.save('snapshot.png', 'PNG')
不过这个python库也有坑人的地方。它更新到pypi的时候,所有的历史版本都找不到。使得可以更新过去,但是更新不回来。
最新的版本在有些机器上还跑不了。截图的时候某些手机还会出现图片缺少颜色的问题。
screencap
截图速度: 2.0s
Android手机上自带有一个截图工具,一般都是被放在了/system/bin/screencap下。
使用的时候需要在电脑上安装adb,然后adb shell进入shell环境,使用的时候,需要生成一个临时图片在手机上,然后把照片从手机上传输回来。
可以写成一个批处理脚本
@echo off adb shell screencap -p /sdcard/snapshot.png adb pull /sdcard/snapshot.png adb shell rm /sdcard/snapshot.png
这个样子截图,要比androidviewclient的稳定性好很多。只是需要生成一个临时文件,感觉好别扭。
APK程序直接截图
截图速度: < 1s
stackoverflow上也有不少代码例子。apk必须用java写,意味着我必须学一下java了,买了一本书《Android第一行代码》。
学习了2个多星期,总算入门了。然后写了一个手机app截图。截图代码我就不贴了,这个比较长一点,网上也有很多例子。
这种方法截图效率在1s以内。不过只有在当前App在前台运行的时候才可以截图。就算写成Service也不行。
后来想想,截取不到图也算合理。假如一个App可以截取到其他App运行时的图片,岂不是越权了,用户的隐私还怎么保证。
既然这样,只能放弃了。
ASL
之后有幸看到了google出的一个android-screenshot-library的东西,简称ASL。代码在 http://code.google.com/p/android-screenshot-library/
看到这个东西真是让人欣喜若狂。立马下载下来试了试,心情立马就不好了,截图来的图,竟然是黑屏。接着又借了4个手机试验。
结果截图只有一台手机截出来的图能看(还是缺少一个颜色通道的那种)。 看看了代码实现的原理,是直接读取framebuffer。
这个地方我解释下:
在linux中,所有的东西通通都可以映射成文件,连屏幕映射成了文件。android的在/dev/graphics/fb0。
通过读取fb0中的数据,然后在根据一些算法就可以还原出屏幕的图像了。
还有一个库, http://code.google.com/p/android-fb2png/ 看代码原理应该和ASL差不多,不过实现了PC端的一个adb_screenshot的程序。
没法截图怎么用啊,放弃吧。 哎
重回screencap, Golang重写截图程序。
截图速度: 1s
好在android是开源的,直接可以翻到screencap实现的源码。意外的发现他有两种输出格式。
一种是png格式 (耗时1.5s)
还有一种是原始的图片格式(这种原始的格式,跟bmp差不多)。 试验了下,好使400ms
之前看过一个韩国人写的remotedroid < https://code.google.com/p/remoteroid/ > 截图速度快的让人震惊。
所以我在想是不是screencap中png的压缩算法有问题。参考下代码中,他输出的格式。用Go语言写了一个转化的程序。
// TakeSnapshot by cmd: /system/bin/screencap func TakeSnapshot() (img *image.RGBA, err error) { scrbf = bytes.NewBuffer(nil) cmd := exec.Command("screencap") cmd.Stdout = scrbf if err = cmd.Run(); err != nil { return } var width, height, format int32 binary.Read(scrbf, binary.LittleEndian, &width) binary.Read(scrbf, binary.LittleEndian, &height) err = binary.Read(scrbf, binary.LittleEndian, &format) if err != nil { return } img = image.NewRGBA(image.Rectangle{image.ZP, image.Point{int(width), int(height)}}) return } func main(){ s, _ := TakeSnapshot() out, _ := os.Create("snapshot.png") defer out.Close() png.Encode(out, s) }
利用总共用时1.2s的样子。比之前用screencap 2s快了不少哎。感觉似乎还可以更快点。把png改成jpeg试试。
func main(){ s, _ := TakeSnapshot() out, _ := os.Create("snapshot.png") defer out.Close() jpeg.Encode(out, s, jpeg.Options{60}) }
这种方法变成了1.1s, 感觉似乎还可以更快点。 需要稍微复杂点,需要减少内存申请和拷贝的次数。
// TakeSnapshot by cmd: /system/bin/screencap var SCRBUFLEN int func TakeSnapshot() (img *image.RGBA, err error) { var scrbf *bytes.Buffer if SCRBUFLEN == 0 { scrbf = bytes.NewBuffer(nil) } else { scrbf = bytes.NewBuffer(make([]byte, 0, SCRBUFLEN)) } cmd := exec.Command("screencap") cmd.Stdout = scrbf if err = cmd.Run(); err != nil { return } var width, height, format int32 binary.Read(scrbf, binary.LittleEndian, &width) binary.Read(scrbf, binary.LittleEndian, &height) SCRBUFLEN = int(width * height * 4 err = binary.Read(scrbf, binary.LittleEndian, &format) if err != nil { return } w, h := int(width), int(height) img = &image.RGBA{scrbf.Bytes(), 4 * w, image.Rect(0, 0, w, h)} return }
改完后,变成1.0s了。 终于到了还算可以接受的程度。 整理下代码终于可以让他抛头露面了。
https://github.com/netease/airinput
这就是我在做Android截图的时候,所遇到的大部分问题。要知道截个图是多么的不容易。 另外想说,请一定不要放弃,总会有办法的。
网易云 免费体验馆 ,0成本体验20+款云产品!
更多网易研发、产品、运营经验分享请访问 网易云社区 。
相关文章:
【推荐】 为何要在网站上设置的验证码
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK