Mon objectif est de pouvoir taper une commande à un mot et obtenir une capture d'écran d'un Nexus One rooté connecté par USB.
Jusqu'à présent, je peux obtenir le framebuffer qui je crois est un 32bit xRGB888
image brute en la tirant comme ceci:
adb pull /dev/graphics/fb0 fb0
À partir de là cependant, j'ai du mal à le convertir en png. J'essaie avec ffmpeg comme ceci:
ffmpeg -vframes 1 -vcodec rawvideo -f rawvideo -pix_fmt rgb8888 -s 480x800 -i fb0 -f image2 -vcodec png image.png
Cela crée une belle image violette qui a des parties qui ressemblent vaguement à l'écran, mais ce n'est en aucun cas une capture d'écran nette.
Une solution beaucoup plus simple pour ICS consiste à utiliser ce qui suit à partir de la ligne de commande
adb Shell /system/bin/screencap -p /sdcard/screenshot.png
adb pull /sdcard/screenshot.png screenshot.png
Cela enregistrera le fichier screenshot.png dans le répertoire courant.
Testé sur un Samsung Galaxy SII et SII exécutant 4.0.3.
En fait, il existe une autre possibilité très simple de saisir une capture d'écran de votre appareil Android: écrire un script simple 1.script
comme ça:
# 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')
et appelez monkeyrunner 1.script
.
Il semble que le tampon de trame de N1 utilise le codage RGB32 (32 bits par pixel).
Voici mon script utilisant 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
Une autre façon dérivée de la méthode ADP1 décrite ici 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
Script 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])
En utilisant mon HTC Hero (et donc en ajustant de 480x800 à 320x480), cela fonctionne si j'utilise rgb565 au lieu de 8888:
ffmpeg -vframes 1 -vcodec rawvideo -f rawvideo -pix_fmt rgb565 -s 320x480 -i fb0 -f image2 -vcodec png image.png
Si vous avez installé dos2unix, alors ce qui suit
adb Shell screencap -p | dos2unix > screen.png
Je crois que tous les tampons d'image à ce jour sont RVB 565, pas 888.
Nous avons maintenant une commande sur une seule ligne pour faire une capture d'écran. La commande comme suit:
adb Shell screencap -p | Perl -pe 's/\x0D\x0A/\x0A/g' > screen.png
Tapez la commande ci-dessus dans votre terminal et appuyez sur Entrée. Si vous souhaitez que la capture d'écran soit stockée dans un emplacement spécifique, indiquez le répertoire chemin (ou) avant screen.png
.
Source .
Un peu élaboré/excessif, mais il gère à la fois les scénarios de capture d'écran et de framebuffer (ainsi que la résolution de la résolution).
#!/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 <[email protected]>
# 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
Sur le MyTouch Slide 3G, je me suis retrouvé avec les canaux rouges et bleus échangés dans mes captures d'écran. Voici l'incantation ffmpeg correcte pour toute autre personne dans cette situation: (la partie notable: - pix_fmt bgr32)
ffmpeg -vframes 1 -vcodec rawvideo -f rawvideo -pix_fmt bgr32 -s 320x480 -i fb0 -f image2 -vcodec png image.png
Merci à Patola pour le script Shell pratique! Au moins pour mon téléphone, aucune mogrification n'est nécessaire pour s'orienter correctement en mode portrait (320x480), et donc la fin de son script devient:
# 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.$$
rgb565
au lieu de 8888
fonctionne également sur l'émulateur
Cela peut être lié au problème Lecture des données binaires depuis la sortie standard d'Adb Shell où adb tente de faire LF en conversion CRLF pour vous (c'est probablement juste la version Windows d'Adb Personnellement, j’ai eu des problèmes avec sa conversion\n en\r\r\n, donc pour le convertir, il est bon d’utiliser le code à [ 1 ] ou d’utiliser.
pour moi le faire fonctionner avec (dans cygwin): adb Shell 'cat /dev/graphics/fb0' | Perl -pi -e 's/\r\r\n/\n/g'
semblait aider
à part cela, essayez de comparer la largeur et la hauteur à la taille du fichier. La taille du fichier doit être divisible par Width * height
si ce n'est pas le cas, alors l'outil adb fait automatiquement les choses pour vous ou c'est un format plus exotique que rgb545 ou rgb8888.
si c'est juste un problème de couleur (c'est-à-dire que tout dans l'image du résultat est au bon endroit), vous voudrez peut-être envisager d'échanger les canaux rouge et bleu car certains systèmes (en général) utilisent l'ordre des octets BGRA au lieu de RGBA.
Un moyen d'automatiser complètement ce processus consiste à créer un script qui ajoute l'horodatage actuel au nom de fichier. De cette façon, vous n'avez pas à écrire le nom du fichier vous-même, toutes vos captures d'écran ont un nom différent et vos captures d'écran sont triées par heure.
Exemple de script 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
Cela va créer un fichier nommé comme screenshot_2014-01-07-10: 31.png
J'espère que mon script pourrait être utile. Je l'utilise sur mon onglet galaxie et cela fonctionne parfaitement, mais il vous est possible de changer la résolution par défaut. Il nécessite cependant le shell "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 ${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.$$
Je pense que rgb32torgb888.py devrait être
sys.stdout.write(colour[0])
sys.stdout.write(colour[1])
sys.stdout.write(colour[2])