python:在socket协议的数据里提取一张图片

2022-08-20 09:55:52

一、需求描述与图片提取

1、在多个分包数据中,提取一张图片有多难?

(1)、将分包组成一个完整包

(2)、基于完整包来截取图片数据)

(3)、如果是RGB格式的图片,确认传输的数据是否是3通道,不是的话得增加其他通道的数据,否则图片会模糊

(4)、保存RGB图片时,需要知道原始图片的尺寸

(5)、有时候图片的数据会超过图片的尺寸,导致无法通过数组的方式写入,因此需要截取图片数据为该尺寸的数据

(6)、截取数据时,截取后半部分的数据才不会使得图片错位

(7)、实践过程中除了遇到以上问题,还有保存图片时,采用了各种方式,如直接写入文件(open函数)、通过Image.frombuffer直接写入(PIL)等等,最终发现Image.fromarray的RGB写入方式才好使,而且需要通过numpy来处理数据。

2、图片数据:

数据太多,无法上传

3、源代码:

import io
import re
import binascii
import socket
from PyQt5.QtGui import QImage
from common.base_socket import BaseSocket
from common.cases_data import test1_data
from PIL import Image
import numpy as np

class SaveImageFromResponse(object):

    with open("./666.txt", "r") as f:
        res_data = f.read().replace("\n", "")  # 去掉所有回车符号

    # 返回一张图片的数据列表
    def res_place_list(self, res_data = res_data):
        # res_data为假设的响应数据
        # 一张图片的数据2:存在其他请求
        all_req_list = [m.start() for m in re.finditer("aa55abcd000000", res_data)]
        return all_req_list

    # 返回所有完整的分包列表
    def res_pack_list(self, res_data = res_data):
        all_req_list = self.res_place_list()
        pack_list = []
        for index, req in enumerate(all_req_list):
            # 获取包的长度
            len_str = res_data[req + 14:req + 18]
            len_act = len_str[2:4] + len_str[0:2]
            len_num = int(len_act, 16)  # 包的长度
            pack_list.append(res_data[req:req + len_num * 2 + 26 + 4])
        return pack_list

    # 返回一个完整包
    def one_full_pack(self, head=0, tail=None):
        pack_list = self.res_pack_list()
        # 掐头去尾组装一个完整的数据包
        one_pack = ""
        one_pack_list = pack_list[head:tail]
        for index, pack in enumerate(one_pack_list):
            one_pack += pack[26:-4]
        # return one_pack.replace("\n", "")  # 已经在原始数据中处理
        return one_pack

    # 获取图片数据
    def one_image_pack(self, json_data):
        one_pack = self.one_full_pack()  # 完整包的区域是列表的4,-4位置
        return one_pack.replace(json_data, "")

    # 获取json数据
    def one_json_pack(self):
        one_pack = self.one_full_pack()
        return bytes().fromhex(one_pack).decode(errors="ignore")

    # 生成图片
    def save_image(self, json_data):
        image_data = self.one_image_pack(json_data)
        if "\n" in image_data:
            print("注意,image_data中存在回车键!")
        # 将单通道数据复制成3通道
        image_data_list = list(image_data)
        image_data = ""
        for i,value in enumerate(image_data_list):
            if (i+1)%2 == 0:
                image_data += (image_data_list[i-1]+value)*3

        # # 方式1:得到一张模糊的图片
        # new666 = Image.frombuffer("RGB", (1280,800), image_data.encode(), 'raw', "RGB", 0, 1)
        # new666.save("new666.png", "PNG")

        # # 方式2:得到一张模糊的图片
        # new666 = Image.frombuffer("L", (1280, 800), image_data.encode(), 'raw', "L", 0, 1)
        # print(new666.getchannel("L"))
        # new666=Image.merge("RGB", (new666.getchannel("L"), new666.getchannel("L"), new666.getchannel("L")))
        # new666.save("new666.png", "PNG")

        # # 方式3:此路不通
        # byte_stream = io.BytesIO(bytearray.fromhex(image_data))  # 请求数据转化字节流
        # roiImg = Image.open(byte_stream)  # Image打开二进制流Byte字节流数据
        # imgByteArr = io.BytesIO()  # 创建一个空的Bytes对象
        # roiImg.save(imgByteArr, format='PNG')  # PNG就是图片格式
        # imgByteArr = imgByteArr.getvalue()  # 保存的二进制流
        # with open("./new666.png", "ab") as f:
        #     f.write(imgByteArr)

        # # 方式4:此路不通
        # # new666 = QImage.fromData(image_data.encode())
        # new666 = QImage.fromData(bytearray.fromhex(image_data))
        # print(new666.size().width())
        # print(new666.size().height())
        # new666.save("./new666.png", "PNG", 100)

        # # 方式5:此路不通
        # arr = np.frombuffer(bytes().fromhex(image_data), dtype=np.uint8)
        # new666 = Image.fromarray(arr.reshape((1280,800, 3),order='A'))
        # new666.save("new666.png", "PNG")

        # # 方式6:得到一张模糊的图片
        # new666 = Image.frombuffer("RGB", (1280, 800), image_data.encode(), 'raw', "RGB", 0, 1)
        # new666.convert("RGB")
        # new666.save("new666.png", "PNG")
        # print(new666.format, new666.size, new666.mode)

        # # 方式7:随即生成一张图片
        # images = np.random.randint(0, 256, size=[800, 1280, 3], dtype=np.uint8) # size=[h,w,channel]
        # print(images)
        # new666 = Image.fromarray(images)
        # new666.save("new666.png", "PNG")
        # print(new666.format, new666.size, new666.mode)  # None (1280, 800) RGB

        # 方式8:
        # print(np.random.randint(1, 2, size=[800, 1280, 3], dtype=np.uint8))
        arr = np.frombuffer(bytes().fromhex(image_data), dtype=np.uint8)
        print("len(arr)", len(arr)-3072000)
        arr_data = arr[len(arr)-3072000:]  # 截取前面部分会导致图片错位
        new666 = Image.fromarray(arr_data.reshape((800, 1280, 3),order='A'))
        new666.save("new666.png", "PNG")

    # 图片转16进制字符串
    def image_to_str16(self, image):
        with open(image, 'rb') as f:
            content = f.read()
        return binascii.hexlify(content).decode()

    # 16进制字符串转图片
    def str16_to_image(self, str_16:str):
        with open("./666_or_copy.png","ab") as f:
            # pic = binascii.a2b_hex(str_16.encode())  # 方法1
            pic = bytearray.fromhex(str_16)  # 方法2
            f.write(pic)


