将字节数组转换为PIL图像
(data, filename=None)
| 13 | |
| 14 | @staticmethod |
| 15 | def byte_array_to_image(data, filename=None): |
| 16 | """将字节数组转换为PIL图像""" |
| 17 | try: |
| 18 | # 检查数据是否为空 |
| 19 | if data is None: |
| 20 | raise ValueError("图像数据为空") |
| 21 | |
| 22 | # 统一转换为字节数组 |
| 23 | data_bytes = None |
| 24 | if isinstance(data, io.BytesIO): |
| 25 | # 对于 BytesIO 对象,先读取所有内容 |
| 26 | try: |
| 27 | current_pos = data.tell() |
| 28 | data.seek(0) # 重置指针到开头 |
| 29 | data_bytes = data.read() |
| 30 | # 恢复原位置(如果可能) |
| 31 | try: |
| 32 | data.seek(current_pos) |
| 33 | except: |
| 34 | pass |
| 35 | except Exception as e: |
| 36 | raise ValueError(f"无法从BytesIO读取数据: {str(e)}") |
| 37 | elif isinstance(data, (bytes, bytearray)): |
| 38 | data_bytes = bytes(data) |
| 39 | else: |
| 40 | # 尝试转换为字节数组 |
| 41 | try: |
| 42 | data_bytes = bytes(data) |
| 43 | except (TypeError, ValueError) as e: |
| 44 | raise ValueError(f"不支持的图像数据类型: {type(data).__name__}, 错误: {str(e)}") |
| 45 | |
| 46 | # 验证数据不为空 |
| 47 | if data_bytes is None or len(data_bytes) == 0: |
| 48 | raise ValueError("图像数据为空") |
| 49 | |
| 50 | # 验证数据大小(至少要有文件头) |
| 51 | if len(data_bytes) < 8: |
| 52 | raise ValueError(f"图像数据太小(仅{len(data_bytes)}字节),不是有效的图像文件") |
| 53 | |
| 54 | # 验证图像文件头(检查常见格式) |
| 55 | header = data_bytes[:8] |
| 56 | is_valid_image = False |
| 57 | |
| 58 | # PNG: 89 50 4E 47 0D 0A 1A 0A |
| 59 | if header.startswith(b'\x89PNG\r\n\x1a\n'): |
| 60 | is_valid_image = True |
| 61 | # JPEG: FF D8 FF |
| 62 | elif header.startswith(b'\xff\xd8\xff'): |
| 63 | is_valid_image = True |
| 64 | # BMP: 42 4D |
| 65 | elif header.startswith(b'BM'): |
| 66 | is_valid_image = True |
| 67 | # GIF: 47 49 46 38 |
| 68 | elif header.startswith(b'GIF8'): |
| 69 | is_valid_image = True |
| 70 | # TIFF: 49 49 2A 00 或 4D 4D 00 2A |
| 71 | elif header.startswith(b'II*\x00') or header.startswith(b'MM\x00*'): |
| 72 | is_valid_image = True |
no test coverage detected