【问题标题】:Screenshot of the Nexus One from adb?来自 adb 的 Nexus One 的屏幕截图?
【发布时间】: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

这会创建一个可爱的紫色图像,其中的部分与屏幕有点相似,但这绝不是一个干净的屏幕截图。

【问题讨论】:

    标签: android graphics ffmpeg screenshot


    【解决方案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 ${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.$$
          

          【讨论】:

          • 我不是很清楚——如果你提供分辨率,它(可能)可以在任何安卓上工作。
          【解决方案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=${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
              

              【讨论】:

                【解决方案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 的文件

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 2010-11-03
                    • 1970-01-01
                    • 2022-11-11
                    • 2019-10-06
                    • 1970-01-01
                    • 2014-10-25
                    • 1970-01-01
                    • 2011-02-19
                    相关资源
                    最近更新 更多