Python检测JPEG、PNG是否完整

本文介绍了一个使用Python脚本检查JPEG和PNG图片文件完整性的方法。通过读取文件末尾的特定字节来判断图片是否损坏,适用于OpenCV项目中的数据集预处理阶段。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

《OpenCV系列教程》
《深度学习-如何提高数据集质量》

项目位置:OpenCV-Sample
代码位置:35-CheckJPEGPNG.py

之前检测过JPEG文件是否完整,这次把PNG也添加进来,检测方式还是比较粗略,不能覆盖的很广。

import os

path = './res/'

def is_valid_jpg(jpg_file):
    with open(jpg_file, 'rb') as f:
        f.seek(-2, 2)
        buf = f.read()
        return buf ==  b'\xff\xd9'

def is_valid_png(png_file):
    with open(png_file, 'rb') as f:
        f.seek(-2, 2)
        buf = f.read()
        return buf == b'\x60\x82'

for file in os.listdir('res'):
    pic_file = path + file
    isJpg = is_valid_jpg(pic_file)
    isPng = is_valid_png(pic_file)


    print("jpeg : %s, png %s, file %s " % (isJpg, isPng, file))
<think>我们正在处理用户关于检测JPEG图像完整性的问题。根据引用内容,我们有两种方法:一种是通过检查文件尾部的特定字节序列(针对JPEG文件),另一种是通过尝试打开图像并转换为WebP格式来检测(但这不是直接检测JPEG完整性的方法,而是转换过程中可能捕获异常)。用户特别关注JPEG图像,因此我们将重点放在第一种方法上,即检查文件结尾的标记。JPEG文件的结束标记是`0xFFD9`(即二进制序列`\xff\xd9`)。因此,我们可以通过检查文件最后两个字节是否为`\xff\xd9`来判断JPEG文件是否完整。但是,引用中提供的代码`badImgFast`函数检查了多种结尾,包括:-`b'\xff\xd9'`(JPEG)-`b'\xae\x82'`(可能是其他图像格式?)-`b'\x00\x3B'`(可能是GIF?)-`b'\x60\x82'`(可能是其他?)-`b'\x00\x00'`(可能是PNG?)并且最后还检查了是否是webp格式(通过`imghdr`模块)。这显然是一个通用的图像完整检测函数,而不仅仅针对JPEG。对于用户的需求(只检测JPEG),我们可以简化:仅检查文件最后两个字节是否为`b'\xff\xd9'`。但是,需要注意的是,有些JPEG文件可能包含多个结束标记(例如,在缩略图之后),但通常我们只需要检查整个文件的结尾是否为`\xff\xd9`即可。另外,引用中还提到了一种方法:使用`imghdr.what`来检测文件类型,但这只能检测文件类型,不能确保文件完整。因此,我们需要结合两种方法:先判断文件类型,再根据类型检查文件结尾。然而,用户只需要JPEG检测方法。我们可以这样做:1.检查文件大小是否过小(比如小于一定阈值,例如512字节),则可能不完整(可选)。2.读取文件的最后两个字节,检查是否为`b'\xff\xd9'`。但注意,有些JPEG文件可能包含应用扩展数据(比如Exif信息),但结束标记仍然是`\xff\xd9`。因此,我们可以编写一个专门检测JPEG完整性的函数。另外,引用中还提到了一种“可靠的实现”是通过尝试用PIL打开图像来检测。这种方法更通用,因为如果图像损坏,打开时会抛出异常。但是,这种方法需要实际解码整个图像,对于大文件可能会慢。而检查文件结尾的方法非常快速。因此,我们可以提供两种方法:-快速检查(通过文件结尾)-完整检查(尝试打开图像)根据用户需求,他们可能希望快速检测大量文件,因此快速检查方法可能更合适。现在,我们编写代码:方法一(快速检查):```pythondefis_jpeg_complete_fast(file_path):"""快速检查JPEG文件是否完整(通过检查结束标记)"""try:withopen(file_path,'rb')asf:#移动到文件末尾前2个字节f.seek(-2,2)last_two_bytes=f.read(2)returnlast_two_bytes==b'\xff\xd9'exceptException:#例如文件太小returnFalse```注意:如果文件小于2字节,则会出现异常,我们返回False。方法二(可靠但较慢):使用PIL(或Pillow)打开图像,如果打开过程中出现异常,则说明图像损坏。```pythonfromPILimportImagedefis_jpeg_complete_slow(file_path):"""通过尝试打开JPEG文件来检查是否完整"""try:withImage.open(file_path)asimg:img.verify()#验证文件完整性(不解码像素数据)returnTrueexceptException:returnFalse```注意:`img.verify()`方法会检查文件结构,但不会解码图像数据,因此比完全加载图像要快。不过,对于非常大的图像,仍然可能比检查文件结尾慢。另外,我们还可以结合文件大小检查(可选),比如文件大小小于某个值(如512字节)则认为不完整。现在,针对用户的问题,我们提供两种方法,并说明优缺点。此外,用户可能还会遇到一些JPEG文件有多个结束标记的情况(比如在文件中间有一个结束标记,但后面还有数据),这种情况很少见,通常我们只检查文件末尾。如果文件末尾不是`\xff\xd9`,那么肯定不完整;如果是,则基本认为完整(但并不能保证中间没有损坏,因为快速检查只检查结尾)。所以快速检查只能检测出文件被截断的情况,而无法检测中间损坏。而使用`verify`方法可以检查更多的结构错误。因此,如果用户需要更可靠的检测,建议使用方法二;如果只是快速检查文件是否被截断(比如下载过程中中断),则方法一足够。最后,我们根据用户要求生成相关问题。</think>### Python检测JPEG图像完整性的方法 检测JPEG图像完整性的核心是验证文件是否包含有效的结束标记`0xFFD9`。以下是两种实现方法: #### 方法一:快速结尾标记检测(推荐) ```python import os def is_jpeg_complete(file_path): """快速检测JPEG文件完整性(通过结尾标记)""" if os.path.getsize(file_path) < 2: # 文件过小 return False try: with open(file_path, 'rb') as f: f.seek(-2, os.SEEK_END) # 定位到文件末尾前2字节 return f.read(2) == b'\xff\xd9' # 检查结束标记 except OSError: return False ``` **原理**: JPEG标准要求文件必须以`0xFFD9`字节序列结束[^1]。该函数通过: 1. 检查文件大小(小于2字节直接判无效) 2. 读取文件最后2字节 3. 验证是否为`b'\xff\xd9'` **优点**:速度快(不加载整个文件),适合批量检测。 #### 方法二:PIL库深度验证 ```python from PIL import Image def is_jpeg_valid(file_path): """深度验证JPEG完整性(通过图像解码)""" try: with Image.open(file_path) as img: img.verify() # 验证文件结构 img.load() # 尝试加载像素数据 return True except (IOError, SyntaxError, OSError): return False ``` **原理**: 使用PIL库的`verify()`和`load()`方法: 1. `verify()`检查文件头结构 2. `load()`尝试解码像素数据 3. 任何解码错误抛出异常 **优点**:能检测中间数据损坏(如部分数据丢失)。 ### 使用建议 - **优先方法一**:快速检查大批量文件 - **怀疑损坏时用方法二**:当方法一返回`False`时二次验证 - **文件大小阈值**:可添加`if os.path.getsize(fn) < 512: return False`排除极小的无效文件 ### 示例检测 ```python # 测试用例 print(is_jpeg_complete("test.jpg")) # True/False print(is_jpeg_valid("test.jpg")) # True/False ``` ### 注意事项 1. 方法一可能漏检**中间数据损坏**(仅验证结尾) 2. 损坏的渐进式JPEG(progressive JPEG)可能通过方法一但被方法二捕获 3. 其他格式(PNG/WEBP)需不同检测逻辑(如PNG结尾为`b'IEND\xaeB`) > 两种方法可结合使用:先用快速检测筛选,再对可疑文件深度验证[^1]。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值