从adb获取Nexus One的屏幕截图?

46

我的目标是能够键入一个单词命令并从通过 USB 连接的已 root 的 Nexus One 获取屏幕截图。

到目前为止,我可以获取帧缓冲区,我相信这是一个 32位 xRGB888 原始图像,通过以下方式进行提取:

adb pull /dev/graphics/fb0 fb0

不过,从那里开始,我很难将它转换为png格式。我正在尝试使用ffmpeg进行转换,如下所示:

ffmpeg -vframes 1 -vcodec rawvideo -f rawvideo -pix_fmt rgb8888 -s 480x800 -i fb0 -f image2 -vcodec png image.png

这会生成一张可爱的紫色图像,其中有些部分模糊地类似于屏幕,但并不是完全清晰的截图。

14个回答

92

ICS的一个极为简单的解决方案是从命令行使用以下内容:

adb shell /system/bin/screencap -p /sdcard/screenshot.png
adb pull /sdcard/screenshot.png screenshot.png

这将会在当前目录保存screenshot.png文件。

在一个运行4.0.3的三星Galaxy SII & SII上进行过测试。


8
更快的方式:adb shell screencap -p | uuencode -m - | uudecode -o out.png(需要Linux和uudecode,但base64也可以使用) - ce4
@ce4,你应该把你的评论写成答案。这是这个问题最好的答案。 - Jade
@Benjamin,这个问题已经有超过10个答案了...而且它只是Ben的答案的改进,只适用于Linux用户。 - ce4
@ce4的答案对我来说每张图片要多花费1-2秒钟的时间,所以你的情况可能会有所不同(除非意图是为了更快地打字)。 - The Compiler

13

实际上,还有一种非常简单的方法可以从你的Android设备中抓取截图:编写一个像这样的简单脚本1.script

# Imports the monkeyrunner modules used by this program
from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice

# Connects to the current device, returning a MonkeyDevice object
device = MonkeyRunner.waitForConnection()

# Takes a screenshot
result = device.takeSnapshot()

# Writes the screenshot to a file
result.writeToFile('1.png','png')

然后调用 monkeyrunner 1.script


11

看起来,N1的帧缓冲使用RGB32编码(每像素32位)。

这是我使用ffmpeg的脚本:

adb pull /dev/graphics/fb0 fb0
dd bs=1920 count=800 if=fb0 of=fb0b
ffmpeg -vframes 1 -vcodec rawvideo -f rawvideo -pix_fmt rgb32 -s 480x800 -i fb0b -f image2 -vcodec png fb0.png

另一种方法是从这里描述的ADP1方法得出的 http://code.lardcave.net/entries/2009/07/27/132648/

adb pull /dev/graphics/fb0 fb0
dd bs=1920 count=800 if=fb0 of=fb0b
python rgb32torgb888.py <fb0b >fb0b.888
convert -depth 8 -size 480x800 RGB:fb0b.888 fb0.png

Python脚本 'rgb32torgb888.py':

import sys
while 1:
 colour = sys.stdin.read(4)
 if not colour:
  break
 sys.stdout.write(colour[2])
 sys.stdout.write(colour[1])
 sys.stdout.write(colour[0])

7

使用我的HTC Hero(因此从480x800调整为320x480),如果我使用rgb565而不是8888,则可以正常工作:

ffmpeg -vframes 1 -vcodec rawvideo -f rawvideo -pix_fmt rgb565 -s 320x480 -i fb0 -f image2 -vcodec png image.png

是的,这对我的Magic/Dream/Hero有效,但在N1上无效。还是谢谢。 - Marcus
同样适用于SE Xperia X10。 - Jørgen R

6
如果您已经安装了dos2unix,则可以执行以下操作:
adb shell screencap -p | dos2unix > screen.png

这是我最喜欢的方法 - 非常简单!我为除文件名以外的所有内容设置了别名,以便在需要截屏时轻松使用。 - BVB
这可能只适用于Windows,在其中默认情况下,它会“有益地”将LF转换为CRLF。在其他操作系统上运行dos2unix会破坏PNG文件。 - Ángel

2

我认为到目前为止所有的帧缓冲都是RGB 565,而不是888。


