.FNT Tool by Roy/SAC

.FNT Tool (Bitmap to .FNT Converter)

   Back to List of Tools Written by Roy/SAC

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 Summary

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.

 

Screenshots

Converter .FNT File Viewer
Editor New Font
Char Editor No Header Font File Properties

 

What the Hell is This?

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.

 

.FNT File Specifications

Types

  1. Byte - Single 8 Bits Byte/Character
  2. 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.

 

Sample Source Code (VB.NET)

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