├── .gitignore ├── LICENSE ├── LICENSE.SourceHanSans ├── README.md ├── SourceHanSansSC-VF.otf ├── WorkBench.ipynb ├── demo ├── 12.png └── 16.png ├── examples └── C │ ├── font.h │ ├── hal.h │ ├── main.c │ └── run.sh ├── font12x11.4FN ├── font16x15.4FN └── requirements.txt /.gitignore: -------------------------------------------------------------------------------- 1 | log.txt 2 | a.out -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 44670 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LICENSE.SourceHanSans: -------------------------------------------------------------------------------- 1 | Copyright 2014-2021 Adobe (http://www.adobe.com/), with Reserved Font 2 | Name 'Source'. Source is a trademark of Adobe in the United States 3 | and/or other countries. 4 | 5 | This Font Software is licensed under the SIL Open Font License, 6 | Version 1.1. 7 | 8 | This license is copied below, and is also available with a FAQ at: 9 | http://scripts.sil.org/OFL 10 | 11 | ----------------------------------------------------------- 12 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 13 | ----------------------------------------------------------- 14 | 15 | PREAMBLE 16 | The goals of the Open Font License (OFL) are to stimulate worldwide 17 | development of collaborative font projects, to support the font 18 | creation efforts of academic and linguistic communities, and to 19 | provide a free and open framework in which fonts may be shared and 20 | improved in partnership with others. 21 | 22 | The OFL allows the licensed fonts to be used, studied, modified and 23 | redistributed freely as long as they are not sold by themselves. The 24 | fonts, including any derivative works, can be bundled, embedded, 25 | redistributed and/or sold with any software provided that any reserved 26 | names are not used by derivative works. The fonts and derivatives, 27 | however, cannot be released under any other type of license. The 28 | requirement for fonts to remain under this license does not apply to 29 | any document created using the fonts or their derivatives. 30 | 31 | DEFINITIONS 32 | "Font Software" refers to the set of files released by the Copyright 33 | Holder(s) under this license and clearly marked as such. This may 34 | include source files, build scripts and documentation. 35 | 36 | "Reserved Font Name" refers to any names specified as such after the 37 | copyright statement(s). 38 | 39 | "Original Version" refers to the collection of Font Software 40 | components as distributed by the Copyright Holder(s). 41 | 42 | "Modified Version" refers to any derivative made by adding to, 43 | deleting, or substituting -- in part or in whole -- any of the 44 | components of the Original Version, by changing formats or by porting 45 | the Font Software to a new environment. 46 | 47 | "Author" refers to any designer, engineer, programmer, technical 48 | writer or other person who contributed to the Font Software. 49 | 50 | PERMISSION & CONDITIONS 51 | Permission is hereby granted, free of charge, to any person obtaining 52 | a copy of the Font Software, to use, study, copy, merge, embed, 53 | modify, redistribute, and sell modified and unmodified copies of the 54 | Font Software, subject to the following conditions: 55 | 56 | 1) Neither the Font Software nor any of its individual components, in 57 | Original or Modified Versions, may be sold by itself. 58 | 59 | 2) Original or Modified Versions of the Font Software may be bundled, 60 | redistributed and/or sold with any software, provided that each copy 61 | contains the above copyright notice and this license. These can be 62 | included either as stand-alone text files, human-readable headers or 63 | in the appropriate machine-readable metadata fields within text or 64 | binary files as long as those fields can be easily viewed by the user. 65 | 66 | 3) No Modified Version of the Font Software may use the Reserved Font 67 | Name(s) unless explicit written permission is granted by the 68 | corresponding Copyright Holder. This restriction only applies to the 69 | primary font name as presented to the users. 70 | 71 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font 72 | Software shall not be used to promote, endorse or advertise any 73 | Modified Version, except to acknowledge the contribution(s) of the 74 | Copyright Holder(s) and the Author(s) or with their explicit written 75 | permission. 76 | 77 | 5) The Font Software, modified or unmodified, in part or in whole, 78 | must be distributed entirely under this license, and must not be 79 | distributed under any other license. The requirement for fonts to 80 | remain under this license does not apply to any document created using 81 | the Font Software. 82 | 83 | TERMINATION 84 | This license becomes null and void if any of the above conditions are 85 | not met. 86 | 87 | DISCLAIMER 88 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 89 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF 90 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 91 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE 92 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 93 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 94 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 95 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM 96 | OTHER DEALINGS IN THE FONT SOFTWARE. 97 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SourceHanSans-Pixel 2 | 3 | 基于思源黑体的开源CJK字符集像素字体。 4 | 5 | 提供C语言的示例程序,可在嵌入式硬件使用。 6 | 7 | 目前提供了16x15像素、12x11像素两种CJK字符集字库,全字库体积为1.4MB。 8 | 9 | ![demo](demo/16.png) 10 | ![demo](demo/12.png) 11 | 12 | # 示例程序 13 | 14 | [UTF8文本绘制](https://github.com/44670/SourceHanSans-Pixel/tree/main/examples/C) 15 | 16 | 提示:修改hal.h中的平台相关代码后可移植到不同的软硬件平台上。 17 | 18 | # 文件列表 19 | 20 | **SourceHanSansSC-VF.otf** 21 | 22 | 原始版本的Source Hans Sans字体文件。 23 | 24 | **font16x15.4FN** 25 | 26 | 16x15像素、CJK字符集的二进制字库文件,使用方法参考示例程序。 27 | 28 | **font12x11.4FN** 29 | 30 | 12x11像素、CJK字符集的二进制字库文件,使用方法参考示例程序。 31 | 32 | **WorkBench.ipynb** 33 | 34 | 实现像素字体转换、编码、预览的Notebook文件,可以在Jupyter Notebook中运行。 35 | 36 | 37 | 38 | # 许可协议 39 | 40 | "Source Han Sans" 字体及其衍生产物,遵循SIL OPEN FONT LICENSE Version 1.1协议。 41 | 42 | 本项目包含的程序代码(WorkBench.ipynb、示例程序代码等等),以MIT协议发布。 43 | -------------------------------------------------------------------------------- /SourceHanSansSC-VF.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/44670/SourceHanSans-Pixel/5fee6f152b5cbb92f1113b7560f9093ba6e5f012/SourceHanSansSC-VF.otf -------------------------------------------------------------------------------- /WorkBench.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "# pip3 install -r requirements.txt\n", 10 | "\n", 11 | "import freetype\n", 12 | "from PIL import Image, ImageDraw\n", 13 | "from io import StringIO" 14 | ] 15 | }, 16 | { 17 | "cell_type": "code", 18 | "execution_count": null, 19 | "metadata": {}, 20 | "outputs": [], 21 | "source": [ 22 | "# Preset: 16x15\n", 23 | "face = freetype.Face('SourceHanSansSC-VF.otf')\n", 24 | "face.set_pixel_sizes(17,15)\n", 25 | "face.set_var_design_coords((300,))\n", 26 | "\n", 27 | "FB_W = 16\n", 28 | "FB_H = 15\n", 29 | "FB_W_HALF = FB_W // 2\n", 30 | "OUT_FILE_NAME = 'font16x15.4FN'\n" 31 | ] 32 | }, 33 | { 34 | "cell_type": "code", 35 | "execution_count": null, 36 | "metadata": {}, 37 | "outputs": [], 38 | "source": [ 39 | "# Preset: 12x12\n", 40 | "face = freetype.Face('SourceHanSansSC-VF.otf')\n", 41 | "face.set_pixel_sizes(13,12)\n", 42 | "face.set_var_design_coords((320,))\n", 43 | "\n", 44 | "FB_W = 12\n", 45 | "FB_H = 11\n", 46 | "FB_W_HALF = FB_W // 2\n", 47 | "OUT_FILE_NAME = 'font12x11.4FN'" 48 | ] 49 | }, 50 | { 51 | "cell_type": "code", 52 | "execution_count": null, 53 | "metadata": {}, 54 | "outputs": [], 55 | "source": [ 56 | "# Preset: 8x8\n", 57 | "face = freetype.Face('SourceHanSansSC-VF.otf')\n", 58 | "face.set_pixel_sizes(9,9)\n", 59 | "face.set_var_design_coords((400,))\n", 60 | "\n", 61 | "FB_W = 8\n", 62 | "FB_H = 8\n", 63 | "FB_W_HALF = FB_W // 2\n", 64 | "OUT_FILE_NAME = 'font8x8.4FN'\n" 65 | ] 66 | }, 67 | { 68 | "cell_type": "code", 69 | "execution_count": null, 70 | "metadata": {}, 71 | "outputs": [], 72 | "source": [ 73 | "# Define functions to draw the character\n", 74 | "\n", 75 | "HEADER_SIZE = 1\n", 76 | "BMP_ROW_SIZE = (FB_W - 1) // 8 + 1\n", 77 | "BMP_SIZE = BMP_ROW_SIZE * FB_H\n", 78 | "CHAR_DATA_SIZE = BMP_SIZE + HEADER_SIZE\n", 79 | "FONT_PAGE_SIZE = CHAR_DATA_SIZE * 256\n", 80 | "\n", 81 | "print('BMP_SIZE', BMP_SIZE)\n", 82 | "logData = StringIO()\n", 83 | "def log(str):\n", 84 | " global logData\n", 85 | " logData.write(str + '\\n')\n", 86 | "\n", 87 | "\n", 88 | "def checkWidthEnforcement(ch):\n", 89 | " if (ch == ' '):\n", 90 | " return FB_W_HALF\n", 91 | " return 0\n", 92 | "\n", 93 | "def renderChar(ch):\n", 94 | " face.load_char(ch, flags=freetype.FT_LOAD_TARGET_MONO | freetype.FT_LOAD_RENDER)\n", 95 | " fb = [0] * (FB_W*FB_H)\n", 96 | " g = face.glyph\n", 97 | " offY = FB_H - max(g.bitmap_top, 0) - 1\n", 98 | " offX = max(g.bitmap_left, 0)\n", 99 | " b = g.bitmap\n", 100 | " w = b.width\n", 101 | " totalWidth = offX + w\n", 102 | " fbWidth = min(FB_W, totalWidth)\n", 103 | " if fbWidth <= 0:\n", 104 | " fbWidth = 1\n", 105 | " fbWidth = max(fbWidth, checkWidthEnforcement(ch))\n", 106 | " #if (fbWidth - totalWidth) >= 2:\n", 107 | " # offX += (fbWidth - totalWidth) // 2\n", 108 | " # totalWidth = offX + w\n", 109 | " h = b.rows\n", 110 | " offY = min(offY, FB_H - h)\n", 111 | " pitch = b.pitch\n", 112 | " buf = b.buffer\n", 113 | " t = 0\n", 114 | " overflowCnt = 0\n", 115 | " for cy in range(0, h):\n", 116 | " for cx in range(0, w):\n", 117 | " if (cx % 8 == 0):\n", 118 | " t = buf[pitch * cy + cx // 8]\n", 119 | " v = 0\n", 120 | " if (t & 0x80):\n", 121 | " v = 1\n", 122 | " posX = offX + cx\n", 123 | " posY = offY + cy\n", 124 | " if (posX < 0) or (posX >= FB_W) or (posY < 0) or (posY >= FB_H):\n", 125 | " overflowCnt += 1\n", 126 | " if overflowCnt <= 2:\n", 127 | " log('overflow %d %d %s' % ( posX, posY, ch))\n", 128 | " else:\n", 129 | " fb[posX + posY * FB_W] = v\n", 130 | " t <<= 1\n", 131 | " return (fb, fbWidth)\n", 132 | "\n", 133 | "def printFB(fb, fbWidth):\n", 134 | " ret = ''\n", 135 | " for y in range(0, FB_H):\n", 136 | " for x in range(0, fbWidth):\n", 137 | " ret += ['.', '#'][fb[x + y * FB_W]]\n", 138 | " ret += '\\n'\n", 139 | " print(ret)\n", 140 | " print(fbWidth)\n" 141 | ] 142 | }, 143 | { 144 | "cell_type": "code", 145 | "execution_count": null, 146 | "metadata": {}, 147 | "outputs": [], 148 | "source": [] 149 | }, 150 | { 151 | "cell_type": "code", 152 | "execution_count": null, 153 | "metadata": { 154 | "scrolled": false, 155 | "tags": [] 156 | }, 157 | "outputs": [], 158 | "source": [ 159 | "# Generate 4FN binary font file\n", 160 | "\n", 161 | "logData = StringIO()\n", 162 | "fontMagic = b'44Font0000000' + bytes([FB_W, FB_H, BMP_SIZE])\n", 163 | "fontIndex = [0xFF] * 256\n", 164 | "fontBuf = b''\n", 165 | "fontBufPtr = 0\n", 166 | "\n", 167 | "PLANES = [(0x00, 0xFF)] #[(0, 0), (0x30, 0x30), ]\n", 168 | "for (l, r) in PLANES:\n", 169 | " for p in range(l, l + r + 1):\n", 170 | " validCharCount = 0\n", 171 | " pageBuf = b''\n", 172 | " for rune in range(p << 8, (p << 8) + 256):\n", 173 | " header = 0\n", 174 | " bmp = [0] * (BMP_SIZE)\n", 175 | " if face.get_char_index(rune) != 0:\n", 176 | " validCharCount += 1\n", 177 | " log(chr(rune))\n", 178 | " (fb, fbWidth) = renderChar(chr(rune))\n", 179 | " header = fbWidth\n", 180 | " for y in range(0, FB_H):\n", 181 | " for x in range(0, FB_W):\n", 182 | " if fb[y * FB_W + x]:\n", 183 | " bmp[BMP_ROW_SIZE * y + (x // 8)] |= 1 << (x % 8)\n", 184 | " pageBuf += bytes([header])\n", 185 | " pageBuf += bytes(bmp)\n", 186 | " log('0x%02x00 %d %d' % (p, validCharCount, len(pageBuf)))\n", 187 | " if validCharCount == 0:\n", 188 | " continue\n", 189 | " fontIndex[p] = fontBufPtr\n", 190 | " fontBuf += pageBuf\n", 191 | " fontBufPtr += 1\n", 192 | "\n", 193 | "with open(OUT_FILE_NAME, 'wb') as f:\n", 194 | " f.write(fontMagic)\n", 195 | " f.write(bytes(fontIndex))\n", 196 | " f.write(fontBuf)\n", 197 | "\n", 198 | "with open('log.txt', 'wb') as f:\n", 199 | " f.write(logData.getvalue().encode('utf-8', 'ignore'))" 200 | ] 201 | }, 202 | { 203 | "cell_type": "code", 204 | "execution_count": null, 205 | "metadata": {}, 206 | "outputs": [], 207 | "source": [ 208 | "# Print a character to console\n", 209 | "\n", 210 | "fb, fbWidth = renderChar('喜')\n", 211 | "\n", 212 | "printFB(fb, fbWidth)" 213 | ] 214 | }, 215 | { 216 | "cell_type": "code", 217 | "execution_count": null, 218 | "metadata": {}, 219 | "outputs": [], 220 | "source": [ 221 | "# Draw a PNG test image\n", 222 | "\n", 223 | "txt = \"\"\"CJK字体测试。\n", 224 | "\n", 225 | "我能吞下玻璃而不伤身体。\n", 226 | "我能吞下玻璃而不傷身體。 \n", 227 | "私はガラスを食べられます。それは私を傷つけません。\n", 228 | "나는 유리를 먹을 수 있어요. 그래도 아프지 않아요\n", 229 | "1234567890!?\n", 230 | "\"\"\"\n", 231 | "img = Image.new('RGB', (320,240), color='white')\n", 232 | "pixels = img.load()\n", 233 | "posX = 0\n", 234 | "posY = 0\n", 235 | "\n", 236 | "def drawFB(fb, fbWidth):\n", 237 | " global posX, posY\n", 238 | "\n", 239 | " if (posX + fbWidth >= 320):\n", 240 | " posX = 0\n", 241 | " posY += FB_H + 1\n", 242 | " for y in range(0, FB_H):\n", 243 | " for x in range(0, fbWidth):\n", 244 | " if fb[x + y * FB_W]:\n", 245 | " pixels[posX + x, posY + y] = (0,0,0)\n", 246 | " posX += fbWidth\n", 247 | "\n", 248 | "\n", 249 | "\n", 250 | "for ch in txt:\n", 251 | " if (ch == '\\n'):\n", 252 | " posX = 0\n", 253 | " posY += FB_H + 1\n", 254 | " continue\n", 255 | " fb, fbWidth = renderChar(ch)\n", 256 | " drawFB(fb, fbWidth)\n", 257 | "img" 258 | ] 259 | }, 260 | { 261 | "cell_type": "code", 262 | "execution_count": null, 263 | "metadata": {}, 264 | "outputs": [], 265 | "source": [ 266 | "\n" 267 | ] 268 | } 269 | ], 270 | "metadata": { 271 | "interpreter": { 272 | "hash": "63fd5069d213b44bf678585dea6b12cceca9941eaf7f819626cde1f2670de90d" 273 | }, 274 | "kernelspec": { 275 | "display_name": "Python 3.9.0 64-bit", 276 | "name": "python3" 277 | }, 278 | "language_info": { 279 | "codemirror_mode": { 280 | "name": "ipython", 281 | "version": 3 282 | }, 283 | "file_extension": ".py", 284 | "mimetype": "text/x-python", 285 | "name": "python", 286 | "nbconvert_exporter": "python", 287 | "pygments_lexer": "ipython3", 288 | "version": "3.10.1" 289 | } 290 | }, 291 | "nbformat": 4, 292 | "nbformat_minor": 2 293 | } 294 | -------------------------------------------------------------------------------- /demo/12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/44670/SourceHanSans-Pixel/5fee6f152b5cbb92f1113b7560f9093ba6e5f012/demo/12.png -------------------------------------------------------------------------------- /demo/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/44670/SourceHanSans-Pixel/5fee6f152b5cbb92f1113b7560f9093ba6e5f012/demo/16.png -------------------------------------------------------------------------------- /examples/C/font.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "hal.h" 3 | 4 | u16 fbPosX; 5 | u16 fbPosY; 6 | 7 | typedef struct _FB_FONT { 8 | int valid; 9 | int charWidth; 10 | int charHeight; 11 | int charDataSize; 12 | int pageSize; 13 | u8 *pData; 14 | u8 *pIndex; 15 | u8 *pCharData; 16 | } FB_FONT; 17 | 18 | FB_FONT fbFontCJK16; 19 | FB_FONT *fbCurrentFont; 20 | 21 | static int fbLoadFontData(FB_FONT *pFont, const u8 *fontData) { 22 | memset(pFont, 0, sizeof(FB_FONT)); 23 | // TODO: check the magic of the font file 24 | pFont->valid = 1; 25 | pFont->charWidth = *(u8 *)(fontData + 13); 26 | pFont->charHeight = *(u8 *)(fontData + 14); 27 | printf("%d %d\n", pFont->charWidth, pFont->charHeight); 28 | pFont->charDataSize = 1 + ((pFont->charWidth + 7) / 8) * pFont->charHeight; 29 | pFont->pageSize = pFont->charDataSize * 256; 30 | pFont->pData = (u8 *)fontData; 31 | pFont->pIndex = pFont->pData + 16; 32 | pFont->pCharData = pFont->pIndex + 256; 33 | return 0; 34 | } 35 | 36 | void fbInit() { 37 | FB_FONT *pFont = &fbFontCJK16; 38 | const u8 *fontDataBuf = halGetFontDataPtr(); 39 | fbLoadFontData(pFont, fontDataBuf); 40 | 41 | fbCurrentFont = pFont; 42 | } 43 | 44 | static int fbDrawUnicodeRune(u32 rune) { 45 | if (!fbCurrentFont) { 46 | return 0; 47 | } 48 | // int fontW = fbCurrentFont->charWidth; 49 | int fontH = fbCurrentFont->charHeight; 50 | int fontCharSize = fbCurrentFont->charDataSize; 51 | int fontPageSize = fbCurrentFont->pageSize; 52 | 53 | int screenW = halGetScreenWidth(); 54 | int screenH = halGetScreenHeight(); 55 | rune = (u16)(rune); 56 | if (rune == '\n') { 57 | fbPosY += fontH + 1; 58 | fbPosX = 0; 59 | return 0; 60 | } 61 | u8 pgOffset = fbCurrentFont->pIndex[rune >> 8]; 62 | if (pgOffset == 0xFF) { 63 | return 0; 64 | } 65 | u8 *ptr = fbCurrentFont->pCharData + fontPageSize * pgOffset + 66 | fontCharSize * (rune & 0xff); 67 | u8 width = *ptr; 68 | ptr++; 69 | 70 | if (fbPosX + width >= screenW) { 71 | fbPosY += fontH + 1; 72 | fbPosX = 0; 73 | } 74 | if (fbPosY + fontH >= screenH) { 75 | return 0; 76 | } 77 | for (u8 y = 0; y < fontH; y++) { 78 | for (u8 x = 0; x < width; x++) { 79 | u8 pix = ptr[y * 2 + x / 8] & (1 << (x % 8)); 80 | if (pix) { 81 | halDrawPixel(fbPosX + x, fbPosY + y, 1); 82 | } 83 | } 84 | } 85 | fbPosX += width + 1; 86 | if (fbPosX >= screenW) { 87 | fbPosY += fontH + 1; 88 | fbPosX = 0; 89 | } 90 | return width; 91 | } 92 | 93 | void fbDrawUtf8String(const char *utf8Str) { 94 | u8 *p = (u8 *)utf8Str; 95 | u16 rune = 0; 96 | while (*p) { 97 | rune = 0; 98 | u8 byte1 = *p; 99 | p++; 100 | if ((byte1 & 0x80) == 0) { 101 | rune = byte1; 102 | } else { 103 | u8 byte2 = *p; 104 | p++; 105 | if (byte2 == 0) { 106 | break; 107 | } 108 | if ((byte1 & 0xE0) == 0xC0) { 109 | rune = ((byte1 & 0x1F) << 6) | (byte2 & 0x3F); 110 | } else { 111 | u8 byte3 = *p; 112 | p++; 113 | if (byte3 == 0) { 114 | break; 115 | } 116 | if ((byte1 & 0xf0) == 0xE0) { 117 | rune = 118 | ((byte1 & 0x0F) << 12) | ((byte2 & 0x3F) << 6) | (byte3 & 0x3F); 119 | } else { 120 | break; 121 | } 122 | } 123 | } 124 | fbDrawUnicodeRune(rune); 125 | } 126 | } -------------------------------------------------------------------------------- /examples/C/hal.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | typedef uint8_t u8; 8 | typedef uint16_t u16; 9 | typedef uint32_t u32; 10 | 11 | u8 frameBuffer[32][64]; 12 | 13 | int halGetScreenWidth() { return 64; } 14 | 15 | int halGetScreenHeight() { return 32; } 16 | 17 | void halDrawPixel(int x, int y, u32 color) { frameBuffer[y][x] = (u8)color; } 18 | 19 | const u8 *halGetFontDataPtr() { 20 | FILE *fp = fopen("../../font16x15.4FN", "rb"); 21 | fseek(fp, 0, SEEK_END); 22 | int fileLen = ftell(fp); 23 | printf("fileLen: %d\n", fileLen); 24 | fseek(fp, 0, SEEK_SET); 25 | 26 | u8 *buf = (u8 *)malloc(fileLen); 27 | fread(buf, fileLen, 1, fp); 28 | fclose(fp); 29 | 30 | return buf; 31 | } -------------------------------------------------------------------------------- /examples/C/main.c: -------------------------------------------------------------------------------- 1 | #include "font.h" 2 | #include 3 | 4 | int main() { 5 | fbInit(); 6 | fbDrawUtf8String("你好世界"); 7 | for (int y = 0; y < halGetScreenHeight(); y++) { 8 | for (int x = 0; x < halGetScreenWidth(); x++) { 9 | printf("%c", frameBuffer[y][x] ? '*' : ' '); 10 | } 11 | printf("\n"); 12 | } 13 | return 0; 14 | } -------------------------------------------------------------------------------- /examples/C/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | gcc -Wall main.c 4 | ./a.out -------------------------------------------------------------------------------- /font12x11.4FN: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/44670/SourceHanSans-Pixel/5fee6f152b5cbb92f1113b7560f9093ba6e5f012/font12x11.4FN -------------------------------------------------------------------------------- /font16x15.4FN: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/44670/SourceHanSans-Pixel/5fee6f152b5cbb92f1113b7560f9093ba6e5f012/font16x15.4FN -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | freetype-py 2 | Pillow --------------------------------------------------------------------------------