You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ADB截取OnePlus 5屏幕截图后无法打开的技术求助

解决OnePlus 5通过ADB连续截图后部分图片无法打开的问题

我之前也踩过类似的坑!你用ADB从OnePlus 5连续截图给Google Tesseract做文字识别,前2-4张正常,后面的不管用PIL、Paint.net还是设备本身都打不开,报错OSError: cannot identify image file,大概率是文件生成/传输不完整或者重复覆盖文件导致的冲突。结合你的代码,给你几个靠谱的解决方案:

可能的原因

  • 连续截图间隔只有1.5秒,设备端的screencap命令还没生成完整的截图文件,你就执行了pull,导致拉下来的是不完整的损坏文件
  • 重复覆盖同一个screen.png,前一次的文件还没被本地程序完全释放,后一次的写入操作就开始了,造成文件损坏
  • 设备端的文件系统写入有延迟,虽然ADB命令执行完了,但实际文件还没写完

解决方案

1. 最推荐:直接获取截图字节流(绕开文件存储)

pure-python-adb其实支持直接获取截图的二进制数据,不用先存到设备再pull,从根源上避免文件IO的问题。修改你的代码如下:

from adb.client import Client as AdbClient
from PIL import Image
from io import BytesIO
import pytesseract
import os

def get_screen(device):
    try:
        # 直接从设备获取截图字节数据
        screenshot_bytes = device.screencap()
        # 用BytesIO包装成文件流给PIL打开
        screens = Image.open(BytesIO(screenshot_bytes))
    except Exception as e:
        print(f"Error opening image: {e}")
        return -1
    return screens

这个方法跳过了设备端写文件和本地pull的步骤,完全在内存中处理,不仅更可靠,速度也更快。

2. 确保截图生成完整再Pull

如果一定要用文件存储的方式,那就要保证设备端的截图文件完全生成后再执行pull。可以通过检查文件大小是否稳定来判断:

def get_screen(device):
    # 先删除旧截图,避免残留的损坏文件干扰
    device.shell("rm -f /sdcard/pgrinder/screen.png")
    # 生成新截图
    device.shell("screencap -p /sdcard/pgrinder/screen.png")
    
    # 等待文件大小稳定,确保截图生成完成
    prev_size = -1
    while True:
        # 获取文件字节大小
        size_output = device.shell("du -b /sdcard/pgrinder/screen.png").split()[0]
        current_size = int(size_output)
        # 当文件大小大于0且连续两次一致时,说明文件写完了
        if current_size > 0 and current_size == prev_size:
            break
        prev_size = current_size
    
    # 拉取文件到本地
    device.pull("/sdcard/pgrinder/screen.png", "screen.png")
    
    # 检查本地文件是否为空
    if os.path.getsize("screen.png") == 0:
        print("Empty image file pulled")
        return -1
    
    try:
        screens = Image.open('screen.png')
    except Exception as e:
        print(f"Error opening image: {e}")
        return -1
    return screens

3. 每次使用不同的文件名

不要重复覆盖同一个文件,用时间戳或者序号命名,避免文件锁定或写入冲突:

import time

def get_screen(device):
    # 生成唯一文件名
    timestamp = int(time.time() * 1000)
    remote_path = f"/sdcard/pgrinder/screen_{timestamp}.png"
    local_path = f"screen_{timestamp}.png"
    
    # 生成并拉取截图
    device.shell(f"screencap -p {remote_path}")
    device.pull(remote_path, local_path)
    
    # 可选:删除设备端的截图,节省存储空间
    device.shell(f"rm {remote_path}")
    
    try:
        screens = Image.open(local_path)
        # 可选:用完后删除本地文件,避免占用空间
        # os.remove(local_path)
    except Exception as e:
        print(f"Error opening image: {e}")
        # 删除损坏的本地文件
        if os.path.exists(local_path):
            os.remove(local_path)
        return -1
    return screens

为什么这些方法有效?

  • 方法1直接在内存中处理截图数据,完全绕开了文件存储的各种问题,是最稳定的方案
  • 方法2通过检查文件大小确保截图完全生成,避免拉取不完整的损坏文件
  • 方法3避免了重复覆盖同一个文件,减少了文件锁定、写入冲突的可能性

内容的提问来源于stack exchange,提问作者Maxinger15

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 07:44:11