2
现在我们有了一个单行命令来截屏。该命令如下:
adb shell screencap -p | perl -pe 's/\x0D\x0A/\x0A/g' > screen.png

在终端中输入上述命令并按回车键。如果你想将截图存储在特定位置,请在screen.png之前给出路径或目录。
来源: 原文链接

谢谢你,Pedro Brasileiro先生。 - parthiban

1

希望我的脚本能对你有所帮助。我在我的Galaxy Tab上使用它,它运行得非常完美,但是你可以更改默认分辨率。不过需要使用“zsh” shell:

#!/bin/zsh

# These settings are for the galaxy tab.
HRES=600
VRES=1024

usage() {
  echo "Usage: $0 [ -p ] outputfile.png"
  echo "-- takes screenshot off your Galaxy Tab Android phone."
  echo " -p: portrait mode"
  echo " -r X:Y: specify resolution, e.g. -r 480:640 specifies that your cellphone has 480x640 resolution."
  exit 1
}

PORTRAIT=0 # false by default

umask 022

[[ ! -w . ]] && {
  echo "*** Error: current directory not writeable."
  usage
}

[[ ! -x $(which mogrify) ]] && {
  echo "*** Error: ImageMagick (mogrify) is not in the PATH!"
  usage
}

while getopts "pr:" myvar
do
  [[ "$myvar" == "p" ]] && PORTRAIT=1
  [[ "$myvar" == "r" ]] && {
    testhres="${OPTARG%%:*}" # remove longest-matching :* from end
    testvres="${OPTARG##*:}" # remove longest-matchung *: from beginning
    if [[ $testhres == <0-> && $testvres == <0-> ]] # Interval: from 0 to infinite. Any value would be: <->
    then
      HRES=$testhres
      VRES=$testvres
    else
      echo "Error! One of these values - '${testhres}' or '${testvres}' - is not numeric!"
      usage
    fi
  }
done
shift $((OPTIND-1))

[[ $# < 1 ]] && usage

outputfile="${1}"

blocksize=$((HRES*4))
count=$((VRES))

adb pull /dev/graphics/fb0 fb0.$$
/bin/dd bs=$blocksize count=$count if=fb0.$$ of=fb0b.$$
/usr/bin/ffmpeg -vframes 1 -vcodec rawvideo -f rawvideo -pix_fmt rgb32 -s ${VRES}x${HRES} -i fb0b.$$ -f image2 -vcodec png "${outputfile}"

if (( ${PORTRAIT} ))
then
  mogrify -rotate 270 "${outputfile}"
else
  mogrify -flip -flop "${outputfile}"
fi

/bin/rm -f fb0.$$ fb0b.$$

我表达不够清晰 -- 只要提供分辨率,它(很可能)可以在任何安卓设备上运行。 - Patola

1

我认为rgb32torgb888.py应该是这样的:

 sys.stdout.write(colour[0])
 sys.stdout.write(colour[1])
 sys.stdout.write(colour[2])

是的,我不得不交换R和B通道才能从我的N1获得正确的颜色。 - Julio Gorgé

1
有点详细/过度,但它可以处理屏幕截图和帧缓冲场景(还可以找出分辨率)。
#!/bin/bash
#
# adb-screenshot - simple script to take screenshots of android devices
#
# Requires: 'ffmpeg' and 'adb' to be somewhere in the PATH
#
# Author: Kevin C. Krinke <kevin@krinke.ca>
# License: Public Domain

# globals / constants
NAME=$(basename $0)
TGT=~/Desktop/${NAME}.png
SRC=/sdcard/${NAME}.png
TMP=/tmp/${NAME}.$$
RAW=/tmp/${NAME}.raw
FFMPEG=$(which ffmpeg)
ADB=$(which adb)
DD=$(which dd)
USB_DEVICE=""

# remove transitory files if exist
function cleanup () {
    [ -f "${RAW}" ] && rm -f "${RAW}"
    [ -f "${TMP}" ] && rm -f "${TMP}"
    [ -z "$1" ] && die "aborting process now."
    exit 0
}

# exit with an error
function die () {
    echo "Critical Error: $@"
    exit 1
}

# catch all signals and cleanup / dump
trap cleanup \
    SIGHUP SIGINT SIGQUIT SIGILL SIGTRAP SIGABRT SIGEMT SIGFPE \
    SIGKILL SIGBUS SIGSEGV SIGSYS SIGPIPE SIGALRM SIGTERM SIGURG \
    SIGSTOP SIGTSTP SIGCONT SIGCHLD SIGTTIN SIGTTOU SIGIO SIGXCPU \
    SIGXFSZ SIGVTALRM SIGPROF SIGWINCH SIGINFO SIGUSR1 SIGUSR2

# adb is absolutely required
[ -x "${ADB}" ] || die "ADB is missing!"

# cheap getopt
while [ $# -gt 0 ]
do
    case "$1" in
        "-h"|"--help")
            echo "usage: $(basename $0) [-h|--help] [-s SERIAL] [/path/to/output.png]"
            exit 1
            ;;
        "-s")
            [ -z "$2" ] && die "Missing argument for option \"-s\", try \"${NAME} --help\""
            HAS_DEVICE=$(${ADB} devices | grep "$2" )
            [ -z "${HAS_DEVICE}" ] && die "No device found with serial $2"
            USB_DEVICE="$2"
            ;;
        *)
            [ -n "$1" -a -d "$(dirname $1)" ] && TGT="$1"
            ;;
    esac
    shift
done

# prep target with fire
[ -f "${TGT}" ] && rm -f "${TGT}"

# tweak ADB command line
if [ -n "${USB_DEVICE}" ]
then
    ADB="$(which adb) -s ${USB_DEVICE}"
fi

# calculate resolution
DISPLAY_RAW=$(${ADB} shell dumpsys window)
HRES=$(echo "${DISPLAY_RAW}" | grep SurfaceWidth  | head -1 | perl -pe 's/^.*\bSurfaceWidth\:\s*(\d+)px\b.*$/$1/')
VRES=$(echo "${DISPLAY_RAW}" | grep SurfaceHeight | head -1 | perl -pe 's/^.*\bSurfaceHeight\:\s*(\d+)px\b.*$/$1/')
RES=${HRES}x${VRES}

# check for screencap binary
HAS_SCREENCAP=$(${ADB} shell "[ -x /system/bin/screencap ] && echo 1 || echo 0" | perl -pe 's/\D+//g')
if [ "$HAS_SCREENCAP" == "1" ]
then # use screencap to get the image easy-peasy
    echo -n "Getting ${RES} screencap... "
    ( ${ADB} shell /system/bin/screencap ${SRC} 2>&1 ) > /dev/null
    [ "$?" != "0" ] && die "Failed to execute screencap"
    ( ${ADB} pull ${SRC} ${TMP} 2>&1 ) > /dev/null
    [ "$?" != "0" ] && die "Failed to pull png image"
    ( ${ADB} shell rm ${SRC} 2>&1 ) > /dev/null
    [ "$?" != "0" ] && die "Failed to remove png image"
    mv ${TMP} ${TGT}
    echo "wrote: ${TGT}"
else # fetch a framebuffer snapshot
    # ffmpeg is only needed if device is pre-ICS
    [ -x "${FFMPEG}" ] || die "FFMPEG is missing!"
    [ -x "${DD}" ] || die "DD is missing!"
    echo -n "Getting ${RES} framebuffer... "
    ( ${ADB} pull /dev/graphics/fb0 ${RAW} 2>&1 ) > /dev/null
    [ "$?" != "0" ] && die "Failed to pull raw image data"
    # calculate dd parameters
    COUNT=$((HRES*4))
    BLOCKSIZE=$((VRES))
    ( ${DD} bs=${BLOCKSIZE} count=${COUNT} if=${RAW} of=${TMP} 2>&1 ) > /dev/null
    [ "$?" != "0" ] && die "Failed to realign raw image data"
    ( ${FFMPEG} -vframes 1 -vcodec rawvideo -f rawvideo -pix_fmt rgb32 -s ${RES} -i ${TMP} -f image2 -vcodec png ${TGT} 2>&1 ) > /dev/null
    [ "$?" != "0" ] && die "Failed to encode PNG image"
    echo "wrote: ${TGT}"
fi

# exit app normal
cleanup 1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接