if __name__ == '__main__':
    print(SaveImageFromResponse().res_place_list())
    # print(SaveImageFromResponse().res_pack_list()[0:5])
    # print(SaveImageFromResponse().one_full_pack()[0:5200])
    json_data = '''aa55abcd0000001405140300007b22416c676f54696d65223a35342c22486173496d616765223a22596573222c22486173526573756c74223a22596573222c22496d6167654e616d65223a223230323130333235303834333536323933222c224e47526573756c74223a22222c22526573756c74223a5b7b22416e676c65223a2d302e363832333637353033363433303335392c22436f6465223a22444d313233343536373831323334353637383930222c22486569676874223a3235392e333532393936383236313731392c224c656674546f7058223a3435342e35383335353731323839303632352c224c656674546f7059223a3237392e33383033373130393337352c2253756363657373223a224f4b222c225769647468223a3235372e383639393634353939363039347d5d2c2253756363657373223a224f4b222c225461736b54696d65223a3230352c225479706573223a367d'''
    print(SaveImageFromResponse().one_image_pack(json_data)[-1000:-1])
    if "262925222526242723252427252424252429262722262426282728262625262825272" in SaveImageFromResponse().one_image_pack(json_data):
        print("很好!")
    SaveImageFromResponse().save_image(json_data)
    # str_16 = SaveImageFromResponse().image_to_str16("./666_or.png")
    # print(str_16[0:1000])
    # if json_data in str_16:
    #     print("图片数据有误!")

    # 图片转16进制再转图片
    str_16=SaveImageFromResponse().image_to_str16("./666_or.png")
    # print(str_16)
    SaveImageFromResponse().str16_to_image(str_16)
    pass
  • 作者:Lion King
  • 原文链接:https://blog.csdn.net/weixin_43431593/article/details/122865950
    更新时间:2022-08-20 09:55:52