Created
June 3, 2015 07:23
-
-
Save fpsunflower/7e6311c9580409c115a0 to your computer and use it in GitHub Desktop.
Tiny bitmap font rendering
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// c++ -o nanofont nanofont.cpp && time ./nanofont /tmp/font.png && open /tmp/font.png | |
#include <cstdio> | |
#include <vector> | |
// Glyphs from http://font.gohu.org/ (8x14 version, most common ascii characters only) | |
// Arguments are the ascii character to print, and x and y positions within the glyph. | |
// This function must be paired with some mechanism to plot pixels (sample below). | |
inline bool glyph_pixel(unsigned int c, unsigned int x, unsigned int y) { | |
c -= 33; x--; if (c > 93 || x > 6 || y > 13) return 0; int i = 98 * c + 7 * y + x; | |
return (("0@P01248@00120000P49B0000000000000:DXlW2UoDX@10008@h;IR4n@R<Y?48000PYDF" | |
"PP011J:U1000<T8QQQDAR4a50000@P012000000000000222448@P024@010028P0148@PP011100000" | |
"ABELDU410000000048@l7124000000000000000H`01100000000n10000000000000000006<0000@P" | |
"P011224488@00000`CXHY:=:D8?0000004<DT01248@000000l4:444444h700000`C8@Ph02D8?0000" | |
"008HX89b?8@P000000n58`7@P05b300000`CP0O25:D8?00000POPP0112248000000l4:D8?Q25b300" | |
"000`CX@Ql1244700000000H`0000<H00000000`P1000H`0110000044444@014@0000000n100PO000" | |
"0000004@014@@@@@0000h948@@@@00120000`G`l5;F\\Lf0n100000l4:DXOQ25:400000hCX@Qn4:D" | |
"X?000000?Q248@P0Ql000000N49DX@Q25i100000hGP01N48@PO00000PO124hAP012000000l4:@PLQ" | |
"25b3000008DX@Qn5:DX@000000748@P0124L00000001248@P25b3000008DT456D8AT@00000P01248" | |
"@P01n10000017G=IbP1364000008dXAU:U:E\\H000000?Q25:DX@Ql000000n4:DX?1248000000`CX" | |
"@Q2U:E4GP0000P?Q25jCR8Q2100000l4:@0?P05b300000l71248@P01200000P@Q25:DX@Ql0000002" | |
"5:D89BT`P1000004<HbT9[:BT800000P@QT8QQ49Q210000013:B4548@P000000h7888888@PO00000" | |
"7248@P01248`10P0148P0148P0148000h01248@P0124>000015A000000000000000000000000h?00" | |
"04@010000000000000000l0bGX@aL10000124XcX@Q25j300000000?Q248@8?000008@Pl5:DX@aL10" | |
"000000`CX@o24`70000`AP01N48@P0100000000l5:DX@aL12T70124XcX@Q25:40000@P0P348@P01>" | |
"00000240HP01248@P0a101248@T47B4940000HP01248@P01L00000000oBV<IbT910000000hCX@Q25" | |
":400000000?Q25:D8?00000000j<:DX@Qn48@00000`GX@Q25c58@P0000P>S248@P000000000l48P7" | |
"@Pn0000048@`31248@030000000P@Q25:D<G0000000025:T49<H000000004<HbTE5920000000P@QT" | |
"`@BX@0000000025:DX@aL12T70000h744444h70000PS01248>P0124`1001248@P01248@P0007@P01" | |
"24`@P01R30000000S9S10000000"[i / 6] - '0') >> (i % 6)) & 1; | |
} | |
// Example usage: | |
struct Img { | |
Img(unsigned w, unsigned h) : w(w), h(h), p(w * h, 0) {} | |
// draw characters one at a time | |
void draw_string(const char* msg, int bx, int by) { | |
for (int lx = bx; *msg; | |
lx = *msg == '\n' ? bx : lx + 8, | |
by = *msg != '\n' ? by : by + 14, | |
msg++) | |
for (int y = 0; y < 14; y++) | |
for (int x = 0; x < 8 ; x++) | |
if (glyph_pixel(*msg, x, y)) | |
plot(lx + x, by + y); | |
} | |
void plot(unsigned x, unsigned y) { | |
if (x < w && y < h) p[y * w + x] = 0xff; | |
} | |
unsigned w, h; std::vector<unsigned char> p; | |
}; | |
// nanopng: https://gist.github.com/fpsunflower/a79b06e92968465397d4 | |
// tweaked for single channel output | |
struct Png { | |
FILE*f; unsigned int tab[256], crc; ~Png() { fclose(f); } | |
Png(const char* fn, int w, int h, const unsigned char* c) { | |
crc=0x575e51f5;unsigned char d[]={137,80,78,71,13, | |
10,26,10,0,0,0,13,73,72,68,82,73,68,65,84,120,1,0, | |
0,0,73,69,78,68,174,66,96,130};/*chunk headers*/ | |
for (int i=0;i<256;i++)/*precompute crc tables*/ | |
for (unsigned int j=8,&v=tab[i]=i;j--;) | |
v=(v>>1)^(0xedb88320u&(~(v&1)+1)); | |
fwrite(d,1,16,f=fopen(fn,"w")); /*write IHDR+IDAT*/ | |
*this>>w>>h<<8<<2<<0<<0<<0;int a=1,b=0;/*adler-32*/ | |
*this>>~crc>>(h*(w*3+6)+6);int len=w*3+1;/*nbytes*/ | |
fwrite(d+16,1,6,f);crc=0x13e5812d; | |
for (;h--;) {/*DEFLATE raw block*/ | |
*this<<!h<<len<<(len>>8)<<~len<<(~len>>8); | |
/*filter=0*/*this <<0;/*adler(0)*/b=(a+b)%65521; | |
for (int x=w,v;x--;){ /*write & checksum*/ | |
v=*c++;*this<<v;a=(a+v)%65521;b=(a+b)%65521; | |
*this<<v;a=(a+v)%65521;b=(a+b)%65521; | |
*this<<v;a=(a+v)%65521;b=(a+b)%65521; | |
} | |
} | |
*this>>((b<<16)|a);*this>>~crc;fwrite(d+22,1,12,f); | |
} | |
Png& operator<<(int b){crc=(crc>>8)^tab[(crc^fputc(b,f))&255];return *this;} | |
Png& operator>>(unsigned int v) {return *this<<(v>>24)<<(v>>16)<<(v>>8)<<v;} | |
}; | |
int main(int argc, const char** argv) { | |
Img img(560, 128); img.draw_string( | |
"| #include <stdio.h>\n" | |
"|\n" | |
"|\n" | |
"| // The quick brown fox jumps over the lazy dog.\n" | |
"| int main(int argc, const char* argv[]) {\n" | |
"| printf(\"Hello World!\\n\");\n" | |
"| return 0;\n" | |
"| }\n" | |
"|", 144, 0); | |
for (char s[] = { 0, 0 }; *s < 127; s[0]++) | |
img.draw_string(s, 8 * (*s % 16), 14 * (*s / 16)); | |
Png(argc < 2 ? "/tmp/test.png" : argv[1], img.w, img.h, &img.p[0]); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment