python3 在线解析jpg图片或解析本地jpg,判断jpg是否损坏

一、JPEG图片格式详解

JPEG图片格式组成部分:SOI(文件头)+APP0(图像识别信息)+ DQT(定义量化表)+ SOF0(图像基本信息)+ DHT(定义Huffman表) + DRI(定义重新开始间隔)+ SOS(扫描行开始)+ EOI(文件尾)

二、数据结构

  1.段的一般结构如下表所示:

表1:段的一般结构
-----------------------------------------------------------------
名称    字节数 数据  说明
-----------------------------------------------------------------
段标识   1     FF    每个新段的开始标识
段类型   1           类型编码(称作“标记码”)
段长度   2           包括段内容和段长度本身,不包括段标识和段类型
段内容               ≤65533字节
-----------------------------------------------------------------
  说明:
①JPG 文件中所有关于宽度高度长度间隔这一类数据,凡是>1字节的,均采用Motorola格式,即:高位在前,低位在后。
②有些段没有长度描述也没有内容,只有段标识和段类型。文件头和文件尾均属于这种段。
③段与段之间无论有多少FF都是合法的,这些FF称为“填充字节”,必须被忽略掉。


  2.段类型有30种,但只有10种是必须被所有程序识别的,其它的类型都可以忽略。所以下面只列出这10种类型。

表2:段类型
---------------------------------------
名称  标记码  说明
---------------------------------------
SOI    D8     文件头 
EOI    D9     文件尾
SOF0   C0     帧开始(标准 JPEG)
SOF1   C1     同上
DHT    C4     定义 Huffman 表(霍夫曼表)
SOS    DA     扫描行开始
DQT    DB     定义量化表
DRI    DD     定义重新开始间隔
APP0   E0     定义交换格式和图像识别信息
COM    FE     注释
-----------------------------------------------------------
  说明:有的文章也将DNL段(标记码=DC,定义扫描行数)列为必须段。

具体请参考这两篇博文:

https://blog.csdn.net/yun_hen/article/details/78135122

https://blog.csdn.net/STN_LCD/article/details/78629029

三.环境

1.python3

2.安装图像处理库 pip install pillow 
 pillow 的api 函数请参考官网:https://pillow.readthedocs.io/en/4.2.x/reference/Image.html#PIL.Image.open

四、代码实例:

 
from os import PathLike
from PIL import Image
import urllib.request
import io
# 判断文件是否为有效(完整)的图片
# 从网络上判断图片是否损坏
def IsValidImage_remote_img(url):
    try:
        bValid = True
        '''python2写法
        request = urllib2.Request(img_url)
        img_data = urllib2.urlopen(request).read()
        img_buffer = StringIO.StringIO(img_data)
        img = Image.open(img_buffer)
        img.save('remote.jpg')#保存图片
        (width,height) = img.size
        out = img.resize((200,height * 200 / width),Image.ANTIALIAS)
        out.save('remote_small.jpg')        '''
        buf = urllib.request.urlopen(url).read()  # bytearray
        img_buffer = io.BytesIO(buf)  # 转换为字符串
        if not buf.startswith(b'\xff\xd8'):#是否以\xff\xd8开头
            bValid=False
        elif buf[6:10] in (b'JFIF', b'Exif'):  # “JFIF”的ASCII码
            if not buf.rstrip(b'\0\r\n').endswith(b'\xff\xd9'):#是否以\xff\xd9结尾
                bValid = False
        else:
            try:
                Image.open(img_buffer).verify()
            except Exception as e:
                bValid = False
                print(e)
    except Exception as e:
        print(e)

    return bValid
# 从本地判断图片是否损坏
def IsValidImage_native_img(file):
    try:
        bValid = True
        if isinstance(file, (str, PathLike)):  # 文件路径
            fileObj = open(file, 'rb')  # 以二进制形式打开
        else:
            fileObj = file  # 文件对象
        buf = fileObj.read()
        if not buf.startswith(b'\xff\xd8'):  # 是否以\xff\xd8开头
            bValid = False
        elif buf[6:10] in (b'JFIF', b'Exif'):  # “JFIF”的ASCII码
            if not buf.rstrip(b'\0\r\n').endswith(b'\xff\xd9'):  # 是否以\xff\xd9结尾
                bValid = False
        else:
            try:
                Image.open(fileObj).verify()
            except Exception as e:
                bValid = False
                print(e)
    except Exception as e:
        print(e)
    return bValid

#打印一个字节数组
def print_bytearray(buf):
    i = 0
    for ebuf in buf:
        i = i + 1
        print('0x%-2x' % ebuf, end='')
        print("  ", end='')
        if i == 16:
            print("\n")
            i = 0
    print("\n")

def main():
    flag1=IsValidImage_remote_img('http:XXX/xxx/xxxxx.jpg')
    flag2=IsValidImage_native_img(r'C:\Users\PC\Desktop\1.jpg')
    print(flag1)
    print(flag2)
if __name__ == '__main__':
    main()

猜你喜欢

转载自blog.csdn.net/zhuhuahong/article/details/82464552