import zlib # 数据解压和压缩的库
import binascii # 进制转换函数的库
# python 标准库处理png图片 简单案例
"""
png图片包括以下的数据块,都是比较重要的一些数据块
# 文件头数据块 IHDR
# 调色板数据块 PLTE
# 图像数据块 IDAT
# 图像结束数据 IEND
"""
# 采用字节流读取,然后转码成十六进制便于处理
def photo_HEX(address):
with open(address, 'rb') as f:
data = f.read().hex()
print("图片十六进制数据为:", data)
return data
# 识别png的IHDR文件头数据块,获取对应信息
def photo_IHDR(data, step):
# 查看是否为png
if data[0:16] == "89504e470d0a1a0a":
print("是png图片")
step += 16
else:
print("错误不是png图片")
# 文件头数据块 IHDR的内容字符长度,转换十进制输出字符长度
number = int(data[step:step + 8], 16)
print("IHDR的内容字符长度为:", number)
# step步数更新
step += 8
# 识别文件头数据块 IHDR
if data[step:step + 8] == "49484452":
print("IHDR 识别成功")
else:
print("IHDR 识别失败")
# step步数更新
step += 8
# 读取图片width信息
width = int(data[step:step + 8], 16)
print("图像宽度为:", width)
# step步数更新
step += 8
# 读取图片height信息
height = int(data[step:step + 8], 16)
print("图像高度为:", height)
# step步数更新
step += 8
"""
图像深度:
索引彩色图像:1,2,4或8
灰度图像:1,2,4,8或16
真彩色图像:8或16
"""
# 读取图片深度信息
bit_depth = int(data[step:step + 2], 16)
print("图像深度为:", bit_depth)
# step步数更新
step += 2
"""
颜色类型:
0:灰度图像, 1,2,4,8或16
2:真彩色图像,8或16
3:索引彩色图像,1,2,4或8
4:带α通道数据的灰度图像,8或16
6:带α通道数据的真彩色图像,8或16
"""
# 读取图片颜色类型信息
color_type = int(data[step:step + 2], 16)
print("图片颜色类型为:", color_type)
# step步数更新
step += 2
# 读取图片压缩方法信息
comdivssion_method = int(data[step:step + 2], 16)
print("图片压缩方法为:", comdivssion_method)
# step步数更新
step += 2
# 读取图片滤波器方法信息
filter_method = int(data[step:step + 2], 16)
print("图片滤波器方法为:", filter_method)
# step步数更新
step += 2
"""
扫描类型:
0:非隔行扫描
1:隔行扫描方法
"""
# 读取图片扫描类型信息
scan_type = int(data[step:step + 2], 16)
print("图片扫描类型为:", scan_type)
# step步数更新
step += 2
return step, width, height
# 图像数据块 IDAT 通过step,width,height处理数据
def photo_IDAT(data, step, width, height):
# 找数据块位置,设置起始位置
step = data.find('49444154', step)
print(step)
# 查看数据块的长度
number = int(data[step - 8:step], 16)
print("数据块长度为:", number)
# step步数更新
step += 8
# 提取数据块数据
extract_data = data[step:step + number * 2]
# 16进制字符串转换为二进制数据
extract_data = binascii.unhexlify(extract_data)
# zlib库解码二进制
photo_data = zlib.decompress(extract_data)
# 转换为list
list_data = list(photo_data)
# 打印长度会发现为5*5的图片彩色情况下应该为75,但打印的是80,这是设计的时候的0换行,去除就行了
print(len(list_data))
# 获取对应的宽度和长度,对数据做处理
width = width
height = height
# 每一部分对应0 去除法:
# 0,3*5*1,3*5*2,3*5*3,3*5*4
for de in range(height):
del list_data[3 * width * de]
# 设置list作为处理图片数据
list_all = []
list_line = []
# 彩色要除以3,3个一组
for one in range(int(len(list_data) / 3)):
list_line.append(list_data[one * 3:(one * 3 + 3)])
# 换行
if len(list_line) % width == 0:
list_all.append(list_line)
list_line = []
# 现在和其他库处理的多维数组是差不多的
print(list_all)
# 更新这一个数据块后的步数
step += number * 2
print("CRC循环冗余检测:", data[step:step + 8])
step += 8
return step, list_all
"""
5×5的图片数据 字节流为
b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x05\x00\x00\x00\x05\x08\x02\x00\x00\x00\x02\r\xb1\xb2\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\x04gAMA\x00\x00\xb1\x8f\x0b\xfca\x05\x00\x00\x00\tpHYs\x00\x00\x0e\xc3\x00\x00\x0e\xc3\x01\xc7o\xa8d\x00\x00\x00\x1dIDAT\x18Wc\xc0\x00\x8b^\x00\xd1[\x19\x95\x997_m}&K\x12\x7f\xe6\xcdW\x00\x1aC!\xf9P\xad\ry\x00\x00\x00\x00IEND\xaeB`\x82'
"""
if __name__ == '__main__':
print("开始解码png图片")
# 初始解码步数
step = 0
# 读取图片
data = photo_HEX("photo.png")
# 识别png的IHDR文件头数据块,获取step,width,height
step, width, height = photo_IHDR(data, step)
# 图片没有调色板数据块 PLTE 直接跳过
# 图像数据块 IDAT 通过step,width,height处理数据
step, list_data = photo_IDAT(data, step, width, height)
if data[step:step + 8] == "00000000":
if data[step + 8:] == "49454e44ae426082":
print("图像结束数据 IEND结束")
import zlib # 数据解压和压缩的库
import binascii # 进制转换函数的库
# python 标准库处理png图片 简单案例
"""
png图片包括以下的数据块,都是比较重要的一些数据块
# 文件头数据块 IHDR
# 调色板数据块 PLTE
# 图像数据块 IDAT
# 图像结束数据 IEND
"""
# 采用字节流读取,然后转码成十六进制便于处理
def photo_HEX(address):
with open(address, 'rb') as f:
data = f.read().hex()
print("图片十六进制数据为:", data)
return data
# 识别png的IHDR文件头数据块,获取对应信息
def photo_IHDR(data, step):
# 查看是否为png
if data[0:16] == "89504e470d0a1a0a":
print("是png图片")
step += 16
else:
print("错误不是png图片")
# 文件头数据块 IHDR的内容字符长度,转换十进制输出字符长度
number = int(data[step:step + 8], 16)
print("IHDR的内容字符长度为:", number)
# step步数更新
step += 8
# 识别文件头数据块 IHDR
if data[step:step + 8] == "49484452":
print("IHDR 识别成功")
else:
print("IHDR 识别失败")
# step步数更新
step += 8
# 读取图片width信息
width = int(data[step:step + 8], 16)
print("图像宽度为:", width)
# step步数更新
step += 8
# 读取图片height信息
height = int(data[step:step + 8], 16)
print("图像高度为:", height)
# step步数更新
step += 8
"""
图像深度:
索引彩色图像:1,2,4或8
灰度图像:1,2,4,8或16
真彩色图像:8或16
"""
# 读取图片深度信息
bit_depth = int(data[step:step + 2], 16)
print("图像深度为:", bit_depth)
# step步数更新
step += 2
"""
颜色类型:
0:灰度图像, 1,2,4,8或16
2:真彩色图像,8或16
3:索引彩色图像,1,2,4或8
4:带α通道数据的灰度图像,8或16
6:带α通道数据的真彩色图像,8或16
"""
# 读取图片颜色类型信息
color_type = int(data[step:step + 2], 16)
print("图片颜色类型为:", color_type)
# step步数更新
step += 2
# 读取图片压缩方法信息
comdivssion_method = int(data[step:step + 2], 16)
print("图片压缩方法为:", comdivssion_method)
# step步数更新
step += 2
# 读取图片滤波器方法信息
filter_method = int(data[step:step + 2], 16)
print("图片滤波器方法为:", filter_method)
# step步数更新
step += 2
"""
扫描类型:
0:非隔行扫描
1:隔行扫描方法
"""
# 读取图片扫描类型信息
scan_type = int(data[step:step + 2], 16)
print("图片扫描类型为:", scan_type)
# step步数更新
step += 2
return step, width, height
# 图像数据块 IDAT 通过step,width,height处理数据
def photo_IDAT(data, step, width, height):
# 找数据块位置,设置起始位置
step = data.find('49444154', step)
print(step)
# 查看数据块的长度
number = int(data[step - 8:step], 16)
print("数据块长度为:", number)
# step步数更新
step += 8
# 提取数据块数据
extract_data = data[step:step + number * 2]
# 16进制字符串转换为二进制数据
extract_data = binascii.unhexlify(extract_data)
# zlib库解码二进制
photo_data = zlib.decompress(extract_data)
# 转换为list
list_data = list(photo_data)
# 打印长度会发现为5*5的图片彩色情况下应该为75,但打印的是80,这是设计的时候的0换行,去除就行了
print(len(list_data))
# 获取对应的宽度和长度,对数据做处理
width = width
height = height
# 每一部分对应0 去除法:
# 0,3*5*1,3*5*2,3*5*3,3*5*4
for de in range(height):
del list_data[3 * width * de]
# 设置list作为处理图片数据
list_all = []
list_line = []
# 彩色要除以3,3个一组
for one in range(int(len(list_data) / 3)):
list_line.append(list_data[one * 3:(one * 3 + 3)])
# 换行
if len(list_line) % width == 0:
list_all.append(list_line)
list_line = []
# 现在和其他库处理的多维数组是差不多的
print(list_all)
# 更新这一个数据块后的步数
step += number * 2
print("CRC循环冗余检测:", data[step:step + 8])
step += 8
return step, list_all
"""
5×5的图片数据 字节流为
b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x05\x00\x00\x00\x05\x08\x02\x00\x00\x00\x02\r\xb1\xb2\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\x04gAMA\x00\x00\xb1\x8f\x0b\xfca\x05\x00\x00\x00\tpHYs\x00\x00\x0e\xc3\x00\x00\x0e\xc3\x01\xc7o\xa8d\x00\x00\x00\x1dIDAT\x18Wc\xc0\x00\x8b^\x00\xd1[\x19\x95\x997_m}&K\x12\x7f\xe6\xcdW\x00\x1aC!\xf9P\xad\ry\x00\x00\x00\x00IEND\xaeB`\x82'
"""
if __name__ == '__main__':
print("开始解码png图片")
# 初始解码步数
step = 0
# 读取图片
data = photo_HEX("photo.png")
# 识别png的IHDR文件头数据块,获取step,width,height
step, width, height = photo_IHDR(data, step)
# 图片没有调色板数据块 PLTE 直接跳过
# 图像数据块 IDAT 通过step,width,height处理数据
step, list_data = photo_IDAT(data, step, width, height)
if data[step:step + 8] == "00000000":
if data[step + 8:] == "49454e44ae426082":
print("图像结束数据 IEND结束")