分享有一款比较好用的取模软件PCtoLCD2002:https://home.chengpei.top:8443/root/%E8%BD%AF%E4%BB%B6%E5%88%86%E4%BA%AB/PCtoLCD2002_exe-master.zip
可以给中文字符或者位图取模,但是好像没法给GIF动图取模,而且我用的macos系统,这个windows下的软件我用的比较少,所以介绍一下一种其他的取模方案
中文取模
这里可以使用Python基于系统的字库创建图片取模,代码如下:
from PIL import Image, ImageFont, ImageDraw
FONT_FILE="/System/Library/Fonts/STHeiti Medium.ttc"
# FONT_FILE="/Users/chengpei/Downloads/simsun.ttc"
FONT_SIZE = 16
TEXT = "内心懒得跟你争开就好呵哒打工人键盘启动摸鱼中建议别正在营业理"
def chinese_to_matrix(ch):
# 创建16x16黑白图片
img = Image.new(
"1",
(16, 16),
0
)
draw = ImageDraw.Draw(img)
font = ImageFont.truetype(
FONT_FILE,
FONT_SIZE
)
# 绘制文字
draw.text(
(0, 0),
ch,
font=font,
fill=1
)
data = []
for y in range(16):
byte = 0
for x in range(16):
if img.getpixel((x, y)):
byte |= (1 << (7 - x % 8))
if x % 8 == 7:
data.append(byte)
byte = 0
return data
print("生成C数组:")
print(
"const unsigned char chinese_font[][32]={"
)
for ch in TEXT:
data = chinese_to_matrix(ch)
print("//", ch)
print("{")
for i,b in enumerate(data):
print(
"0x%02X" % b,
end=","
)
if (i+1)%16==0:
print()
print("},")
print("};")
想要不同的字体也可以去网上找不同的字体文件
图片取模
from PIL import Image
IMAGE_FILES = [
"/Users/chengpei/Desktop/1.png",
"/Users/chengpei/Desktop/2.png",
"/Users/chengpei/Desktop/3.png",
"/Users/chengpei/Desktop/4.png",
"/Users/chengpei/Desktop/5.png",
"/Users/chengpei/Desktop/6.png",
"/Users/chengpei/Desktop/7.png",
"/Users/chengpei/Desktop/8.png",
]
OUTPUT_FILE = "/Users/chengpei/Desktop/images.h"
IMAGE_WIDTH = 64
IMAGE_HEIGHT = 64
def convert_image(img):
"""
PNG -> 64x64 单色位图
输出格式:
[64][8]
每行 64 像素 = 8 字节
bit7 = 最左边像素
bit0 = 最右边像素
"""
framebuffer = [
[0x00 for _ in range(8)]
for _ in range(64)
]
for y in range(64):
for x in range(64):
pixel = img.getpixel((x, y))
if pixel >= 128:
byte_index = x // 8
bit_index = 7 - (x % 8)
framebuffer[y][byte_index] |= (
1 << bit_index
)
return framebuffer
with open(OUTPUT_FILE, "w") as f:
f.write("#pragma once\n")
f.write("#include <stdint.h>\n\n")
f.write(
"#define IMAGE_COUNT 8\n"
"#define IMAGE_WIDTH 64\n"
"#define IMAGE_HEIGHT 64\n"
"#define IMAGE_BYTES_PER_ROW 8\n\n"
)
f.write(
"/*\n"
" * 8张64x64单色图片\n"
" * 每张图片:64x8 = 512字节\n"
" * 格式:[图片][Y][字节]\n"
" * bit7 = 左侧像素\n"
" * bit0 = 右侧像素\n"
" */\n"
)
f.write(
"\n"
"static const uint8_t "
"images[IMAGE_COUNT][64][8] = {\n"
)
for index, filename in enumerate(IMAGE_FILES):
print(f"处理: {filename}")
img = Image.open(filename)
print(f" 原始尺寸: {img.size}")
# 转灰度
img = img.convert("L")
# 缩放到 64x64
img = img.resize(
(IMAGE_WIDTH, IMAGE_HEIGHT),
Image.Resampling.LANCZOS
)
bitmap = convert_image(img)
f.write(
f" /* Image {index + 1} */\n"
)
f.write(" {\n")
for row in bitmap:
values = ", ".join(
f"0x{value:02X}"
for value in row
)
f.write(
f" {{{values}}},\n"
)
f.write(" },\n")
f.write("};\n")
print()
print("生成完成:")
print(OUTPUT_FILE)
print()
print("每张图片:")
print("64 x 64 = 512 bytes")
print()
print("8张图片:")
print(f"{8 * 512} bytes = {8 * 512 / 1024:.1f} KB")
我这里是有8张图片,全部转为64*64像素的数组
GIF动图取模
from PIL import Image
GIF_FILE = "/Users/chengpei/Desktop/IMG_5319.gif"
OUTPUT_FILE = "gif_frames.h"
OLED_WIDTH = 128
OLED_HEIGHT = 64
IMAGE_WIDTH = 64
IMAGE_HEIGHT = 64
# 64x64 图片靠 OLED 最右边
OFFSET_X = OLED_WIDTH - IMAGE_WIDTH
OFFSET_Y = 0
def convert_frame(img):
"""
将 64x64 图片放到 128x64 OLED 最右侧。
最终生成:
[64][16]
每一行:
前 8 字节 = 0x00
后 8 字节 = 图片数据
即:
0x00 ... 0x00 | 图片数据
<--- 64px ---><--- 64px --->
bit7 对应左边像素
bit0 对应右边像素
"""
# 128x64 全黑
framebuffer = [
[0x00 for _ in range(16)]
for _ in range(64)
]
for y in range(IMAGE_HEIGHT):
oled_y = OFFSET_Y + y
for x in range(IMAGE_WIDTH):
oled_x = OFFSET_X + x
pixel = img.getpixel((x, y))
if pixel >= 128:
byte_index = oled_x // 8
bit_index = 7 - (oled_x % 8)
framebuffer[oled_y][byte_index] |= (
1 << bit_index
)
return framebuffer
gif = Image.open(GIF_FILE)
frame_count = gif.n_frames
print(f"GIF尺寸: {gif.size}")
print(f"帧数: {frame_count}")
print(f"缩放尺寸: {IMAGE_WIDTH}x{IMAGE_HEIGHT}")
print(f"显示位置: ({OFFSET_X}, {OFFSET_Y})")
with open(OUTPUT_FILE, "w") as f:
f.write("#pragma once\n")
f.write("#include <stdint.h>\n\n")
f.write(
f"#define GIF_FRAME_COUNT {frame_count}\n"
)
f.write(
"\n"
"/*\n"
" * SSD1306 128x64 GIF frames\n"
" * 每帧 1024 字节\n"
" * [64][16]\n"
" * 前 8 字节固定为 0x00\n"
" * 图片位于最右侧 64x64 区域\n"
" */\n"
)
f.write(
"\n"
"static const uint8_t "
"gif_frames[GIF_FRAME_COUNT][64][16] = {\n"
)
delays = []
for frame_index in range(frame_count):
gif.seek(frame_index)
# 获取 GIF 当前帧的播放时间
delay = gif.info.get("duration", 100)
if delay is None:
delay = 100
delays.append(delay)
# 转灰度
frame = gif.convert("L")
# 125x125 → 64x64
frame = frame.resize(
(IMAGE_WIDTH, IMAGE_HEIGHT),
Image.Resampling.LANCZOS
)
bitmap = convert_frame(frame)
f.write(
f" /* Frame {frame_index} "
f"({delay} ms) */\n"
)
f.write(" {\n")
for row in bitmap:
values = ", ".join(
f"0x{value:02X}"
for value in row
)
f.write(
f" {{{values}}},\n"
)
f.write(" },\n")
f.write("};\n")
# 输出每帧延迟
f.write(
"\n"
"/* 每帧播放时间,单位 ms */\n"
)
f.write(
"static const uint16_t "
"gif_delays[GIF_FRAME_COUNT] = {\n"
)
for i in range(0, len(delays), 10):
values = ", ".join(
str(x) for x in delays[i:i + 10]
)
f.write(
f" {values},\n"
)
f.write("};\n")
print(f"\n生成完成: {OUTPUT_FILE}")
print(f"每帧大小: 1024 bytes")
print(f"总数据大小: {frame_count * 1024 / 1024:.1f} KB")
最后这个是把GIF动图的每一帧取模,然后代码里一帧帧的切换就实现动画效果了
以上方法就可以跨平台使用,不用专门去找对应平台的软件,也不用专门转位图再取模了,而且比较灵活
评论区