Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@andelf
Created January 16, 2021 05:32
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save andelf/4d2f7d023c92becd1ba2999d82368ab4 to your computer and use it in GitHub Desktop.
Save andelf/4d2f7d023c92becd1ba2999d82368ab4 to your computer and use it in GitHub Desktop.
CJK Font for Rust embedded-graphics
from PIL import Image, ImageDraw, ImageFont
import PIL.features
# ! brew install libraqm
print('libraqm:', PIL.features.check('raqm'))
size = (320, 16)
"""
FORMAT = "RGB"
BG = (255, 255, 255)
FG = (0, 0, 0)
"""
FORMAT = '1'
BG = 0
FG = 1
YOFF = 0 # or -1
CHARS = "气温湿度照压卧槽艹牛逼数据设备"
im = Image.new(FORMAT, size, BG)
# font = ImageFont.truetype("sarasa-mono-sc-nerd-light.ttf", size=16, index=0)
# font = ImageFont.truetype("sarasa-mono-sc-nerd-regular.ttf", size=16, index=0)
font = ImageFont.truetype("Unibit.ttf", size=16, index=0)
# font = ImageFont.truetype("zpix.ttf", size=12, index=0)
draw = ImageDraw.Draw(im)
# code snippet to show the rendering resuble
draw.text((0, YOFF), CHARS, font=font, fill=FG, language='zh-CN')
im.save('font.png')
im.show()
draw.rectangle([(0, 0), size], fill=BG)
# NOTE: char 127 is replaced with '°'
# all control ascii chars can be used for half width symbols.
ASCII = '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~°'
charmap = []
for i, c in enumerate(ASCII):
if c.isprintable():
draw.text((0, YOFF), c, font=font, fill=FG)
else:
draw.text((0, YOFF), " ", font=font, fill=FG)
for y in range(16):
v = 0
for x in range(0, 8):
b = im.getpixel((x, y))
v = (v << 1) + b
charmap.append(v)
draw.rectangle([(0, 0), size], fill=BG)
for i, c in enumerate(CHARS):
draw.text((0, YOFF), c, font=font, fill=FG)
for y in range(16):
v = 0
for x in range(0, 16):
b = im.getpixel((x, y))
v = (v << 1) + b
charmap.append(v >> 8)
charmap.append(v & 0xFF)
draw.rectangle([(0, 0), size], fill=BG)
with open('font.raw', 'wb') as fp:
fp.write(bytes(charmap))
use embedded_graphics::fonts::Font;
use embedded_graphics::geometry::Size;
#[derive(Clone, Copy)]
pub struct FontCn;
impl Font for FontCn {
const FONT_IMAGE: &'static [u8] = include_bytes!("../font.raw");
// add 1pixel row spacing
const CHARACTER_SIZE: Size = Size::new(16, 16 + 1);
const VARIABLE_WIDTH: bool = true;
const FONT_IMAGE_WIDTH: u32 = 16;
const CHARACTER_SPACING: u32 = 1;
fn char_offset(_c: char) -> u32 {
unreachable!()
}
fn char_width(c: char) -> u32 {
match c {
_ if (c as u16) < 128 => 8,
'°' => 8,
_ => 16,
}
}
fn character_pixel(c: char, x: u32, y: u32) -> bool {
if x >= 16 || y >= 16 {
return false;
}
if c.is_ascii_graphic() {
let map = &Self::FONT_IMAGE[16 * (c as usize)..16 + (c as usize) * 16];
return (map[y as usize] & (1 << (7 - x))) != 0;
}
// chars that are remaped to 0-127 chontrol chars
if c == '°' {
let map = &Self::FONT_IMAGE[16 * 127..16 + 16 * 128];
return (map[y as usize] & (1 << (7 - x))) != 0;
}
const start: usize = 128 * 16;
const step: usize = 2 * 16;
if let Some(index) = "气温湿度照压卧槽艹牛逼数据设备"
.chars()
.position(|ch| ch == c)
{
let bitmap = &Self::FONT_IMAGE[start + index * step..start + (index + 1) * step];
if x >= 8 {
(bitmap[y as usize * 2 + 1] & (1 << (15 - x))) != 0
} else {
(bitmap[y as usize * 2] & (1 << (7 - x))) != 0
}
} else {
false
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment