Well, i'll just publish my source code here, i used it to fix russian fonts about 10 years ago.
That program can be started as:
prog.exe font.fnt
it shows all the letters raster in text mode (each point is a number).
Program is most likely useless, except the source code to read and parse the whole .fnt-file
You can make something useful based on it.
Here's it:
// fontwar2.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include<stdio.h>
#include<windows.h>
#define MAX_LEETER_NUM 256
void bmp2fnt();
void cp2win(char *,int,int);
int getletter(char *,unsigned,char *);
typedef struct _FontHeader {
DWORD Name; // Always is "FONT"
BYTE LowIndex; // Index of first letter in file
BYTE HighIndex; // Index of the last letter in file
BYTE MaxWidth; // Maximum width
BYTE MaxHeight; // Maximum height
DWORD Unk1; // Unknown / Unused
} FontHeader;
typedef struct _FontLetterRaw {
BYTE Width; // Width of the letter
BYTE Height; // Height of the letter
BYTE XOffset; // X Offset for the topleft corner of the letter.
BYTE YOffset; // Y Offset for the topleft corner of the letter.
} FontLetterRaw;
//DWORD letterofs[MAX_LEETER_NUM];
//FontHeader fontheader;
//FontLetterRaw letterheader;
int main(int argc, char* argv[])
{
/* FILE *in;
int i,pixelcounter,toskip;
BYTE c;
if(argc<2){printf("Usage: fontwar2 <filename.fnt> [-w]\n");return 0;}
in=fopen(argv[1],"rb");
if(!in){printf("Data error reading file %s\n",argv[1]);return 1;}
if(!fread(&fontheader,sizeof(FontHeader),1,in)){printf("Error in %s\n",argv[1]);return 2;}
printf("ok: %d, %d, %d, %d",fontheader.LowIndex,fontheader.HighIndex,fontheader.MaxWidth,fontheader.MaxHeight);
for(i=fontheader.LowIndex;i<fontheader.HighIndex;i++)
{
if(i>=MAX_LEETER_NUM){printf("Error! too many letters\n");return 3;}
fread(&letterofs[i],4,1,in);
// printf("%d ",letterofs[i]);
}
printf("\n");
for(i=fontheader.LowIndex;i<fontheader.HighIndex;i++)
{
if(letterofs[i]==0){printf("skip\n");continue;}
fseek(in,letterofs[i],SEEK_SET);
fread(&letterheader,sizeof(FontLetterRaw),1,in);
printf("%d %d^\n",letterheader.Width,letterheader.Height);
toskip=0;
printf("Begin %d\n",i+1);
for(pixelcounter=0;pixelcounter<letterheader.Width*letterheader.Height;pixelcounter++)
{
if(toskip-->0)
{
printf("-");
}
else{
if(pixelcounter)printf("%d",c&7);
c=fgetc(in);
toskip=c>>3;
}
if(pixelcounter%letterheader.Width==0)printf("\n");
}
printf("%d\n",c&7);
printf("End\n");
}
printf("!%d!\n",ftell(in));
fclose(in);
// bmp2fnt();
if(argc>2&&strcmp(argv[2],"-w")==0)cp2win(argv[1],fontheader.LowIndex,fontheader.HighIndex);*/
char buf[1024]; // FIXME! insecure
// if(argc<4){printf("Usage: fontwar2 <source1.fnt> <source2.fnt> <target.fnt>\n");return 0;}
int outfnt[32768]; // FIXME! insecure
int outfnt_seek=0,letsize;
char header[]={'F','O','N','T',0x20,0xff,0x0e,0x0e};
FontHeader outfh;
outfh.LowIndex=header[4];
outfh.HighIndex=header[5];
outfh.MaxWidth=header[6];
outfh.MaxHeight=header[7];
memset(outfnt,0,sizeof(outfnt));
memcpy(outfnt,header,sizeof(header));
outfnt_seek=(outfh.HighIndex+1-outfh.LowIndex)*4+sizeof(header);
if(argc==2)
{
for(int i=outfh.LowIndex;i<=outfh.HighIndex;i++)
getletter(argv[1],i,(char *)outfnt+outfnt_seek);
return 0;
}
for(int i=outfh.LowIndex;i<=outfh.HighIndex;i++)
{
switch(i)
{
case 128:letsize=getletter(argv[2],'З',(char *)outfnt+outfnt_seek);break;
case 129:letsize=getletter(argv[2],'ь',(char *)outfnt+outfnt_seek);break;
case 130:letsize=getletter(argv[2],'й',(char *)outfnt+outfnt_seek);break;
case 131:letsize=getletter(argv[2],'в',(char *)outfnt+outfnt_seek);break;
case 132:letsize=getletter(argv[2],'д',(char *)outfnt+outfnt_seek);break;
case 133:letsize=getletter(argv[2],'а',(char *)outfnt+outfnt_seek);break;
case 134:letsize=getletter(argv[2],'е',(char *)outfnt+outfnt_seek);break;
case 135:letsize=getletter(argv[2],'з',(char *)outfnt+outfnt_seek);break;
case 136:letsize=getletter(argv[2],'к',(char *)outfnt+outfnt_seek);break;
case 137:letsize=getletter(argv[2],'л',(char *)outfnt+outfnt_seek);break;
case 138:letsize=getletter(argv[2],'и',(char *)outfnt+outfnt_seek);break;
case 139:letsize=getletter(argv[2],'п',(char *)outfnt+outfnt_seek);break;
case 140:letsize=getletter(argv[2],'о',(char *)outfnt+outfnt_seek);break;
case 141:letsize=getletter(argv[2],'м',(char *)outfnt+outfnt_seek);break;
case 142:letsize=getletter(argv[2],'Д',(char *)outfnt+outfnt_seek);break;
case 143:letsize=getletter(argv[2],'Е',(char *)outfnt+outfnt_seek);break;
case 144:letsize=getletter(argv[2],'Й',(char *)outfnt+outfnt_seek);break;
case 145:letsize=getletter(argv[2],'ж',(char *)outfnt+outfnt_seek);break;
case 146:letsize=getletter(argv[2],'Ж',(char *)outfnt+outfnt_seek);break;
case 147:letsize=getletter(argv[2],'ф',(char *)outfnt+outfnt_seek);break;
case 148:letsize=getletter(argv[2],'ц',(char *)outfnt+outfnt_seek);break;
case 149:letsize=getletter(argv[2],'т',(char *)outfnt+outfnt_seek);break;
case 150:letsize=getletter(argv[2],'ы',(char *)outfnt+outfnt_seek);break;
case 151:letsize=getletter(argv[2],'щ',(char *)outfnt+outfnt_seek);break;
case 152:letsize=getletter(argv[2],'я',(char *)outfnt+outfnt_seek);break;
case 153:letsize=getletter(argv[2],'Ц',(char *)outfnt+outfnt_seek);break;
case 154:letsize=getletter(argv[2],'Ь',(char *)outfnt+outfnt_seek);break;
case 155:letsize=getletter(argv[2],'ш',(char *)outfnt+outfnt_seek);break;
// case 156:letsize=getletter(argv[2],'Ь',(char *)outfnt+outfnt_seek);break;
case 157:letsize=getletter(argv[2],'Ш',(char *)outfnt+outfnt_seek);break;
case 158:letsize=getletter(argv[2],'Ч',(char *)outfnt+outfnt_seek);break;
// case 159:letsize=getletter(argv[2],'Я',(char *)outfnt+outfnt_seek);break;
case 160:letsize=getletter(argv[2],'б',(char *)outfnt+outfnt_seek);break;
case 161:letsize=getletter(argv[2],'н',(char *)outfnt+outfnt_seek);break;
case 162:letsize=getletter(argv[2],'у',(char *)outfnt+outfnt_seek);break;
case 163:letsize=getletter(argv[2],'ъ',(char *)outfnt+outfnt_seek);break;
case 164:letsize=getletter(argv[2],'с',(char *)outfnt+outfnt_seek);break;
case 165:letsize=getletter(argv[2],'С',(char *)outfnt+outfnt_seek);break;
case 181:letsize=getletter(argv[2],'Б',(char *)outfnt+outfnt_seek);break;
case 182:letsize=getletter(argv[2],'В',(char *)outfnt+outfnt_seek);break;
case 183:letsize=getletter(argv[2],'А',(char *)outfnt+outfnt_seek);break;
case 198:letsize=getletter(argv[2],'г',(char *)outfnt+outfnt_seek);break;
case 199:letsize=getletter(argv[2],'Г',(char *)outfnt+outfnt_seek);break;
case 208:letsize=getletter(argv[2],'р',(char *)outfnt+outfnt_seek);break;
case 209:letsize=getletter(argv[2],'Р',(char *)outfnt+outfnt_seek);break;
case 210:letsize=getletter(argv[2],'К',(char *)outfnt+outfnt_seek);break;
case 211:letsize=getletter(argv[2],'Л',(char *)outfnt+outfnt_seek);break;
case 212:letsize=getletter(argv[2],'И',(char *)outfnt+outfnt_seek);break;
case 214:letsize=getletter(argv[2],'Н',(char *)outfnt+outfnt_seek);break;
case 215:letsize=getletter(argv[2],'О',(char *)outfnt+outfnt_seek);break;
case 216:letsize=getletter(argv[2],'П',(char *)outfnt+outfnt_seek);break;
case 222:letsize=getletter(argv[2],'М',(char *)outfnt+outfnt_seek);break;
case 224:letsize=getletter(argv[2],'У',(char *)outfnt+outfnt_seek);break;
case 225:letsize=getletter(argv[2],'Я',(char *)outfnt+outfnt_seek);break;
case 226:letsize=getletter(argv[2],'Ф',(char *)outfnt+outfnt_seek);break;
case 227:letsize=getletter(argv[2],'Т',(char *)outfnt+outfnt_seek);break;
case 228:letsize=getletter(argv[2],'х',(char *)outfnt+outfnt_seek);break;
case 229:letsize=getletter(argv[2],'Х',(char *)outfnt+outfnt_seek);break;
case 231:letsize=getletter(argv[2],'ю',(char *)outfnt+outfnt_seek);break;
case 232:letsize=getletter(argv[2],'Ю',(char *)outfnt+outfnt_seek);break;
case 233:letsize=getletter(argv[2],'Ъ',(char *)outfnt+outfnt_seek);break;
case 234:letsize=getletter(argv[2],'Ы',(char *)outfnt+outfnt_seek);break;
case 235:letsize=getletter(argv[2],'Щ',(char *)outfnt+outfnt_seek);break;
case 236:letsize=getletter(argv[2],'э',(char *)outfnt+outfnt_seek);break;
case 237:letsize=getletter(argv[2],'Э',(char *)outfnt+outfnt_seek);break;
case 246:letsize=getletter(argv[2],'ч',(char *)outfnt+outfnt_seek);break;
default:
if(i<128)letsize=getletter(argv[2],i,(char *)outfnt+outfnt_seek);
else letsize=getletter(argv[1],i,(char *)outfnt+outfnt_seek);
}
printf("len: %d\twriting %x\t",letsize,letsize?outfnt_seek:0);
outfnt[i-outfh.LowIndex+sizeof(header)/4]=letsize?outfnt_seek:0;
outfnt_seek+=letsize;
}
// int i=getletter(argv[1],247,buf);
// printf("len: %d\n",i);
FILE *out=fopen(argv[3],"wb");
if(!out){printf("!out");return 1;}
if(!fwrite(outfnt,outfnt_seek,1,out))printf("Error writing %s\n",argv[3]);
printf("!%x!",getletter(argv[1],33,(char *)outfnt));
return 0;
}
int getletter(char *filename,unsigned letnum,char *buf)
{
FILE *in;
FontHeader fh;
FontLetterRaw flr;
int pixelcounter;
int ofs=0,toskip=0,in_ofs;
char c;
in=fopen(filename,"rb");
letnum=(letnum+256)%256;
printf ("let:%d:num\t",letnum);
if(!in){printf("Data error reading file %s\n",filename);return 1;}
if(!fread(&fh,sizeof(FontHeader),1,in)){printf("Error in %s\n",filename);return 2;}
if(letnum<=fh.LowIndex||letnum>fh.HighIndex)return 0;
fseek(in,8+(letnum-fh.LowIndex)*4,SEEK_SET);
if(!fread(&in_ofs,4,1,in)){printf("Error in %s\n",filename);return 2;}
//printf("letofs: %X\n",in_ofs);
if(in_ofs==0)return 0;
fseek(in,in_ofs,SEEK_SET);
if(!fread(&flr,sizeof(FontLetterRaw),1,in)){printf("Error in %s\n",filename);return 2;}
memcpy(buf+ofs,&flr,sizeof(flr));
ofs+=sizeof(flr);
for(pixelcounter=0;pixelcounter<flr.Width*flr.Height;pixelcounter++)
{
if(toskip-->0)
{
printf("-");
}
else{
if(pixelcounter)printf("%d",c&7);
c=fgetc(in);
toskip=c>>3;
buf[ofs++]=c;
}
if(pixelcounter%flr.Width==0)printf("\n");
}
printf("%d\n",c&7);
return ofs;
}
/*void cp2win(char *fntfilename,int low,int high)
{
DWORD cp[256];
DWORD win[256];
FILE *fnt;
fnt=fopen(fntfilename,"r+b");
if(!fnt){printf("!fnt\n");return;}
fseek(fnt,12,SEEK_SET);
memset(cp,0,sizeof(cp));
memset(win,0,sizeof(win));
if(fread(cp+low,4,high-low,fnt)!=(unsigned)(high-low)){printf("!fread\n");return;}
//for(int i=low;i<high;i++)printf("%4X ",cp[i]);
for(int i=low;i<high;i++)
{
// if(i>=0x80-1&&i<0xb0-1)win[i]=cp[i+0x40];
// else if(i>=0xc0-1&&i<0xf0-1)win[i]=cp[i-0x40];
// else if(i>=0xb0-1&&i<0xc0-1)win[i]=cp[i+0x40];
// else if(i>=0xf0-1&&i<0x100-1)win[i]=cp[i-0x10];
// if(i==128)win[i]=cp[129];
// else
// win[i]=cp[i];
// switch(i)
// {
// case "└":win[]=cp[i];
// }
}
fseek(fnt,12,SEEK_SET);
if(fwrite(win+low,4,high-low,fnt)!=(unsigned)(high-low)){printf("!fwrite\n");return;}
printf("font file written successfully\n");
fclose(fnt);
}
/*void bmp2fnt()
{
BYTE fnt[65536];
BYTE buf[16][16];
int fnt_len=0;
int width=14,bmp_width=16,height=14,letternum=239-32;
int i,j,k,len,seek,c,toskip=0;
FILE *in=fopen("game.bmp","rb");
if(!in){printf("!in");return;}
FILE *out=fopen("out.fnt","wb");
if(!out){printf("!out");return;}
fseek(in,0,2);
len=ftell(in);
memcpy(fnt+fnt_len,&fontheader,sizeof(FontHeader));
fnt_len+=sizeof(FontHeader);
fnt_len+=letternum*4;
for(k=0;k<letternum;k++)
{
seek=len-k*bmp_width*height;
for(j=0;j<height;j++)
for(i=0;i<bmp_width;i++)
{
seek--;
if((len-seek)%16==1||(len-seek)%16==2)continue;
fseek(in,seek,0);
buf[bmp_width-1-i][j]=fgetc(in);
}
for(j=0;j<height;j++)
{
for(i=0;i<width;i++)
printf("%2x",buf[i][j]);
printf("\n");
}
}
}
*/