My goal is to be able to type a one word command and get a screenshot from a rooted Nexus One attached by USB.
So far, I can get the framebuffer which I believe is a 32bit xRGB888 raw image by pulling it like this:
adb pull /dev/graphics/fb0 fb0
From there though, I'm having a hard time getting it converted to a png. I'm trying with ffmpeg like this:
ffmpeg -vframes 1 -vcodec rawvideo -f rawvideo -pix_fmt rgb8888 -s 480x800 -i fb0 -f image2 -vcodec png image.png
That creates a lovely purple image that has parts that vaguely resemble the screen, but it's by no means a clean screenshot.
Source: Tips4all
You can simply build this app from the Android source tree: http://android.git.kernel.org/?p=platform/sdk.git;a=tree;f=screenshot;h=d3bfa8c5d4ba1a6b4ac0d7d6f01f8df288917d4e;hb=master
ReplyDeleteIt's a command line utility that grabs a screenshot from the device.
It seems that frame buffer of N1 uses RGB32 encoding (32 bits per pixel).
ReplyDeleteHere is my script using 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
Another way derived from ADP1 method described here 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 script '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])
Using my HTC Hero (and hence adjusting from 480x800 to 320x480), this works if I use rgb565 instead of 8888:
ReplyDeleteffmpeg -vframes 1 -vcodec rawvideo -f rawvideo -pix_fmt rgb565 -s 320x480 -i fb0 -f image2 -vcodec png image.png
Actually, there is another very simple ability to grab screenshot from your android device: write simple script 1.script like this:
ReplyDelete# 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')
and call monkeyrunner 1.script.
I believe all framebuffers to date are RGB 565, not 888.
ReplyDeleteI think rgb32torgb888.py should be
ReplyDeletesys.stdout.write(colour[0])
sys.stdout.write(colour[1])
sys.stdout.write(colour[2])
I hope my script might be of any use. I use it on my galaxy tab and it works perfectly, but it is possible for you to change the default resolution. It requires the "zsh" shell, though:
ReplyDelete#!/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.$$
On the MyTouch Slide 3G, I ended up with the red and blue channels swapped in my screenshots. Here's the correct ffmpeg incantation for anyone else in that situation:
ReplyDelete(the notable part: -pix_fmt bgr32)
ffmpeg -vframes 1 -vcodec rawvideo -f rawvideo -pix_fmt bgr32 -s 320x480 -i fb0 -f image2 -vcodec png image.png
Thanks to Patola for the handy shell script! At least for my phone, no mogrification is necessary to correctly orient for portrait mode (320x480), and so the end of his script becomes:
# 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.$$
Here's another solution, handling various color depths: RGB16, RGB24, RGB32: http://www.pocketmagic.net/?p=1473
ReplyDelete