|
| 1 | +# 您可以通过使用 python3 的 pillow 库将图片转换为 pbm 格式,比如: |
| 2 | +# convert_type = "1" # 1 为黑白图像,RGBA 为彩色图像 |
| 3 | +# from PIL import Image |
| 4 | +# with Image.open("文件名.png", "r") as img: |
| 5 | +# img2 = img.convert(convert_type) |
| 6 | +# img2.save("文件名.pbm") |
| 7 | + |
| 8 | +import os |
| 9 | + |
| 10 | +try: |
| 11 | + from PIL import Image |
| 12 | +except ImportError: |
| 13 | + os.system('pip3 install pillow -i https://mirrors.aliyun.com/pypi/simple/') |
| 14 | + from PIL import Image |
| 15 | + |
| 16 | + |
| 17 | +def _get_output_path(file: str, path: str, extension: str = None): |
| 18 | + """ |
| 19 | + 根据文件路径和输出路径,获取输出文件的路径 |
| 20 | +
|
| 21 | + Args: |
| 22 | + file: 文件路径 |
| 23 | + path: 输出路径 |
| 24 | + extension: 文件扩展名,为 None 时保持扩展名不变 |
| 25 | +
|
| 26 | + Returns: |
| 27 | + 文件名 |
| 28 | + """ |
| 29 | + file_name = file.split("/")[-1] # 除去原路径,保留文件名 |
| 30 | + file_name = file_name.split(".") |
| 31 | + if extension: |
| 32 | + if len(file_name) > 1: # 若需要更改扩展名且已存在文件扩展名,则去除 |
| 33 | + del file_name[-1] |
| 34 | + file_name[-1] += ".{}".format(extension.lstrip(".")) # 增加扩展名 |
| 35 | + |
| 36 | + file_name = ".".join(file_name) # 考虑文件名含多个 "." 的情况 |
| 37 | + return "{}/{}".format(path.rstrip("/"), file_name) # 将文件名与输出路径合并 |
| 38 | + |
| 39 | + |
| 40 | +def _color(r: int, g: int, b: int) -> int: |
| 41 | + """ |
| 42 | + 将 (0-255) 值的:红绿蓝 转换为 16-bit 的 565 编码 |
| 43 | +
|
| 44 | + Args: |
| 45 | + r: 红 |
| 46 | + g: 绿 |
| 47 | + b: 蓝 |
| 48 | +
|
| 49 | + Returns: |
| 50 | + color (int): 0-65535 |
| 51 | + """ |
| 52 | + return (r & 0xf8) << 8 | (g & 0xfc) << 3 | b >> 3 |
| 53 | + |
| 54 | + |
| 55 | +def _calculate_palette(color, bg_color) -> tuple: |
| 56 | + """ |
| 57 | + 通过 主体颜色 和 背景颜色 计算调色板 |
| 58 | +
|
| 59 | + Args: |
| 60 | + color: 主体颜色 |
| 61 | + bg_color: 背景颜色 |
| 62 | + """ |
| 63 | + return [bg_color & 0xFF, (bg_color & 0xFF00) >> 8], [color & 0xFF, (color & 0xFF00) >> 8] |
| 64 | + |
| 65 | + |
| 66 | +def _flatten_byte_data(byte_data, palette) -> bytearray: |
| 67 | + """ |
| 68 | + 将 二进制 黑白图像渲染为 RGB565 彩色图像 |
| 69 | + Args: |
| 70 | + byte_data: 图像数据 |
| 71 | + palette: 调色板 |
| 72 | +
|
| 73 | + Returns: |
| 74 | +
|
| 75 | + """ |
| 76 | + _temp = [] |
| 77 | + r = range(7, -1, -1) |
| 78 | + for _byte in byte_data: |
| 79 | + for _b in r: |
| 80 | + _temp.extend(palette[(_byte >> _b) & 0x01]) |
| 81 | + return bytearray(_temp) |
| 82 | + |
| 83 | + |
| 84 | +def _convert_image(file, output_path=".", convert_type="1", size: tuple = None, image_type: str = "pbm"): |
| 85 | + """ |
| 86 | + 将图片转换为 指定 格式 |
| 87 | +
|
| 88 | + Args: |
| 89 | + file: 原图片路径 |
| 90 | + output_path: 输出路径(文件夹) |
| 91 | + convert_type: 图像类型("1" 为黑白图像,"RGBA" 为彩色图像) |
| 92 | + size: 图像大小 |
| 93 | + image_type: 图像类型(图像文件后缀名) |
| 94 | + """ |
| 95 | + with Image.open(file, "r") as img: |
| 96 | + img2 = img.convert(convert_type) |
| 97 | + if size: |
| 98 | + img2 = img2.resize(size, Image.LANCZOS) |
| 99 | + file_path = _get_output_path(file, output_path, image_type) |
| 100 | + path = file_path.split('/') |
| 101 | + del path[-1] |
| 102 | + path = "/".join(path) |
| 103 | + if not os.path.exists(path): |
| 104 | + os.makedirs(path) |
| 105 | + img2.save(file_path) |
| 106 | + |
| 107 | + |
| 108 | +def image_to_pbm(file, output_path=".", convert_type="1", size: tuple = None): |
| 109 | + """ |
| 110 | + 将图片转换为 PBM 格式 |
| 111 | +
|
| 112 | + Args: |
| 113 | + file: 原图片路径 |
| 114 | + output_path: 输出路径(文件夹) |
| 115 | + convert_type: 图像类型("1" 为黑白图像,"RGBA" 为彩色图像) |
| 116 | + size: 图像大小 |
| 117 | + """ |
| 118 | + _convert_image(file, output_path, convert_type, size, "pbm") |
| 119 | + |
| 120 | + |
| 121 | +def image_to_bmp(file, output_path=".", convert_type="1", size: tuple = None): |
| 122 | + """ |
| 123 | + 将图片转换为 BMP 格式 |
| 124 | +
|
| 125 | + Args: |
| 126 | + file: 原图片路径 |
| 127 | + output_path: 输出路径(文件夹) |
| 128 | + convert_type: 图像类型("1" 为黑白图像,"RGBA" 为彩色图像) |
| 129 | + size: 图像大小 |
| 130 | + """ |
| 131 | + _convert_image(file, output_path, convert_type, size, "bmp") |
| 132 | + |
| 133 | + |
| 134 | +def pbm_to_dat(file, output_path=".", color: int = 65535, bg_color: int = 0, reverse: bool = False): |
| 135 | + """ |
| 136 | + 将 PBM 图片转换为 micropython-easydisplay 专用的 DAT 格式 |
| 137 | +
|
| 138 | + Args: |
| 139 | + file: 原图片路径 |
| 140 | + output_path: 输出路径(文件夹) |
| 141 | + color: 图案颜色(仅黑白两色的 PBM 图片生效) |
| 142 | + bg_color: 背景颜色(仅黑白两色的 PBM 图片生效) |
| 143 | + reverse: 图像颜色反转 |
| 144 | + """ |
| 145 | + with open(file, "rb") as img: |
| 146 | + file_format = img.readline() # 读取文件格式 |
| 147 | + if file_format == b"P4\n" or file_format == b"P6\n": |
| 148 | + _width, _height = [int(value) for value in img.readline().split()] # 获取图片的宽度和高度 |
| 149 | + with open(_get_output_path(file, output_path, "dat"), "wb") as f: |
| 150 | + f.write('EasyDisplay\nV1\n{} {}\n'.format(_width, _height).encode('utf-8')) # 写入文件头 |
| 151 | + print(_width, _height) |
| 152 | + if file_format == b"P4\n": |
| 153 | + palette = _calculate_palette(color, bg_color) # 计算调色板 |
| 154 | + data = img.read(4096) |
| 155 | + while data: |
| 156 | + if reverse: |
| 157 | + data = bytes([~b & 0xFF for b in data]) |
| 158 | + f.write(_flatten_byte_data(data, palette)) |
| 159 | + data = img.read(4096) |
| 160 | + elif file_format == b"P6\n": |
| 161 | + max_pixel_value = img.readline() # 获取最大像素值 |
| 162 | + buffer = bytearray(_width * 2) |
| 163 | + for _y in range(_height): # 逐行处理图片 |
| 164 | + for _x in range(_width): # 逐像素处理 |
| 165 | + color_bytearray = img.read(3) |
| 166 | + r, g, b = color_bytearray[0], color_bytearray[1], color_bytearray[2] |
| 167 | + if reverse: |
| 168 | + r = 255 - r |
| 169 | + g = 255 - g |
| 170 | + b = 255 - b |
| 171 | + buffer[_x * 2: (_x + 1) * 2] = _color(r, g, b).to_bytes(2, 'big') # 通过索引赋值 |
| 172 | + f.write(buffer) |
| 173 | + else: |
| 174 | + try: |
| 175 | + raise TypeError("[ERROR] Unsupported File Format {} !".format(file_format.rstrip(b"\n"))) |
| 176 | + except: |
| 177 | + raise TypeError("[ERROR] Unsupported File Format!") |
| 178 | + |
| 179 | + |
| 180 | +if __name__ == "__main__": |
| 181 | + # 使用示例 |
| 182 | + image_to_pbm("(image_file_path)", "(image_output_folder)", "RGBA", size=(64, 64)) |
| 183 | + pbm_to_dat("(pbm_file_path)", "(image_output_folder)") |
| 184 | + image_to_bmp("(image_file_path)", "(image_output_folder)", "RGBA", size=(64, 64)) |
0 commit comments