/* this program is designed to convert my neoletters font into a ttf */ #include "stdio.h" #include "stdint.h" #include "string.h" #include "stdlib.h" #include "time.h" #include "ctype.h" #include "byteswap.h" #include "u8.h" #include "bdf.h" #define ei else if int xdgval(int c){ if(c >= '0' && c <= '9')return c - '0'; if(c >= 'A' && c <= 'F')return c - 'A' + 10; if(c >= 'a' && c <= 'f')return c - 'a' + 10; return 0; } uint32_t read32(FILE *f){ uint32_t c; fread(&c,4,1,f); // c = (c >> 16) | (c << 16); // c = (c >> 8 & 0xFF00FF) | (c << 8 & 0xFF00FF00); return bswap_32(c); } void write32(FILE *f,uint32_t c){ // c = c >> 16 | c << 16; // c = (c >> 8 & 0xFF00FF) | (c << 8 & 0xFF00FF00); c = bswap_32(c); fwrite(&c,4,1,f); } void write64(FILE *f,uint64_t c){ // c = c >> 32 | c << 32; // c = (c >> 16 & 0xFFFF0000FFFF) | (c << 16 & 0xFFFF0000FFFF0000); // c = (c >> 8 & 0xFF00FF00FF00FF) | (c << 8 & 0xFF00FF00FF00FF00); c = bswap_64(c); fwrite(&c,8,1,f); } void writestr(FILE *f,char*s){ fwrite(s,1,strlen(s),f); } uint16_t read16(FILE *f){ uint16_t c; fread(&c,2,1,f); // c = c >> 8 | c << 8; return bswap_16(c); } void write16(FILE *f, uint16_t c){ c = bswap_16(c);//c >> 8 | c << 8; fwrite(&c,2,1,f); } void write8(FILE *f, uint8_t c){ fwrite(&c,1,1,f); } void goloc(FILE *f, long loc){ fseek(f,loc,SEEK_SET); } void gorel(FILE *f, long x){ fseek(f,x,SEEK_CUR); } void ffastfw(FILE *f){ fseek(f,0,SEEK_END); } void writenameent(FILE *f,FILE *sf, int plat,int code,int lang, int name,char *s, int len){ write16(f,plat);//windows write16(f,code);//ucs write16(f,lang);//english write16(f,name);//name id 1 font family write16(f,len);//string length write16(f,ftell(sf)); //offset fwrite(s,len,1,sf); } void makepathmap(struct bdfglyph*g); //temporary storage; char line[300]; char pathmap[17*19]; struct point {char x,y,start;} pathlist[17*19*2]; int pathend; int bdfpthchk(struct bdfglyph g,int x,int y); void addpath(int x,int y); void writefile(FILE *f,FILE*g){ rewind(g); int c; while((c=fgetc(g))!=EOF)fputc(c,f); } unsigned writeblanktable(FILE *f,char*s){ writestr(f,s); unsigned x = ftell(f); write32(f,0);//cksum write32(f,0);//location write32(f,0);//length return x; } void finalizetable(FILE *f,unsigned tblent,unsigned tblloc,unsigned tbllen){ int padc = tbllen % 4; if(padc==1)fwrite("\0\0\0",1,3,f); if(padc==2)fwrite("\0\0",1,2,f); if(padc==3)fwrite("\0",1,1,f); unsigned lenwpad = tbllen/4 + (padc?1:0); uint32_t sum = 0; goloc(f,tblloc); int i; for(i=0;i<lenwpad;i++)sum += read32(f); goloc(f,tblent); write32(f,sum); write32(f,tblloc); write32(f,tbllen); ffastfw(f); if(ftell(f) % 4 != 0){printf("ERRO misaligned padc=%d ftell=%ld tblloc=%d tbllen=%d\n",padc,ftell(f),tblloc,tbllen);exit(1);} } void checkext(char *name, char *ext){ char *i = name; char *j = ext; while(*i)i++; while(*j)j++; while(j >= ext){ if(*i != *j){ fprintf(stderr,"Extension mismatch: %s want %s\r\n",name,ext); abort(); } i--;j--; } } void showbar(int total, int cur, int wid) { if (total == 0)return; int i,pix = cur * 8*wid / total; for(i=0;i<pix/8;i++)fputs("\342\226\210",stdout); if(pix%8!=0)printf("\342\226%c",0220-pix%8); int bl = wid - pix/8 - !!(pix%8); for(i=0;i<bl;i++)putchar(' '); } void bdf2ttf_status(struct bdfglyph *g,int cur,int tot) { printf("\e[8H\e[Kstatus: U%05x\n\r\e[Kname: %s",g->encoding,g->name); printf("\e[3H%3d%%\e[36;43m",cur*100/tot); showbar(tot,cur,30); printf("\e[0m"); outputasbitmap(g,4,1); } int main (int argc, char**argv) { printf("\e[2J\e[1;1H\e[41mOren's 𝔹𝔻𝔽 2 𝑻𝑻𝑭\e[0m\n"); char * bdfname = "in.bdf"; char * ttfname = "out.ttf"; if (argc > 1)bdfname = argv[1]; if (argc > 2)ttfname = argv[2]; checkext(bdfname,"bdf"); checkext(ttfname,"ttf"); FILE *out = fopen(ttfname,"w+"); printf("\e[2;1HLoading BDF %s",bdfname); struct bdfglyph **font = (void*)calloc(0x20000,sizeof(void*)); struct bdfinfo fontinfo; load_font(bdfname,font,&fontinfo,bdf2ttf_status); printf("\e[2;1H\e[2K\e[0JWriting TTF Tables:"); printf("\e[3;1H\e[33m[OS/2][cmap][cvt ][glyf][head][hhea][hmtx][loca][maxp][name][post]\e[0m"); /* write ttf file header */ write32(out,0x00010000); write16(out,11); write16(out,128); write16(out,3); write16(out,48); unsigned os2ent = writeblanktable(out,"OS/2"); // the table entries unsigned cmapent = writeblanktable(out,"cmap"); unsigned cvtent = writeblanktable(out,"cvt "); unsigned glyfent = writeblanktable(out,"glyf"); unsigned headent = writeblanktable(out,"head"); unsigned hheaent = writeblanktable(out,"hhea"); unsigned hmtxent = writeblanktable(out,"hmtx"); unsigned locaent = writeblanktable(out,"loca"); unsigned maxpent = writeblanktable(out,"maxp"); unsigned nameent = writeblanktable(out,"name"); unsigned postent = writeblanktable(out,"post"); #define UPM 16 unsigned cvtloc = ftell(out); write32(out,0x00000000);//AAAAAAAAA unsigned cvtlen = ftell(out) - cvtloc; finalizetable(out,cvtent,cvtloc,cvtlen); printf("\e[3;13H\e[36;1m[cvt ]\e[0m"); /* write the head table */ unsigned headloc = ftell(out); write16(out,1);//major write16(out,0);//minor write32(out,0x00010000);//font version write32(out,0);//checksumadjustment write32(out,0x5F0F3CF5);//magic number write16(out,0x0000);//flags write16(out,UPM);//units per em write64(out,time(0) + 24107ULL * 86400ULL);//date created write64(out,time(0) + 24107ULL * 86400ULL);//date modified write16(out,0);//xmin write16(out,-4);//ymin write16(out,18);//xmax write16(out,12);//ymax write16(out,0);//macstyle write16(out,8);//lowest recommended ppem write16(out,2);// deprecated set to 2 write16(out,1);// 0 short/long 1 format for loca table write16(out,0);// glyph data format, always 0 unsigned headlen = ftell(out) - headloc; finalizetable(out,headent,headloc,headlen); printf("\e[3;25H\e[32m[head]\e[0m"); /*write the hhea table*/ unsigned hhealoc = ftell(out); write16(out,1); write16(out,0); write16(out,UPM*3/4);//ascent write16(out,-UPM/4);//descent write16(out,0);//line gap write16(out,18);//max advance width write16(out,0);//min left sidebearing write16(out,0);//min right sidebearing write16(out,18);//max extent write16(out,0);//slope rise write16(out,1);//slope run write16(out,0);//slant shift write16(out,0);//reserved write16(out,0);//reserved write16(out,0);//reserved write16(out,0);//reserved write16(out,0);//metric data fmt always 0 write16(out,fontinfo.nchars);//number of hmtx unsigned hhealen = ftell(out) - hhealoc; finalizetable(out,hheaent,hhealoc,hhealen); printf("\e[3;31H\e[36;1m[hhea]\e[0m"); /*write the OS/2 table*/ unsigned os2loc = ftell(out); write16(out,4); write16(out,UPM*9/16);//average width write16(out,500);//Medium Weight write16(out,5);//Medium Width write16(out,0);//fstype write16(out,UPM);//subscript x size write16(out,UPM/2);//subscript y size write16(out,0);//subscript x offset write16(out,UPM/4);//subscript y offset write16(out,UPM);//superscript x size write16(out,UPM/2);//superscript y size write16(out,0);//superscript x offset write16(out,UPM/4);//superscript y offset write16(out,UPM*2/16);//strikeout size write16(out,UPM/4);//strikeout position write8(out,8);// neoletters is a sans serif write8(out,3);// geometric face. /* panose font type */ write8(out,2);//Latin text write8(out,11);//normal sans serif write8(out,6);//medium weight write8(out,9);//monospaced write8(out,2);//no contrast write8(out,2);//no variation write8(out,0);//blahhhh write8(out,0);//blahhhh write8(out,0);//blahhhh write8(out,0);//blahhhh /*unicode range bits, set all on for now*/ write32(out,0xFFFFFFFF); write32(out,0xFFFFFFFF); write32(out,0xFFFFFFFF); write32(out,0xFFFFFFFF); /*vendor id*/ writestr(out,"OREN");// blah write16(out,0x1C0);//style bits write16(out,0x0020);//minmum character write16(out,0xFFFF);//last char write16(out,UPM*3/4);//ideogram ascension write16(out,-UPM/4);//ideogram descent write16(out,0);//line gap write16(out,UPM*3/4);//windows basic ascension write16(out,UPM/4);//windows basic descent /*code page range bits, set all on for now*/ write32(out,0x7FFFFFFF); write32(out,0xFFFFFFFF); write16(out,UPM/2);//x height write16(out,UPM*3/4);//cap height write16(out,0xFFFD);//character to use as replacement write16(out,0x0020);//character to use as space write16(out,1);//max context of ligatures unsigned os2len = ftell(out) - os2loc; finalizetable(out,os2ent,os2loc,os2len); printf("\e[3;1H\e[36;1m[OS/2]\e[0m"); /*write the post table*/ unsigned postloc = ftell(out); write32(out,0x00030000);//version 3.0 write32(out,0x00000000);//upright write16(out,0x0000);//underline? write16(out,0x0002);//thickness? write32(out,0x00000001);//font is monospace write32(out,0x00000000);//meomory usage unknown write32(out,0x00000000);//meomory usage unknown write32(out,0x00000000);//meomory usage unknown write32(out,0x00000000);//meomory usage unknown unsigned postlen = ftell(out) - postloc; finalizetable(out,postent,postloc,postlen); printf("\e[3;61H\e[36;1m[post]\e[0m"); /*write the name table*/ unsigned nameloc = ftell(out); FILE *strng = fopen("strng.temp","w+"); write16(out,0); write16(out,12);//number of name records write16(out,6+12*12);//offset to start of strings writenameent(out,strng,3,1,0x409,1,"\0n\0e\0o\0l\0e\0t\0t\0e\0r\0s",20); writenameent(out,strng,3,1,0x409,2,"\0R\0e\0g\0u\0l\0a\0r",14); writenameent(out,strng,3,1,0x409,3,"\0n\0e\0o\0l\0e\0t\0t\0e\0r\0s\0 \0R\0e\0g\0u\0l\0a\0r",36); writenameent(out,strng,3,1,0x409,4,"\0n\0e\0o\0l\0e\0t\0t\0e\0r\0s",20); writenameent(out,strng,3,1,0x409,5,"\0V\0e\0r\0s\0i\0o\0n\0 \0""1\0.\0""0",20); writenameent(out,strng,3,1,0x409,6,"\0n\0e\0o\0l\0e\0t\0t\0e\0r\0s",20); writenameent(out,strng,1,0,0,1,"neoletters",10); writenameent(out,strng,1,0,0,2,"Regular",7); writenameent(out,strng,1,0,0,3,"neoletters Regular",18); writenameent(out,strng,1,0,0,4,"neoletters",10); writenameent(out,strng,1,0,0,5,"Version 1.0",20); writenameent(out,strng,1,0,0,6,"neoletters",10); writefile(out,strng); unsigned namelen = ftell(out) - nameloc; finalizetable(out,nameent,nameloc,namelen); printf("\e[3;55H\e[36;1m[name]\e[0m"); unsigned localoc = ftell(out); write32(out,0); /* open ttf table files */ FILE *glyf = fopen("glyf.temp","w+"); FILE *hmtx = fopen("hmtx.temp","w+"); // write16(hmtx,9); // write16(hmtx,0); FILE *cmap12 = fopen("cmap12.temp","w+");// format 12 table int startccode = -1; int endccode = -1; int startglyfid = 0; int maxpoints = 0; int maxcontour = 0; int glyfid = 0; int ngroups = 0; int n2groups = 0;//number of groups below FFFF int ccode = -1; while(glyfid < fontinfo.nchars){ ccode++; while(ccode < 0x20000 && !font[ccode])ccode++; if(ccode >= 0x20000)break; struct bdfglyph g = *(font[ccode]); printf("\e[4;1HU%05x, %d \e[36;43m",ccode,glyfid); showbar(fontinfo.nchars,glyfid,30); printf("\e[0m"); //if(ccode != g.encoding)abort(); // width, height, x offset, y offset (of lower left corner) int bwidth = (g.bbx[0]+(g.bbx[0]%8?8-g.bbx[0]%8:0))/8; int bottom = 12 - g.bbx[3]; int top = bottom - g.bbx[1]; int lsb = g.bbx[2]; int j,i; //outputasbitmap(&g,5,1); /* create path map */ int xmin=20,xmax=0,ymin=16,ymax=0; for(i=0;i<=18;i++){ for(j=0;j<=16;j++){ pathmap[i+j*19]=bdfpthchk(g,i,j); if(pathmap[i+j*19] && pathmap[i+j*19] != 0xF){ if(i<xmin)xmin=i; if(i>xmax)xmax=i; if(j<ymin)ymin=j; if(j>ymax)ymax=j; } } } /* use map to find all paths */ pathend = 0; int n=0; for(i=0;i<=18;i++){ for(j=0;j<=16;j++){ if(pathmap[i+j*19] && pathmap[i+j*19] != 0xF){ addpath(i,j); n++; } } } if(n==0)goto outputloca; /* output paths into glyf */ write16(glyf,n);//number of contours write16(glyf,xmin);//xmin write16(glyf,12-ymax);//ymin write16(glyf,xmax);//xmax write16(glyf,12-ymin);//ymax printf("\e[6;1Hpaths: %d %d %d %d %d\n",n,xmin,12-ymax,xmax,12-ymin); for(i=1;i<pathend;i++){ if(pathlist[i].start==1)write16(glyf,i-1); } write16(glyf,pathend-1); write16(glyf,0);// zero bytes of code for(i=0;i<pathend;i++){ struct point p = pathlist[i]; int flags = 7; if(p.x == 0)flags ^= 022; ei(p.x > 0)flags |= 020; if(p.y == 0)flags ^= 044; ei(p.y > 0)flags |= 040; write8(glyf,flags); } for(i=0;i<pathend;i++){ if(pathlist[i].x!=0)write8(glyf,abs(pathlist[i].x)); } for(i=0;i<pathend;i++){ if(pathlist[i].y!=0)write8(glyf,abs(pathlist[i].y)); } if (0) {/*16 bit format*/ i = pathend; while(i > 0){ write8(glyf,0x9);// two bytes for each x and y if(i > 1 && i <= 256)write8(glyf,i-1),i=0; ei(i > 256)write8(glyf,255),i-=255; else i=0; } for(i=0;i<pathend;i++){ write16(glyf,(int)pathlist[i].x); } for(i=0;i<pathend;i++){ write16(glyf,(int)pathlist[i].y); } } if(pathend > maxpoints)maxpoints = pathend; if(n > maxcontour)maxcontour = n; //if(ftell(glyf)%2==1)write8(glyf,0x0);//filler outputloca: write32(out,ftell(glyf)); //check if we need to output a character range record if(startccode == -1 && ccode != 0){startccode=endccode=ccode;startglyfid=glyfid;} if(endccode < ccode-1){ if(endccode < 0x10000 && ccode > 0x10000)n2groups=ngroups +1; write32(cmap12,startccode); write32(cmap12,endccode); write32(cmap12,startglyfid); startccode = endccode = ccode; startglyfid = glyfid; ngroups++; }else endccode=ccode; //output hmtx if(ccode == 0){ write16(hmtx,9); } else { int w = u8chrwidn(ccode); write16(hmtx,9*w); } write16(hmtx,xmin==20?0:xmin); printf("\e[4;1HU%05x, %d",ccode,glyfid); glyfid++; } // write32(out,ftell(glyf)); //final group write32(cmap12,startccode); write32(cmap12,endccode); write32(cmap12,startglyfid); ngroups++; unsigned localen = ftell(out) - localoc; finalizetable(out,locaent,localoc,localen); printf("\e[3;43H\e[36;1m[loca]\e[0m"); unsigned hmtxloc = ftell(out); writefile(out,hmtx); unsigned hmtxlen = ftell(out) - hmtxloc; finalizetable(out,hmtxent,hmtxloc,hmtxlen); printf("\e[3;37H\e[36;1m[hmtx]\e[0m"); unsigned cmaploc = ftell(out); write16(out,0); write16(out,2);//1 subtables write16(out,3);//platform 3 windows write16(out,1);//code 1 unicode BMP write32(out,20);//offset write16(out,3);//platform 3 windows write16(out,10);//code 10 unicode write32(out,0);//offset write16(out,4);//subtable format 4 unsigned nranges = n2groups + 1; write16(out,nranges*8 + 16);//length write16(out,0);//language (not used) write16(out,nranges*2); unsigned searchrange=2; unsigned selector = 0; while(searchrange<=nranges)searchrange*=2,selector++; write16(out,searchrange); write16(out,selector); write16(out,2*nranges - searchrange); int i; for(i=0;i<n2groups;i++){ goloc(cmap12,12*i+4); write16(out,read32(cmap12)); } write16(out,0xFFFF); write16(out,0); for(i=0;i<n2groups;i++){ goloc(cmap12,12*i); write16(out,read32(cmap12)); } write16(out,0xFFFF); for(i=0;i<n2groups;i++){ goloc(cmap12,12*i); unsigned short x = read32(cmap12); read32(cmap12); x = read32(cmap12) - x; write16(out,x); } write16(out,1); for(i=0;i<n2groups;i++){ write16(out,0); } write16(out,0); unsigned cmap12loc = ftell(out); write16(out,12);//subtable format 12 write16(out,0);//reserved 0 write32(out,ngroups*12 + 16);//length write32(out,0);//language (not used) write32(out,ngroups);//number of groups writefile(out,cmap12); goloc(out,cmaploc+16); write32(out,cmap12loc-cmaploc); ffastfw(out); unsigned cmaplen = ftell(out) - cmaploc; finalizetable(out,cmapent,cmaploc,cmaplen); printf("\e[3;7H\e[36;1m[cmap]\e[0m"); unsigned glyfloc = ftell(out); writefile(out,glyf); unsigned glyflen = ftell(out) - glyfloc; finalizetable(out,glyfent,glyfloc,glyflen); printf("\e[3;19H\e[36;1m[glyf]\e[0m"); unsigned maxploc = ftell(out); write32(out,0x00010000); write16(out,glyfid);//number of glyphs write16(out,maxpoints); write16(out,maxcontour); write16(out,maxpoints); write16(out,maxcontour); write16(out,1);//program maxima write16(out,0); write16(out,0); write16(out,0); write16(out,0); write16(out,0); write16(out,0); write16(out,0); write16(out,0); unsigned maxplen = ftell(out) - maxploc; finalizetable(out,maxpent,maxploc,maxplen); printf("\e[3;49H\e[36;1m[maxp]\e[0m"); printf("\e[7;1H...computing final checksum..."); uint32_t sum = 0; unsigned len = ftell(out); goloc(out,0); for(i=0;i<len;i++)sum += read32(out); goloc(out,headloc + 8); write32(out,sum); printf("\e[3;25H\e[36;1m[head]\e[0m\e[8;1HFinished!\n"); return 0; } struct point p0; void addpath(int x,int y){ int dir; int i = pathend; char map = pathmap[x+y*19]; printf("\e[5;1H\e[2Kstart at %d,%d:",x,y); if(i==0){ pathlist[i] = (struct point){x,12-y,1}; p0 = (struct point){x,12-y,1}; }else{ pathlist[i] = (struct point){x-p0.x,12-y-p0.y,1}; p0 = (struct point){x,12-y,1}; } if(map == 8){dir = 'R';pathmap[x+y*19]=0;} if(map == 7){dir = 'D';pathmap[x+y*19]=0;} i++; pathlist[i]=(struct point){0,0,0}; nextpoint:; putchar(dir); fflush(stdout); int olddir = dir; if(dir == 'R'){ x++; pathlist[i].x++; char map = pathmap[x+y*19]; if(map == 4){dir = 'D';pathmap[x+y*19]=0;} ei(map == 6){dir = 'D';pathmap[x+y*19]=2;} ei(map == 12){dir = 'R';pathmap[x+y*19]=0;} ei(map == 14){dir = 'U';pathmap[x+y*19]=0;} else goto endof; }ei(dir == 'D'){ y++; pathlist[i].y--; char map = pathmap[x+y*19]; if(map == 1){dir = 'L';pathmap[x+y*19]=0;} ei(map == 5){dir = 'D';pathmap[x+y*19]=0;} ei(map == 9){dir = 'L';pathmap[x+y*19]=8;} ei(map == 13){dir = 'R';pathmap[x+y*19]=0;} else goto endof; }ei(dir == 'L'){ x--; pathlist[i].x--; char map = pathmap[x+y*19]; if(map == 2){dir = 'U';pathmap[x+y*19]=0;} ei(map == 3){dir = 'L';pathmap[x+y*19]=0;} ei(map == 6){dir = 'U';pathmap[x+y*19]=4;} ei(map == 7){dir = 'D';pathmap[x+y*19]=0;} else goto endof; }ei(dir == 'U'){ y--; pathlist[i].y++; char map = pathmap[x+y*19]; if(map == 8){dir = 'R';pathmap[x+y*19]=0;} ei(map == 9){dir = 'R';pathmap[x+y*19]=1;} ei(map == 10){dir = 'U';pathmap[x+y*19]=0;} ei(map == 11){dir = 'L';pathmap[x+y*19]=0;} else goto endof; } if(dir != olddir){ p0.x += pathlist[i].x; p0.y += pathlist[i].y; i++; pathlist[i]=(struct point){0,0,0}; } goto nextpoint; endof:; printf(" end at %d,%d\n",p0.x,p0.y); pathend = i; // the last segment is not included. } int bdfpixchk(struct bdfglyph g,int x,int y){ if(x<0||y<0||x>17||y>15)return 0; return!!(g.bitmap[y]&(0x20000>>x)); } int bdfpthchk(struct bdfglyph g,int x,int y){ return bdfpixchk(g,x-1,y-1) + 2*bdfpixchk(g,x,y-1) + 4*bdfpixchk(g,x-1,y) + 8*bdfpixchk(g,x,y); }