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
相关产品推荐
相关产品推荐

