{"id":1853,"date":"2022-02-15T02:04:24","date_gmt":"2022-02-15T02:04:24","guid":{"rendered":"http:\/\/www.ishygddt.xyz\/~blog\/?p=1853"},"modified":"2022-11-09T15:11:47","modified_gmt":"2022-11-09T21:11:47","slug":"5x6-bitmap-font","status":"publish","type":"post","link":"http:\/\/www.ishygddt.xyz\/~blog\/2022\/02\/5x6-bitmap-font","title":{"rendered":"A very tiny bitmap font"},"content":{"rendered":"<p>The sprites are 6&#215;7 <em>including<\/em> a 1px margin on the right and bottom edges. The margin is occasionally tapped into by descenders (g, j, p, q, \u0192, \u00c7, \u03c6, \u045f, comma, semicolon, etc.), box-drawing characters, and other symbols that just wouldn't consistently compress below 6&#215;7 (\u2194, \u21a8, \u221a, etc.).<\/p>\n<p>I have crafted thus far all characters in IBM 437, Windows-1252, and the Macintosh Cyrillic codepage.<\/p>\n<p><a href=\"http:\/\/www.ishygddt.xyz\/~blog\/wp-content\/uploads\/2022\/02\/cp437_tinyfont.gif\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.ishygddt.xyz\/~blog\/wp-content\/uploads\/2022\/02\/cp437_tinyfont.gif\" width=\"96\" height=\"112\" \/><\/a> <a href=\"http:\/\/www.ishygddt.xyz\/~blog\/wp-content\/uploads\/2022\/03\/cp1252_tinyfont.gif\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.ishygddt.xyz\/~blog\/wp-content\/uploads\/2022\/03\/cp1252_tinyfont.gif\" width=\"96\" height=\"112\" \/><\/a> <a href=\"http:\/\/www.ishygddt.xyz\/~blog\/wp-content\/uploads\/2022\/02\/Cyrillic_tinyfont.gif\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.ishygddt.xyz\/~blog\/wp-content\/uploads\/2022\/02\/Cyrillic_tinyfont.gif\" width=\"96\" height=\"112\" \/><\/a><\/p>\n<p>(Original work; hereby published under a dual license <a href=\"https:\/\/creativecommons.org\/publicdomain\/zero\/1.0\/\">CC0<\/a>+<a href=\"http:\/\/www.wtfpl.net\/faq\/\">WTFPL<\/a>.)<\/p>\n<p>Could be useful for very small LCD displays, or for fitting an entire movie script on your monitor at once.<\/p>\n<hr \/>\n<p>It is not finished yet; my next goal is to figure out how to create <a title=\"OpenType Bitmap Font\" href=\"https:\/\/fontforge.org\/docs\/techref\/bitmaponlysfnt.html\">one of these<\/a> so I can actually <em>use<\/em> the thing\u2026 then I'll worry about adding more characters. (Fontforge is <em>waay<\/em> too sophisticated for this use-case, though, so it has ended up screwing up the font every time I tried to render an <code class=\"\" data-line=\"\">.obt<\/code> file: the letters all had \"shaved tops\", and the UI element to set their height manually was greyed-out. Hmm\u2026)<\/p>\n<hr \/>\n<h2>Appendices<\/h2>\n<h3>Compiler<\/h3>\n<pre><code class=\"language-python\" data-line=\"\">from PIL import Image\nimport struct, csv, gzip\n\n# USAGE:\n#\tpython3 make_psf.py 6x7 cp437_tinyfont.gif unicode_cp437.tsv 437-Handmade5x6.psf2.gz &amp;&amp; setfont -v 437-Handmade5x6.psf2.gz\n#\tpython3 make_psf.py 6x7 cp437_tinyfont.gif unicode_x1252.tsv x1252-Handmade5x6.psf2.gz &amp;&amp; setfont -v x1252-Handmade5x6.psf2.gz\n\n\nPSF2_MAGIC = b&#039;\\x72\\xb5\\x4a\\x86&#039;\nPSF2_HAS_UNICODE_TABLE = 0b1\nPSF2_MAXVERSION = 0\nPSF2_SEPARATOR = b&#039;\\xFF&#039;\nPSF2_STARTSEQ = b&#039;\\xFE&#039;\n\npsf2_header = struct.Struct(&#039;&lt;4sIiIII2I&#039;)\n\n# PCF IS WIP NOT YET IMPLEMENTED #\n# https:\/\/fontforge.org\/docs\/techref\/pcf-format.html\nPCF_MAGIC = b&#039;\\x01FCP&#039;\n\nPCF_PROPERTIES = 0b000000001\nPCF_ACCELERATORS = 0b000000010\nPCF_METRICS = 0b000000100\nPCF_BITMAPS = 0b000001000\nPCF_INK_METRICS = 0b000010000\nPCF_BDF_ENCODINGS = 0b000100000\nPCF_SWIDTHS = 0b001000000\nPCF_GLYPH_NAMES = 0b010000000\nPCF_BDF_ACCELERATORS = 0b100000000\n\nPCF_DEFAULT_FORMAT = 0x000\nPCF_INKBOUNDS = 0x200\nPCF_ACCEL_W_INKBOUNDS = 0x100\nPCF_COMPRESSED_METRICS = 0x100\n\nPCF_GLYPH_PAD_MASK = 0b000011\nPCF_BYTE_MASK = 0b000100\nPCF_BIT_MASK = 0b001000\nPCF_SCAN_UNIT_MANK = 0b110000\n\npcf_header_1 = struct.Struct(&#039;&lt;4sI&#039;)\npcf_header_2 = struct.Struct(&#039;&lt;IIII&#039;)\n\ndef im2glyphs(im, w, h):\n\tfor y in range(0, im.height, h):\n\t\tfor x in range(0, im.width, w):\n\t\t\tyield im.crop((x, y, x+w, y+h))\n\ndef _makeheader(glyphs, *, ver=PSF2_MAXVERSION, flags=0):\n\tn = len(glyphs)\n\tassert len(set(glyph.size for glyph in glyphs)) == 1\n\tw, h = glyphs[0].size\n\tglyphsize = h * ((w + 7) \/\/ 8)\n\t#glyphsize = -(w * h \/\/ -8)\n\treturn psf2_header.pack(PSF2_MAGIC, ver, psf2_header.size, flags, n, glyphsize, h, w)\n\ndef _makebody(glyphs):\n\tassert len(set(glyph.size for glyph in glyphs)) == 1\n\tfor glyph in glyphs:\n\t\tyield glyph.convert(&#039;1&#039;).tobytes()\n\ndef _makeuctable(unicodemap):\n\tfor position in unicodemap:\n\t\tfor sequence in position:\n\t\t\tyield PSF2_STARTSEQ\n\t\t\tyield sequence.encode(&quot;utf-8&quot;)\n\t\tyield PSF2_SEPARATOR\n\ndef makepsf2(size, im, out, unicodemap=None):\n\tglobal glyphs # for debugging, run python -i \n\tglyphs = list(im2glyphs(im, *size))\n\tflags = 0\n\tif unicodemap is not None:\n\t\tflags |= PSF2_HAS_UNICODE_TABLE\n\telse:\n\t\tassert len(glyphs) == 256\n\tout.write(_makeheader(glyphs, flags=flags))\n\tfor chunk in _makebody(glyphs):\n\t\tout.write(chunk)\n\tif unicodemap is not None:\n\t\tfor chunk in _makeuctable(unicodemap):\n\t\t\tout.write(chunk)\n\nif __name__ == &#039;__main__&#039;:\n\timport sys\n\tsize = map(int, sys.argv[1].split(&#039;x&#039;))\n\tim = Image.open(sys.argv[2])\n\twith open(sys.argv[3], &#039;r&#039;) as f:\n\t\tr = csv.reader(f, delimiter=&#039;\\t&#039;)\n\t\tunicodemap = list(r)\n\t\tif unicodemap[0][0] == &#039;&#039;:\n\t\t\tunicodemap[0][0] = &#039;\\u0000&#039;\n\t\tif unicodemap[255][0] == &#039;\\x20&#039; and unicodemap[0x20][0] == &#039;\\x20&#039;:\n\t\t\tunicodemap[255][0] = &#039;\\u00A0&#039;\n\twith gzip.open(sys.argv[4], &#039;wb&#039;) as f:\n\t\tmakepsf2(size, im, f, unicodemap)<\/code><\/pre>\n<h3>datafiles<\/h3>\n<h4>CP437 Unicode Table<\/h4>\n<pre>\"\"\r\n\u263a\r\n\u263b\r\n\u2665\r\n\u2666\r\n\u2663\r\n\u2660\r\n\u2022\r\n\u25d8\r\n\u25cb\r\n\u25d9\r\n\u2642\r\n\u2640\r\n\u266a\t\ud834\udd58\ud834\udd65\ud834\udd6e\r\n\u266b\r\n\u263c\r\n\u25ba\t\u25b6\t\u25b8\r\n\u25c4\r\n\u2195\t\u16e8\r\n\u203c\r\n\u00b6\r\n\u00a7\r\n\u25ac\r\n\u21a8\r\n\u2191\t\u16cf\r\n\u2193\r\n\u2192\r\n\u2190\r\n\u221f\r\n\u2194\r\n\u25b2\r\n\u25bc\r\n\" \"\r\n!\t\u01c3\t\u2d51\r\n\"\"\"\"\r\n#\r\n$\r\n%\t\u066a\t\u2052\r\n&amp;\r\n'\t\u02bb\t\u02b9\t\u02c8\t\u0374\t\u144a\t\ua78c\r\n(\t\u2772\r\n)\t\u2773\r\n*\t\u2217\t\ud800\udf1f\r\n+\r\n,\t\u00b8\t\u060d\t\u201a\t\ua4f9\r\n-\t\u02d7\t\u2010\t\u2011\r\n.\t\u0701\t\u0702\t\u2024\t\ua4f8\t\ud834\udd6d\r\n\/\t\u1735\t\u2215\t\u3033\t\ud834\ude3a\r\n0\r\n1\r\n2\r\n3\t\u0417\t\u04e0\r\n4\r\n5\r\n6\t\u0431\r\n7\r\n8\r\n9\r\n:\t\u02d0\t\u02f8\t\u0589\t\u05c3\t\u0703\t\u0704\t\u0903\t\u0a83\t\u16ec\t\u1803\t\u1809\t\u205a\t\u2236\t\ua4fd\t\ua789\t\ufe30\t\uff1a\r\n;\t\u037e\r\n&lt;\t\u1438\t\ud834\ude36\r\n=\r\n&gt;\t\u1433\t\ud81b\udf3f\t\ud834\ude37\r\n?\r\n@\r\nA\t\u0391\t\u0410\r\nB\t\u0392\t\u0412\r\nC\t\u03f9\t\u0421\r\nD\r\nE\t\u0395\t\u0415\r\nF\r\nG\r\nH\t\u0397\t\u041d\r\nI\t\u0399\t\u0406\t\u04c0\r\nJ\t\u0408\r\nK\t\u039a\t\u041a\r\nL\r\nM\t\u039c\t\u041c\r\nN\t\u039d\r\nO\t\u039f\t\u041e\r\nP\t\u03a1\t\u0420\r\nQ\t\u051a\r\nR\r\nS\t\u0405\t\ua682\r\nT\t\u03a4\t\u0422\r\nU\r\nV\r\nW\t\u051c\r\nX\t\u03a7\t\u0425\r\nY\t\u03a5\t\u04ae\r\nZ\t\u0396\r\n[\r\n\\\r\n]\r\n^\t\u02c4\t\u02c6\r\n_\r\n`\r\na\t\u0430\r\nb\r\nc\t\u0441\r\nd\r\ne\t\u0435\r\nf\r\ng\r\nh\t\u04bb\r\ni\t\u0456\r\nj\t\u0458\r\nk\t\u03ba\r\nl\r\nm\r\nn\r\no\t\u03bf\t\u043e\r\np\t\u0440\r\nq\t\u051b\r\nr\r\ns\t\u0455\r\nt\r\nu\r\nv\r\nw\t\u051d\r\nx\t\u0445\r\ny\t\u03b3\t\u0443\t\u04af\r\nz\r\n{\r\n|\t\u04cf\r\n}\r\n~\r\n\u2302\t\ud83c\udfe0\r\n\u00c7\r\n\u00fc\r\n\u00e9\r\n\u00e2\r\n\u00e4\t\u04d3\r\n\u00e0\r\n\u00e5\r\n\u00e7\t\u03c2\t\u04ab\r\n\u00ea\r\n\u00eb\t\u0451\r\n\u00e8\t\u0450\r\n\u00ef\t\u03ca\t\u0457\r\n\u00ee\r\n\u00ec\r\n\u00c4\t\u04d2\r\n\u00c5\t\u212b\r\n\u00c9\r\n\u00e6\t\u04d5\r\n\u00c6\t\u04d4\r\n\u00f4\r\n\u00f6\t\u04e7\r\n\u00f2\r\n\u00fb\r\n\u00f9\r\n\u00ff\t\u04f1\r\n\u00d6\t\u04e6\r\n\u00dc\r\n\u00a2\r\n\u00a3\r\n\u00a5\r\n\u20a7\r\n\u0192\r\n\u00e1\r\n\u00ed\r\n\u00f3\r\n\u00fa\r\n\u00f1\r\n\u00d1\r\n\u00aa\r\n\u00ba\r\n\u00bf\r\n\u2310\r\n\u00ac\r\n\u00bd\r\n\u00bc\r\n\u00a1\r\n\u00ab\r\n\u00bb\r\n\u2591\r\n\u2592\r\n\u2593\r\n\u2502\r\n\u2524\r\n\u2561\r\n\u2562\r\n\u2556\r\n\u2555\r\n\u2563\r\n\u2551\r\n\u2557\r\n\u255d\r\n\u255c\r\n\u255b\r\n\u2510\r\n\u2514\r\n\u2534\r\n\u252c\r\n\u251c\r\n\u2500\r\n\u253c\r\n\u255e\r\n\u255f\r\n\u255a\r\n\u2554\r\n\u2569\r\n\u2566\r\n\u2560\r\n\u2550\r\n\u256c\r\n\u2567\r\n\u2568\r\n\u2564\r\n\u2565\r\n\u2559\r\n\u2558\r\n\u2552\r\n\u2553\r\n\u256b\r\n\u256a\r\n\u2518\r\n\u250c\r\n\u2588\r\n\u2584\r\n\u258c\r\n\u2590\r\n\u2580\r\n\u03b1\r\n\u00df\t\u03b2\r\n\u0393\t\u0413\t\u0413\r\n\u03c0\r\n\u03a3\r\n\u03c3\r\n\u00b5\t\u03bc\r\n\u03c4\t\ua68d\r\n\u03a6\t\u0424\r\n\u0398\t\u0472\t\u04e8\r\n\u03a9\t\u2126\r\n\u03b4\r\n\u221e\t\ua699\r\n\u03c6\r\n\u03b5\t\u0454\t\u025b\r\n\u2229\r\n\u2261\t\u039e\r\n\u00b1\r\n\u2265\r\n\u2264\r\n\u2320\r\n\u2321\r\n\u00f7\r\n\u2248\r\n\u00b0\r\n\u2219\r\n\u00b7\t\ud802\ude50\t\u0660\t\u06f0\r\n\u221a\r\n\u207f\r\n\u00b2\r\n\u25a0\r\n\" \"<\/pre>\n<h4>x1252 Unicode Table<\/h4>\n<pre>\u25cb\r\n\u25a0\r\n\u2191\t\u16cf\r\n\u2193\r\n\u2192\r\n\u2190\r\n\u2551\r\n\u2550\r\n\u2554\r\n\u2557\r\n\u255a\r\n\u255d\r\n\u2591\r\n\u2592\r\n\u25ba\t\u25b6\t\u25b8\r\n\u25c4\r\n\u2502\r\n\u2500\r\n\u250c\r\n\u2510\r\n\u2514\r\n\u2518\r\n\u251c\r\n\u2524\r\n\u2534\r\n\u252c\r\n\u2666\r\n\u253c\r\n\u2588\r\n\u2584\r\n\u2580\r\n\u25ac\r\n\" \"\r\n!\t\u01c3\t\u2d51\r\n\"\"\"\"\r\n#\r\n$\r\n%\t\u066a\t\u2052\r\n&amp;\r\n'\t\u02bb\t\u02b9\t\u02c8\t\u0374\t\u144a\t\ua78c\r\n(\t\u2772\r\n)\t\u2773\r\n*\t\u2217\t\ud800\udf1f\r\n+\r\n,\t\u00b8\t\u060d\t\ua4f9\r\n-\t\u02d7\t\u2010\t\u2011\r\n.\t\u0701\t\u0702\t\u2024\t\ua4f8\t\ud834\udd6d\r\n\/\t\u1735\t\u2215\t\u3033\t\ud834\ude3a\r\n0\r\n1\r\n2\r\n3\t\u0417\t\u04e0\r\n4\r\n5\r\n6\t\u0431\r\n7\r\n8\r\n9\r\n:\t\u02d0\t\u02f8\t\u0589\t\u05c3\t\u0703\t\u0704\t\u0903\t\u0a83\t\u16ec\t\u1803\t\u1809\t\u205a\t\u2236\t\ua4fd\t\ua789\t\ufe30\t\uff1a\r\n;\t\u037e\r\n&lt;\t\u1438\t\ud834\ude36\r\n=\r\n&gt;\t\u1433\t\ud81b\udf3f\t\ud834\ude37\r\n?\r\n@\r\nA\t\u0391\t\u0410\r\nB\t\u0392\t\u0412\r\nC\t\u03f9\t\u0421\r\nD\r\nE\t\u0395\t\u0415\r\nF\r\nG\r\nH\t\u0397\t\u041d\r\nI\t\u0399\t\u0406\t\u04c0\r\nJ\t\u0408\r\nK\t\u039a\t\u041a\r\nL\r\nM\t\u039c\t\u041c\r\nN\t\u039d\r\nO\t\u039f\t\u041e\r\nP\t\u03a1\t\u0420\r\nQ\t\u051a\r\nR\r\nS\t\u0405\t\ua682\r\nT\t\u03a4\t\u0422\r\nU\r\nV\r\nW\t\u051c\r\nX\t\u03a7\t\u0425\r\nY\t\u03a5\t\u04ae\r\nZ\t\u0396\r\n[\r\n\\\r\n]\r\n^\r\n_\r\n`\r\na\t\u0430\r\nb\r\nc\t\u0441\r\nd\r\ne\t\u0435\r\nf\r\ng\r\nh\t\u04bb\r\ni\t\u0456\r\nj\t\u0458\r\nk\t\u03ba\r\nl\r\nm\r\nn\r\no\t\u03bf\t\u043e\r\np\t\u0440\r\nq\t\u051b\r\nr\r\ns\t\u0455\r\nt\r\nu\r\nv\r\nw\t\u051d\r\nx\t\u0445\r\ny\t\u03b3\t\u0443\t\u04af\r\nz\r\n{\r\n|\t\u04cf\r\n}\r\n~\r\n\r\n\u20ac\r\n\r\n\u201a\r\n\u0192\r\n\u201e\r\n\u2026\r\n\u2020\r\n\u2021\r\n\u02c6\t\u02c4\r\n\u2030\r\n\u0160\r\n\u2039\r\n\u0152\r\n\r\n\u017d\r\n\r\n\r\n\u2018\r\n\u2019\r\n\u201c\r\n\u201d\r\n\u2022\r\n\u2013\r\n\u2014\r\n\u02dc\r\n\u2122\r\n\u0161\r\n\u203a\r\n\u0153\r\n\r\n\u017e\r\n\u0178\r\n\r\n\u00a1\r\n\u00a2\r\n\u00a3\r\n\u00a4\r\n\u00a5\r\n\u00a6\r\n\u00a7\r\n\u00a8\r\n\u00a9\r\n\u00aa\r\n\u00ab\r\n\u00ac\r\n\"\u00ad\"\r\n\u00ae\r\n\u00af\r\n\u00b0\r\n\u00b1\r\n\u00b2\r\n\u00b3\r\n\u00b4\r\n\u00b5\t\u03bc\r\n\u00b6\r\n\u00b7\r\n\u00b8\r\n\u00b9\r\n\u00ba\r\n\u00bb\r\n\u00bc\r\n\u00bd\r\n\u00be\r\n\u00bf\r\n\u00c0\r\n\u00c1\r\n\u00c2\r\n\u00c3\r\n\u00c4\t\u04d2\r\n\u00c5\t\u212b\r\n\u00c6\t\u04d4\r\n\u00c7\r\n\u00c8\r\n\u00c9\r\n\u00ca\r\n\u00cb\r\n\u00cc\r\n\u00cd\r\n\u00ce\r\n\u00cf\r\n\u0110\r\n\u00d1\r\n\u00d2\r\n\u00d3\r\n\u00d4\r\n\u00d5\r\n\u00d6\r\n\u00d7\r\n\u00d8\r\n\u00d9\r\n\u00da\r\n\u00db\r\n\u00dc\r\n\u00dd\r\n\u00de\r\n\u00df\r\n\u00e0\r\n\u00e1\r\n\u00e2\r\n\u00e3\r\n\u00e5\r\n\u00e4\t\u04d3\r\n\u00e6\t\u04d5\r\n\u00e7\t\u03c2\t\u04ab\r\n\u00e8\t\u0450\r\n\u00e9\r\n\u00ea\r\n\u00eb\r\n\u00ec\r\n\u00ed\r\n\u00ee\r\n\u00ef\r\n\u00f0\t\u2202\r\n\u00f1\r\n\u00f2\r\n\u00f3\r\n\u00f4\r\n\u00f5\r\n\u00f6\r\n\u00f7\r\n\u00f8\r\n\u00f9\r\n\u00fa\r\n\u00fb\r\n\u00fc\r\n\u00fd\r\n\u00fe\r\n\u00ff<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Could be useful for very small LCD displays, or for fitting an entire movie script on your monitor at once. TODO: convert to OpenType Bitmap\u2026<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[97],"tags":[98,100,51,99],"class_list":["post-1853","post","type-post","status-publish","format-standard","hentry","category-original-content","tag-art","tag-font","tag-linux","tag-pixelart"],"_links":{"self":[{"href":"http:\/\/www.ishygddt.xyz\/~blog\/wp-json\/wp\/v2\/posts\/1853","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.ishygddt.xyz\/~blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.ishygddt.xyz\/~blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.ishygddt.xyz\/~blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/www.ishygddt.xyz\/~blog\/wp-json\/wp\/v2\/comments?post=1853"}],"version-history":[{"count":30,"href":"http:\/\/www.ishygddt.xyz\/~blog\/wp-json\/wp\/v2\/posts\/1853\/revisions"}],"predecessor-version":[{"id":2425,"href":"http:\/\/www.ishygddt.xyz\/~blog\/wp-json\/wp\/v2\/posts\/1853\/revisions\/2425"}],"wp:attachment":[{"href":"http:\/\/www.ishygddt.xyz\/~blog\/wp-json\/wp\/v2\/media?parent=1853"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.ishygddt.xyz\/~blog\/wp-json\/wp\/v2\/categories?post=1853"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.ishygddt.xyz\/~blog\/wp-json\/wp\/v2\/tags?post=1853"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}