Android之高效率截圖


本文來自網易雲社區

作者:孫聖翔


在一張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+款雲產品! 


更多網易研發、產品、運營經驗分享請訪問網易雲社區


相關文章:
【推薦】 如何實現最佳的跨平台游戲體驗?Unity成亮解密實時渲染
【推薦】 全局腳手架了解一下【fle-cli】
【推薦】 一文了解安卓APP逆向分析與保護機制


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM