来自 adb 的 Nexus One 的屏幕截图?
Posted
技术标签:
【中文标题】来自 adb 的 Nexus One 的屏幕截图?【英文标题】:Screenshot of the Nexus One from adb? 【发布时间】:2011-02-17 22:07:45 【问题描述】:我的目标是能够键入一个单词命令并从通过 USB 连接的根 Nexus One 中获取屏幕截图。
到目前为止,我可以像这样拉取我认为是32bit 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
这会创建一个可爱的紫色图像,其中的部分与屏幕有点相似,但这绝不是一个干净的屏幕截图。
【问题讨论】:
【参考方案1】: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 上测试。
【讨论】:
更快:adb shell screencap -p \| uuencode o | uudecode -o out.png
(需要 linux+uudecode,base64 也可以)
@ce4,您应该写下您的评论作为答案。这是这个问题的最佳答案。
@Benjamin 这个问题已经有 >10 个答案了......而且它只是对 Ben 的答案的改进,仅适用于 linux 用户。
@ce4 的回答对我来说每张照片需要多花 1-2 秒的时间,所以 YMMV(除非意图是更快地打字)。【参考方案2】:
其实,还有一个非常简单的功能可以从你的安卓设备上截取屏幕截图:像这样编写简单的脚本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
。
【讨论】:
【参考方案3】:N1的frame buffer好像使用了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])
【讨论】:
【参考方案4】:使用我的 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。不过还是谢谢。 也适用于 SE Xperia X10。【参考方案5】:如果你安装了dos2unix,那么下面
adb shell screencap -p | dos2unix > screen.png
【讨论】:
这是我最喜欢的方法——非常简单!我为除文件名之外的所有内容设置了别名,以便在需要截屏时轻松使用。 这可能只对 Windows 准确,默认情况下它会在其 C 运行时内“帮助”将 LF 转换为 CRLF。在其他操作系统上,在那里运行 dos2unix 会损坏 png【参考方案6】:我相信迄今为止所有的帧缓冲区都是 RGB 565,而不是 888。
【讨论】:
【参考方案7】:现在我们有一个单行命令来截取屏幕截图。命令如下:
adb shell screencap -p | perl -pe 's/\x0D\x0A/\x0A/g' > screen.png
在您的终端中输入上述命令并按回车键。如果您希望将屏幕截图存储在任何特定位置,请在screen.png
之前给出路径(或)目录。
Source.
【讨论】:
谢谢佩德罗·巴西莱罗爵士。【参考方案8】:我认为 rgb32torgb888.py 应该是
sys.stdout.write(colour[0])
sys.stdout.write(colour[1])
sys.stdout.write(colour[2])
【讨论】:
是的,我必须交换 R 和 B 通道才能从 N1 获得正确的颜色。【参考方案9】:我希望我的脚本可能有用。我在我的银河选项卡上使用它,它运行良好,但您可以更改默认分辨率。不过,它需要“zsh”外壳:
#!/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 $VRESx$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.$$
【讨论】:
我不是很清楚——如果你提供分辨率,它(可能)可以在任何安卓上工作。【参考方案10】:在 MyTouch Slide 3G 上,我最终在屏幕截图中交换了红色和蓝色通道。这是在这种情况下其他任何人的正确 ffmpeg 咒语: (值得注意的部分:-pix_fmt bgr32)
ffmpeg -vframes 1 -vcodec rawvideo -f rawvideo -pix_fmt bgr32 -s 320x480 -i fb0 -f image2 -vcodec png image.png
感谢 Patola 提供的方便的 shell 脚本!至少对于我的手机而言,无需修改即可正确定向纵向模式 (320x480),因此他的脚本结尾变为:
# assuming 'down' is towards the keyboard or usb jack
# in landscape and protrait modes respectively
(( $PORTRAIT )) || mogrify -rotate 270 "$outputfile"
/bin/rm -f fb0.$$ fb0b.$$
【讨论】:
【参考方案11】:rgb565
代替 8888
也适用于模拟器
【讨论】:
【参考方案12】:有点复杂/过度,但它同时处理屏幕截图和帧缓冲区场景(以及计算分辨率)。
#!/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=$HRESx$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
【讨论】:
【参考方案13】:这可能与问题Reading binary Data from adb shell's stdout 有关,其中 adb 尝试为您进行 LF 到 CRLF 的转换(它可能只是 adb 的 Windows 版本)。我个人在将 \n 转换为 \r\r\n 时遇到了麻烦,因此作为一种转换方式,最好使用 [1] 处的代码或使用。
对我来说(在 cygwin 中)运行它:
adb shell 'cat /dev/graphics/fb0' | perl -pi -e 's/\r\r\n/\n/g'
似乎有帮助
除此之外,尝试将宽度和高度与文件的大小进行比较。文件大小应该可以被Width * height
整除,如果不是这种情况,那么 adb 工具会自动为您做事,或者它是一种比 rgb545 或 rgb8888 更奇特的格式。
如果只是颜色问题(即:结果图像中的所有内容都在正确的位置),那么您可能需要考虑交换红色和蓝色通道,因为某些系统(通常)使用字节顺序 BGRA 而不是 RGBA。
【讨论】:
【参考方案14】:完全自动化此过程的一种方法是创建一个脚本,将当前时间戳添加到文件名中。这样,你就不用自己写文件名了,你所有的截图都有不同的名字,而且你的截图是按时间排序的。
bash 脚本示例:
#! /bin/bash
filename=$(date +"_%Y-%m-%d-%H:%M")
/PATH_TO_ANDROID_SDK/platform-tools/adb -d shell screencap -p | perl -pe 's/\x0D\x0A/\x0A/g' > screenshot$filename.png
这将创建一个名为 screenshot_2014-01-07-10:31.png 的文件
【讨论】:
以上是关于来自 adb 的 Nexus One 的屏幕截图?的主要内容,如果未能解决你的问题,请参考以下文章
当我尝试使用 adb shell 打开数据库时,为啥在根植的 Nexus One 上出现“sqlite3:未找到”错误?
sh Android设备带有ADB屏幕截图 - 来自http://blog.shvetsov.com/2013/02/grab-android-screenshot-to-computer-via.h