Oh boy, this is a mess.

This commit is contained in:
Marisa the Magician 2022-09-22 20:44:00 +02:00
commit 5ff8bd2367

123
mkfont.c
View file

@ -49,10 +49,13 @@
uint8_t pal[768]; uint8_t pal[768];
int palsize = 0; int palsize = 0;
int xupshift = 0;
int rightshift = 0;
int bordshift = 0; int bordshift = 0;
int tewi_hotfix = 0; // U+0309 and U+030A glyphs are offset incorrectly
// and the entire font height needs to be cropped
int miniwi_hotfix = 0; // U+01C2 glyph is offset incorrect
// this font's height also needs a crop
uint32_t endianswap( uint32_t n ) uint32_t endianswap( uint32_t n )
{ {
// if we're in a big endian system, we don't need this // if we're in a big endian system, we don't need this
@ -94,9 +97,9 @@ int writepng( const char *filename, uint8_t *fdata, int w, int h, int p )
png_set_IHDR(pngp,infp,w,h,8,palsize?PNG_COLOR_TYPE_RGBA:PNG_COLOR_TYPE_GA, png_set_IHDR(pngp,infp,w,h,8,palsize?PNG_COLOR_TYPE_RGBA:PNG_COLOR_TYPE_GA,
PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_DEFAULT, PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT); PNG_FILTER_TYPE_DEFAULT);
if ( xupshift || rightshift || bordshift ) if ( bordshift )
{ {
uint32_t grabs[2] = {endianswap(rightshift+bordshift),endianswap(xupshift+bordshift)}; uint32_t grabs[2] = {endianswap(bordshift),endianswap(bordshift)};
png_unknown_chunk grab = png_unknown_chunk grab =
{ {
.name = "grAb", .name = "grAb",
@ -118,10 +121,10 @@ FT_Library ftlib;
FT_Face fnt; FT_Face fnt;
int iw, ih; int iw, ih;
int w, h, pxsiz, datsiz; int w, h, datsiz;
uint8_t *idata; uint8_t *idata;
int autosize = 0; int calcsize = 1;
int gradient = 0; int gradient = 0;
int upshift = 0; int upshift = 0;
@ -191,9 +194,9 @@ int draw_glyph( FT_Bitmap *bmp, uint8_t v, int px, int py, int ox, int oy )
if ( v == 255 ) if ( v == 255 )
{ {
float a; float a;
int ofs = j+oy+(upshift+1); int ofs = j+oy+(upshift+tewi_hotfix+miniwi_hotfix);
if ( ofs < 0 ) a = 0.; if ( ofs < 0 ) a = 0.;
else a = ofs/(float)(h+upshift+1); else a = ofs/(float)(h-1);
if ( (gradient&3) == 1 ) rv = lerpg(1.-a); if ( (gradient&3) == 1 ) rv = lerpg(1.-a);
else if ( (gradient&3) == 2 ) rv = lerpg(a); else if ( (gradient&3) == 2 ) rv = lerpg(a);
else if ( (gradient&3) == 3 ) rv = lerpg((a>.5)?((1.-a)*2.):(a*2.)); else if ( (gradient&3) == 3 ) rv = lerpg((a>.5)?((1.-a)*2.):(a*2.));
@ -343,10 +346,10 @@ const char grads[8][20] =
int main( int argc, char **argv ) int main( int argc, char **argv )
{ {
if ( argc < 4 ) if ( argc < 3 )
{ {
fprintf(stderr,"usage: mkfontsingle <font name> <pxsize> <wxh|auto>" fprintf(stderr,"usage: mkfont <font name> <pxsize> <unicode range (hex)>"
" <unicode range (hex)> [gradient type] [color palette] [-palinv]\n"); " [gradient type] [color palette] [-palinv]\n");
return 1; return 1;
} }
if ( FT_Init_FreeType(&ftlib) ) if ( FT_Init_FreeType(&ftlib) )
@ -355,18 +358,20 @@ int main( int argc, char **argv )
return 2; return 2;
} }
uint32_t range[2] = {0x0000,0x00FF}; uint32_t range[2] = {0x0000,0x00FF};
int pxsiz;
sscanf(argv[2],"%d",&pxsiz); sscanf(argv[2],"%d",&pxsiz);
if ( !strcmp(argv[3],"auto") ) autosize = 1; sscanf(argv[3],"%x-%x",&range[0],&range[1]);
else sscanf(argv[3],"%dx%d",&w,&h); if ( argc > 4 ) sscanf(argv[4],"%d",&gradient);
sscanf(argv[4],"%x-%x",&range[0],&range[1]); if ( argc > 6 ) palinv = !strcmp(argv[6],"-palinv");
if ( argc > 5 ) sscanf(argv[5],"%d",&gradient); if ( argc > 5 ) loadpalette(argv[5]);
if ( argc > 7 ) palinv = !strcmp(argv[7],"-palinv");
if ( argc > 6 ) loadpalette(argv[6]);
if ( FT_New_Face(ftlib,argv[1],0,&fnt) ) if ( FT_New_Face(ftlib,argv[1],0,&fnt) )
{ {
fprintf(stderr,"error: failed to open font '%s'\n",argv[1]); fprintf(stderr,"error: failed to open font '%s'\n",argv[1]);
return 4; return 4;
} }
fprintf(stderr,"info: loaded font \'%s %s\'.\n",fnt->family_name,fnt->style_name);
if ( !strcmp(fnt->family_name,"tewi") ) tewi_hotfix = 1;
else if ( !strcmp(fnt->family_name,"miniwi") ) miniwi_hotfix = 1;
if ( FT_Set_Pixel_Sizes(fnt,0,pxsiz) ) if ( FT_Set_Pixel_Sizes(fnt,0,pxsiz) )
{ {
if ( fnt->num_fixed_sizes <= 0 ) if ( fnt->num_fixed_sizes <= 0 )
@ -391,10 +396,11 @@ int main( int argc, char **argv )
return 8; return 8;
} }
} }
h = (fnt->size->metrics.height>>6)-tewi_hotfix-miniwi_hotfix;
FT_Select_Charmap(fnt,FT_ENCODING_UNICODE); FT_Select_Charmap(fnt,FT_ENCODING_UNICODE);
// first pass to compute baseline upshift // first pass to compute baseline upshift
upshift = 65535; upshift = 65535;
for ( uint32_t i=range[0]; i<=range[1]; i++ ) for ( uint32_t i=0; i<=0xFFFF; i++ )
{ {
FT_UInt glyph = FT_Get_Char_Index(fnt,i); FT_UInt glyph = FT_Get_Char_Index(fnt,i);
if ( !glyph || FT_Load_Glyph(fnt,glyph,LOADFLAGS) ) continue; if ( !glyph || FT_Load_Glyph(fnt,glyph,LOADFLAGS) ) continue;
@ -407,48 +413,13 @@ int main( int argc, char **argv )
if ( gshift < upshift ) upshift = gshift; if ( gshift < upshift ) upshift = gshift;
} }
fprintf(stderr,"info: estimated baseline upshift is %d.\n",upshift); fprintf(stderr,"info: estimated baseline upshift is %d.\n",upshift);
// second pass to compute "real" upshift, which is used for the grAb Y offset // second pass to compute the maximum cell size (for memory allocation)
// as well as the "rightshift" for the X offset if ( calcsize )
xupshift = 65535;
for ( uint32_t i=range[0]; i<=range[1]; i++ )
{ {
FT_UInt glyph = FT_Get_Char_Index(fnt,i);
if ( !glyph || FT_Load_Glyph(fnt,glyph,LOADFLAGS) ) continue;
FT_Render_Glyph(fnt->glyph,RENDERMODE);
int valid = 0;
for ( unsigned j=0; j<fnt->glyph->bitmap.rows; j++ )
valid |= valid_row(&fnt->glyph->bitmap,j);
if ( !valid ) continue;
int xx = fnt->glyph->bitmap_left;
if ( -xx > rightshift ) rightshift = -xx;
int yy = upshift+1+(pxsiz-fnt->glyph->bitmap_top);
for ( unsigned j=0; j<fnt->glyph->bitmap.rows; j++ )
{
if ( !valid_row(&fnt->glyph->bitmap,j) ) yy++;
else break;
}
if ( yy < 0 )
{
int xup = -yy;
if ( xup < xupshift ) xupshift = xup;
}
}
if ( xupshift == 65535 ) xupshift = 0;
if ( xupshift )
{
fprintf(stderr,"info: real upshift is %d.\n",upshift+xupshift);
fprintf(stderr,"info: grAb Y offset %d will be used.\n",xupshift);
}
if ( rightshift )
fprintf(stderr,"info: right shift detected, grAb X offset %d will be used.\n",rightshift);
// third pass to compute the maximum cell size (for memory allocation)
if ( autosize )
{
h = (fnt->size->metrics.height>>6)+1;
if ( FT_IS_FIXED_WIDTH(fnt) ) if ( FT_IS_FIXED_WIDTH(fnt) )
{ {
w = fnt->size->metrics.max_advance>>6; w = fnt->size->metrics.max_advance>>6;
autosize = 0; // don't readjust per-glyph calcsize = 0; // don't readjust per-glyph
} }
else for ( uint32_t i=range[0]; i<=range[1]; i++ ) else for ( uint32_t i=range[0]; i<=range[1]; i++ )
{ {
@ -457,8 +428,8 @@ int main( int argc, char **argv )
FT_Render_Glyph(fnt->glyph,RENDERMODE); FT_Render_Glyph(fnt->glyph,RENDERMODE);
int adv = fnt->glyph->linearHoriAdvance>>16; int adv = fnt->glyph->linearHoriAdvance>>16;
int adv2 = fnt->glyph->advance.x>>6; int adv2 = fnt->glyph->advance.x>>6;
if ( !adv ) adv = adv2; if ( adv2 ) adv = adv2;
if ( (adv+rightshift) > w ) w = adv+rightshift; if ( adv > w ) w = adv;
} }
fprintf(stderr,"info: max cell size is %dx%d.\n",w,h); fprintf(stderr,"info: max cell size is %dx%d.\n",w,h);
} }
@ -483,37 +454,41 @@ int main( int argc, char **argv )
for ( unsigned j=0; j<fnt->glyph->bitmap.rows; j++ ) for ( unsigned j=0; j<fnt->glyph->bitmap.rows; j++ )
valid |= valid_row(&fnt->glyph->bitmap,j); valid |= valid_row(&fnt->glyph->bitmap,j);
if ( !valid ) continue; if ( !valid ) continue;
if ( autosize ) if ( calcsize )
{ {
// readjust cell width (but not height) for this character // readjust cell width (but not height) for this character
int adv = fnt->glyph->linearHoriAdvance>>16; int adv = fnt->glyph->linearHoriAdvance>>16;
int adv2 = fnt->glyph->advance.x>>6; int adv2 = fnt->glyph->advance.x>>6;
if ( !adv ) adv = adv2; if ( adv2 ) adv = adv2;
w = adv+rightshift; w = adv;
iw = w+((gradient&4)?2:1); iw = w+((gradient&4)?2:1);
} }
int xx = rightshift; int xx = 0;
int yy = upshift+xupshift+1; int yy = upshift+tewi_hotfix+miniwi_hotfix;
if ( tewi_hotfix && ((i != 0x0309) && (i != 0x030A)) )
fnt->glyph->bitmap_top++;
if ( miniwi_hotfix && (i == 0x01C2) )
fnt->glyph->bitmap_top++;
valid = 0; valid = 0;
oob = 0; oob = 0;
if ( gradient&4 ) if ( gradient&4 )
{ {
// draw outline first // draw outline first
draw_glyph(&fnt->glyph->bitmap,0,xx,yy,fnt->glyph->bitmap_left,pxsiz-fnt->glyph->bitmap_top); draw_glyph(&fnt->glyph->bitmap,0,xx,yy,fnt->glyph->bitmap_left,h-fnt->glyph->bitmap_top);
draw_glyph(&fnt->glyph->bitmap,0,xx+1,yy,fnt->glyph->bitmap_left,pxsiz-fnt->glyph->bitmap_top); draw_glyph(&fnt->glyph->bitmap,0,xx+1,yy,fnt->glyph->bitmap_left,h-fnt->glyph->bitmap_top);
draw_glyph(&fnt->glyph->bitmap,0,xx+2,yy,fnt->glyph->bitmap_left,pxsiz-fnt->glyph->bitmap_top); draw_glyph(&fnt->glyph->bitmap,0,xx+2,yy,fnt->glyph->bitmap_left,h-fnt->glyph->bitmap_top);
draw_glyph(&fnt->glyph->bitmap,0,xx,yy+1,fnt->glyph->bitmap_left,pxsiz-fnt->glyph->bitmap_top); draw_glyph(&fnt->glyph->bitmap,0,xx,yy+1,fnt->glyph->bitmap_left,h-fnt->glyph->bitmap_top);
draw_glyph(&fnt->glyph->bitmap,0,xx+2,yy+1,fnt->glyph->bitmap_left,pxsiz-fnt->glyph->bitmap_top); draw_glyph(&fnt->glyph->bitmap,0,xx+2,yy+1,fnt->glyph->bitmap_left,h-fnt->glyph->bitmap_top);
draw_glyph(&fnt->glyph->bitmap,0,xx,yy+2,fnt->glyph->bitmap_left,pxsiz-fnt->glyph->bitmap_top); draw_glyph(&fnt->glyph->bitmap,0,xx,yy+2,fnt->glyph->bitmap_left,h-fnt->glyph->bitmap_top);
draw_glyph(&fnt->glyph->bitmap,0,xx+1,yy+2,fnt->glyph->bitmap_left,pxsiz-fnt->glyph->bitmap_top); draw_glyph(&fnt->glyph->bitmap,0,xx+1,yy+2,fnt->glyph->bitmap_left,h-fnt->glyph->bitmap_top);
draw_glyph(&fnt->glyph->bitmap,0,xx+2,yy+2,fnt->glyph->bitmap_left,pxsiz-fnt->glyph->bitmap_top); draw_glyph(&fnt->glyph->bitmap,0,xx+2,yy+2,fnt->glyph->bitmap_left,h-fnt->glyph->bitmap_top);
valid = draw_glyph(&fnt->glyph->bitmap,255,xx+1,yy+1,fnt->glyph->bitmap_left,pxsiz-fnt->glyph->bitmap_top); valid = draw_glyph(&fnt->glyph->bitmap,255,xx+1,yy+1,fnt->glyph->bitmap_left,h-fnt->glyph->bitmap_top);
} }
else else
{ {
// draw drop shadow first // draw drop shadow first
draw_glyph(&fnt->glyph->bitmap,0,xx+1,yy+1,fnt->glyph->bitmap_left,pxsiz-fnt->glyph->bitmap_top); draw_glyph(&fnt->glyph->bitmap,0,xx+1,yy+1,fnt->glyph->bitmap_left,h-fnt->glyph->bitmap_top);
valid = draw_glyph(&fnt->glyph->bitmap,255,xx,yy,fnt->glyph->bitmap_left,pxsiz-fnt->glyph->bitmap_top); valid = draw_glyph(&fnt->glyph->bitmap,255,xx,yy,fnt->glyph->bitmap_left,h-fnt->glyph->bitmap_top);
} }
if ( valid ) if ( valid )
{ {