Introduction
This font tool allows easy and quick conversion of bitmap representations of those fonts to a re-usable and generally compatible format to be used by programmers. It also has a preview feature to look at already converted .FNT files that you might get or download somewhere else.
With Version 1.1 is also included a new .FNT file editor to create new or modify existing fonts as needed.
With Version 1.2 font files without a header that contains the character width/height and count information are supported for previewing and editing.
With Version 1.3 the Font Editor was enhanced. The Control sizing for smaller screen resolutions in particular. When you load a font into the editor, font properties like character size are now displayed. As real new feature was introduced the ability to copy the layout of a character and paste it into a new one. The content of the current clipboard is shown as mini preview also that you always know, what you are going to paste.
See Also
Tool Name |
|
Current Version |
|
Platform |
|
Programming Language Used |
|
Short Description |
|
Latest Version Download |
|
Please Note! ... that all of my tools posted on my web site are using the Free Art License (FAL) 1.3 (Copy left Attitude), which means its free to use, share and even modify and redistribute, as long as your modified version is still free and not commercially distributed. If you want to exploit the software commercially, you would have to contact me and negotiate terms.
Needless to say, but better safe than sorry.... using my tools does not make me liable for any direct or indirect caused damages or losses, because of the use of them. You use them at your own risk. If you are paranoid, don't use them, if you are not understanding what I am saying here, don't use them either.
The .FNT file format allows for space efficient and relatively simple storrage of monochrome (black/white) bitmap font information for the use in any kind of
tool that need to emulate a specifc and non-standard character set, such as the display of ANSI and ASCII text art from old MS DOS PC's or Commodore Amiga systems or PETSCII and ATASCII art from the Commodore 64 and Atari 800 8 Bit home computers.
I saw this format first in the source code of an earlier version of PabloDraw by Curtis Wensley aka Eto and found it very useful.
Types
- Byte - Single 8 Bits Byte/Character
- Word - 2 Bytes Unsigned Short Integer in Little Endian Byte Order
Header
Offset |
Type |
Length |
Description |
Sample Value |
0 |
Word |
2 |
Character Width |
08 00 = Width = 8 pixels |
2 |
Word |
2 |
Character Height |
10 00 = Height = 16 pixels |
4 |
Word |
2 |
Number of Characters |
00 01 = # Chars = 255 |
Character Data
Each Point/Pixel is stored in a single bit. So for each row of a 8 pixels wide character 1 byte is used. For a 16 pixels per character wide font, 2 bytes would be used for a single row. The bit order is again little endian (right to left).
Character data are stored line by line, so for an 8 pixels wide and 16 pixels high font, each character would take up 16 bytes, or 4,096 bytes for a complete set of 256 characters, making the resulting .FNT file including its 6 byte header 4,102 bytes in size.
Example for MS DOS Character 01 with character size 8 pixels wide and 16 pixels high:
Bits Alt View*
00000000 ........
00000000 ........
01111110 .######.
10000001 #......#
10100101 #.#..#.#
10000001 #......#
10000001 #......#
10111101 #.####.#
10011001 #..##..#
10000001 #......#
10000001 #......#
01111110 .######.
00000000 ........
00000000 ........
00000000 ........
00000000 ........
*Alt View replaced 0 with . and 1 with # for better visualization
The Hex Values in the .FNT file look like this:
00 00 7E 81 A5 81 81 A5 99 81 81 7E 00 00 00 00
Again as a reminder:
Because of the Little Endian bit order the Characters appear mirrowed on the Y Axis (flip the bits in a byte) in the .FNT file.
CSharp Source Code is also available below as well as this VB.NET Sample code as ZIP Archive.
Public Module Sample
Public Function ProcessFntFile(ByVal sFNTFile As System.String) _
As System.Collections.Generic.List(Of System.Drawing.Bitmap)
If sFNTFile = "" Then
Return Nothing
Exit Function
Else
If Not System.IO.File.Exists(sFNTFile) Then
Return Nothing
Exit Function
End If
End If
Dim lstResults As New System.Collections.Generic.List(Of System.Drawing.Bitmap)
Dim lstChars As New System.Collections.Generic.List(Of System.Byte(,))
'Build a 16 colors MS DOS PC ANSI colors palette
Dim pal As System.Drawing.Imaging.ColorPalette = BuildMSDOSAnsiColorsPalette()
Dim bteFC As System.Byte = 7
Dim bteBC As System.Byte = 0
Dim fntBytes() As Byte = System.IO.File.ReadAllBytes(sFNTFile)
Dim lngCurrPos As System.Int64 = 0
Dim intCharWidth As System.Int32 = 0
Dim intCharHeight As System.Int32 = 0
Dim intNumChars As System.Int32 = 0
intCharWidth = GetWordLE(fntBytes, lngCurrPos)
intCharHeight = GetWordLE(fntBytes, lngCurrPos)
intNumChars = GetWordLE(fntBytes, lngCurrPos)
'Read all character information into a structered array
'Dimension 1 contains all lines/rows and Dimension 2 the row details (point bits)
For i As System.Int32 = 0 To intNumChars - 1
Dim aChar(intCharHeight - 1, intCharWidth / 8 - 1) As System.Byte
For y As System.Int32 = 0 To intCharHeight - 1
For x As System.Int32 = 0 To intCharWidth / 8 - 1
aChar(y, x) = GetByte(fntBytes, lngCurrPos)
Next
Next
lstChars.Add(aChar)
Next
For i As System.Int32 = 0 To lstChars.Count - 1
Dim Img As New System.Drawing.Bitmap(intCharWidth, intCharHeight, _
System.Drawing.Imaging.PixelFormat.Format4bppIndexed)
Img.Palette = pal
Dim bmpSr As System.Drawing.Imaging.BitmapData = Img.LockBits( _
New System.Drawing.Rectangle(0, 0, Img.Width, Img.Height), _
System.Drawing.Imaging.ImageLockMode.ReadWrite, _
Img.PixelFormat)
Dim ptrSr As System.IntPtr = bmpSr.Scan0
Dim bytesSr As System.Int32 = bmpSr.Stride * Img.Height
Dim rgbvaluesSr(bytesSr) As System.Byte
System.Runtime.InteropServices.Marshal.Copy(ptrSr, rgbvaluesSr, 0, bytesSr)
Dim iPos As System.Int64 = 0
Dim xOff As System.Int32 = 0
Dim yOff As System.Int32 = 0
For y As System.Int32 = 0 To intCharHeight - 1
For x As System.Int32 = 0 To intCharWidth - 1
Dim arrPos As System.Int32 = Math.Floor((y * bmpSr.Stride) + (x / 2))
Dim cb As System.Int32 = Math.Floor(x / 8)
Dim bitpos As System.Byte = 8 - (x - cb * 8)
Dim wByte As System.Byte = rgbvaluesSr(arrPos)
If x Mod 2 <> 0 Then
'odd .. right part
rgbvaluesSr(arrPos) = (wByte - ((wByte << &H4) >> &H4)) + _
IIf(ExamineBit(lstChars.Item(i)(y, cb), bitpos), bteFC, bteBC)
Else
'even .. left part
rgbvaluesSr(arrPos) = (wByte - ((wByte >> &H4) * 16)) + _
(IIf(ExamineBit(lstChars.Item(i)(y, cb), bitpos), bteFC, bteBC) * 16)
End If
Next
Next
System.Runtime.InteropServices.Marshal.Copy(rgbvaluesSr, 0, ptrSr, bytesSr)
Img.UnlockBits(bmpSr)
bmpSr = Nothing
rgbvaluesSr = Nothing
lstResults.Add(Img.Clone)
Img.Dispose()
Img = Nothing
Next
Return lstResults
End Function
' The ExamineBit function will return True or False
' depending on the value of the 1 based, nth bit (MyBit)
' of an integer (MyByte).
Public Function ExamineBit(ByVal MyByte As System.Byte, ByVal MyBit As System.Byte) As System.Boolean
Dim BitMask As System.Int16
MyByte = MyByte And &HFF
BitMask = 2 ^ (MyBit - 1)
Return ((MyByte And BitMask) > 0)
End Function
' The SetBit Sub will set the 1 based, nth bit
' (MyBit) of an integer (MyByte).
Public Sub SetBit(ByRef MyByte As System.Byte, ByVal MyBit As System.Byte)
Dim BitMask As System.Int16
MyByte = MyByte And &HFF
BitMask = 2 ^ (MyBit - 1)
MyByte = MyByte Or BitMask
End Sub
Public Function GetByte(ByVal arr() As System.Byte, ByRef lngPos As System.Int64) As System.Byte
'Read a single byte from a byte array at specified position
If lngPos < arr.Length Then
lngPos += 1
Return arr(lngPos - 1)
Else
Return 0
End If
End Function
Public Function GetWordLE(ByVal arr() As System.Byte, ByRef lngPos As System.Int64) As System.UInt16
'read 2 bytes into an unsigned 16 bit integer little endian
If lngPos + 1 < arr.Length Then
Return GetByte(arr, lngPos) + (GetByte(arr, lngPos) * 256)
Else
Return 0
End If
End Function
Public Function BuildMSDOSAnsiColorsPalette() As System.Drawing.Imaging.ColorPalette
Dim tmpImg As New System.Drawing.Bitmap(1, 1, System.Drawing.Imaging.PixelFormat.Format4bppIndexed)
Dim pal As System.Drawing.Imaging.ColorPalette = tmpImg.Palette
pal.Entries(0) = System.Drawing.Color.FromArgb(255, 0, 0, 0)
pal.Entries(1) = System.Drawing.Color.FromArgb(255, 0, 0, 170)
pal.Entries(2) = System.Drawing.Color.FromArgb(255, 0, 170, 0)
pal.Entries(3) = System.Drawing.Color.FromArgb(255, 0, 170, 170)
pal.Entries(4) = System.Drawing.Color.FromArgb(255, 170, 0, 0)
pal.Entries(5) = System.Drawing.Color.FromArgb(255, 170, 0, 170)
pal.Entries(6) = System.Drawing.Color.FromArgb(255, 170, 85, 0)
pal.Entries(7) = System.Drawing.Color.FromArgb(255, 170, 170, 170)
pal.Entries(8) = System.Drawing.Color.FromArgb(255, 85, 85, 85)
pal.Entries(9) = System.Drawing.Color.FromArgb(255, 85, 85, 255)
pal.Entries(10) = System.Drawing.Color.FromArgb(255, 85, 255, 85)
pal.Entries(11) = System.Drawing.Color.FromArgb(255, 85, 255, 255)
pal.Entries(12) = System.Drawing.Color.FromArgb(255, 255, 85, 85)
pal.Entries(13) = System.Drawing.Color.FromArgb(255, 255, 85, 255)
pal.Entries(14) = System.Drawing.Color.FromArgb(255, 255, 255, 85)
pal.Entries(15) = System.Drawing.Color.FromArgb(255, 255, 255, 255)
tmpImg.Dispose()
tmpImg = Nothing
Return pal
End Function
End Module
Previous Versions