如何将图片转换为二进制数据包并从中恢复图片(Python示例)

引言

在很多应用中,处理图像时可能需要将图片转换成二进制数据(比如存储、传输等),然后再从这些二进制数据中恢复图片。本文将演示如何使用 Python 完成这一任务,具体实现将包括两部分:将图片转换为二进制数据包以及从二进制数据恢复图片。比如笔者在最近工作中就遇到了相关问题。俗话说好记性不如烂笔头。于是写了一个处理二进制图像数据包的方法。

实现目标

  1. 将图片读取并转换为二进制数据包。
  2. 将二进制数据包转换回图片并保存。
  3. 展示如何通过简单的调试打印前64个字节和后64个字节,检查数据包是否完整。

环境准备

首先,我们需要安装 Python 和 Pillow 库。如果尚未安装 Pillow,可以使用以下命令进行安装:

pip install pillow

步骤 1:读取转换为二进制数据包(这里为了方便展示直接解析自带PNG文件位二进制包)

我们可以通过 Pillow 库读取图片,然后将其保存到内存中的 BytesIO 对象中,最终提取出二进制数据。具体代码如下:

from PIL import Image
import io

def image_to_binary(image_path):
    with Image.open(image_path) as img:
        img_byte_arr = io.BytesIO()
        img.save(img_byte_arr, format='PNG')
        img_binary = img_byte_arr.getvalue()
    return img_binary

步骤 2:将二进制数据恢复为图片

将二进制数据包恢复为图片时,我们首先通过 BytesIO 将其加载到内存中,并使用 Pillow 打开图片。最后将其保存为文件。代码如下:

def binary_to_image(binary_data, output_path):
    try:
        img_byte_arr = io.BytesIO(binary_data)
        img = Image.open(img_byte_arr)
        img.verify()  # 验证图像完整性
        img = Image.open(img_byte_arr)  # 重新打开图像
        img.save(output_path)
        return img
    except Exception as e:
        print(f"恢复图片时出错: {e}")
        return None

步骤 3:打印前64个字节和后64个字节

为了调试和确认数据包是否正确,我们可以打印二进制数据的前64个字节和后64个字节。代码如下:

# 打印前64个字节和后64个字节
print(f"二进制数据包(前64个字节):{binary_data[:64]}")
print(f"二进制数据包(后64个字节):{binary_data[-64:]}")

完整代码示例

以下是完整的代码示例,包含了上述所有步骤:

from PIL import Image
import io

def image_to_binary(image_path):
    with Image.open(image_path) as img:
        img_byte_arr = io.BytesIO()
        img.save(img_byte_arr, format='PNG')
        img_binary = img_byte_arr.getvalue()
    return img_binary

def binary_to_image(binary_data, output_path):
    try:
        img_byte_arr = io.BytesIO(binary_data)
        img = Image.open(img_byte_arr)
        img.verify()  # 验证图像完整性
        img = Image.open(img_byte_arr)  # 重新打开图像
        img.save(output_path)
        return img
    except Exception as e:
        print(f"恢复图片时出错: {e}")
        return None

# 示例用法
image_path = "input_image.png"  # 替换为你的输入图片文件路径
output_path = "output_image.png"  # 替换为你想要保存输出图片的路径

# 将图片转换为二进制包
binary_data = image_to_binary(image_path)

# 打印二进制数据包的前64个字节和后64个字节
print(f"二进制数据包(前64个字节):{binary_data[:64]}")
print(f"二进制数据包(后64个字节):{binary_data[-64:]}")

# 将二进制包转换回图片
img = binary_to_image(binary_data, output_path)

# 检查是否成功恢复图片
if img:
    img.show()
    print(f"图片已从二进制数据恢复并保存到: {output_path}")
else:
    print("图片恢复失败")

在解析 PNG 文件的二进制包时,我们可以通过查看 PNG 文件的结构,理解文件的帧头(Header)和帧尾(Trailer)部分。PNG 是一种常见的图像格式,它具有明确的文件结构,包含帧头、数据块、以及帧尾。

  1. 文件头(Header)
    PNG 文件的开头是一个 8 字节的文件签名(89 50 4E 47 0D 0A 1A 0A),表示这是一个 PNG 文件。

    \x89PNG\r\n\x1a\n
    

    IHDR

    \x00\x00\x00\rIHDR
    

    IHDR 数据:(示例)

    \x00\x00\x0f\x00\x00\x00\t`\x08\x02\x00\x00\x00\xba}U
    
    

    这是 IHDR 数据块的实际数据。我们可以进一步解释它

  • 宽度(4字节)\x00\x00\x0f\x00(3840)

  • 高度(4字节)\x00\x00\x00\t(9)

  • 位深度(1字节)\x60(96)

  • 颜色类型(1字节)\x08(表示灰度图像)

  • 压缩方法(1字节)\x02(DEFLATE 压缩)

  • 滤波方法(1字节)\x00(过滤方法 0)

  • 隔行扫描方法(1字节)\x00(没有隔行扫描)

  • IHDR CRC 校验和

    \xba}U
    

    1. 文件尾(Trailer)

      PNG 文件的尾部是一个 IEND 数据块,用于标识 PNG 文件的结束。

      \x00\x00\x00\x00IEND\xaeB`\x82
      

      这部分数据是 PNG 文件的结尾标志 IEND 数据块。IEND 表示文件的结束。IEND 数据块的长度是 0,后面跟着 CRC 校验和。

    总结 PNG 文件的结构

  • 文件头:包含 PNG 文件的签名,固定为 \x89PNG\r\n\x1a\n
  • IHDR:包含图像的基本信息,如宽度、高度、位深度、颜色类型等。
  • IDAT:包含压缩的图像数据。
  • IEND:标识 PNG 文件的结束。
  • 扩展:提取更多的文件信息

    1. 宽度和高度:通过解析 IHDR 块的数据,可以提取图像的宽度和高度。
    2. 颜色类型:可以从 IHDR 数据中得知图像的颜色类型(例如灰度、RGB 等)。
    3. 图像数据IDAT 数据块包含压缩的图像数据,通常需要解压并解析该数据。

    作者:小小菜鸟1125

    物联沃分享整理
    物联沃-IOTWORD物联网 » 如何将图片转换为二进制数据包并从中恢复图片(Python示例)

    发表回复