{"id":970,"date":"2014-08-31T07:37:50","date_gmt":"2014-08-31T15:37:50","guid":{"rendered":"http:\/\/www.roysac.com\/blog\/?p=970"},"modified":"2014-08-31T07:51:02","modified_gmt":"2014-08-31T15:51:02","slug":"a-little-fnt-tool-for-programmers","status":"publish","type":"post","link":"https:\/\/www.roysac.com\/blog\/2014\/08\/a-little-fnt-tool-for-programmers\/","title":{"rendered":"A Little .FNT Tool for Programmers"},"content":{"rendered":"<p>&nbsp;<\/p>\n<p>I saw this format first in the <a title=\"download source from SourceForge.net\" href=\"http:\/\/sourceforge.net\/projects\/pablodraw\/files\/pablodraw-win\/2.0.8\/PabloDraw-2.0.8.70.src.zip\/download\" target=\"_blank\">source code<\/a> of an earlier version of <a class=\"roylink\" href=\"http:\/\/picoe.ca\/products\/pablodraw\" target=\"_blank\"><span style=\"text-decoration: underline;\"><span style=\"color: #aaaaff; text-decoration: underline;\">PabloDraw<\/span><\/span><\/a> by <strong>Curtis Wensley<\/strong> aka <strong>Eto<\/strong> and found it very useful.<\/p>\n<p><center><a href=\"http:\/\/www.roysac.com\/roy-tools\/fnt-tool.html\" target=\"_blank\"><img decoding=\"async\" src=\"http:\/\/www.roysac.com\/images\/scr\/fnt_tool2.gif\" alt=\"\" border=\"0\" \/><\/a><\/center><\/p>\n<p>I saw it again used for a EGA\/VGA DOS Font collection from 1992 by <strong>Joseph (Yossi) Gil <\/strong>(<a title=\"find the file on filewatcher.com\" href=\"http:\/\/www.filewatcher.com\/m\/fntcol16.zip.462295-0.html\" target=\"_blank\">fntcol16.zip<\/a>), which also comes with a set of tools, such as <em>BREAKCPI.COM<\/em>, which breaks the current EGA.CPI into fonts or <em>DUMPFONT.COM<\/em>, which is another tool to extract system fonts.<\/p>\n<p>The fonts are naturally all <strong>bitmap fonts<\/strong>, <strong>mono-spaced<\/strong> and <strong>monochrome<\/strong> (black\/white). The size per character is usually one of the following (Width X Height in pixels): 8&#215;8, 8&#215;14 or 8&#215;16 pixels. The font files in the collection by Joseph lack the &#8220;HEADER&#8221; though, meaning the width and height information are not part of the file. He simply used the file extensions &#8220;<em>Fxx<\/em>&#8220;, where &#8220;<em>xx<\/em>&#8221; specified the height (width wasn&#8217;t needed, because all his fonts had the same width (8 pixels)). Since I added a header to all the fonts in his collection and made it part of mine, you don&#8217;t have to worry about that anymore. However, if you happen to use one of his tools to extract new fonts, you can add a header very easily by using the DOS command: &#8220;<strong><span style=\"font-family: courier new,courier;\">copy \/b Fxx.BIN + FONTFILE.FNT NEWFONTFILE.FNT<\/span><\/strong>&#8220;<\/p>\n<p>&#8220;<em>Fxx.BIN<\/em>&#8221; should be one of the files <a title=\"FNTHDRSBIN.ZIP\" href=\"http:\/\/www.roysac.com\/blogimages\/files\/FNTHDRSBIN.ZIP\" target=\"_blank\">from this archive <\/a>, depending on the font HEIGHT, e.g. <em>F08.BIN<\/em> or <em>F16.BIN<\/em>.<\/p>\n<p>But enough of this and lets get to the actual stuff here.<\/p>\n<p>The<em> .FNT file format<\/em> that I am introducing here allows for space efficient and relatively simple storage of monochrome (black\/white) bitmap font information for the use in any kind of tool that need to emulate a specific and non-standard character set, such as the display of ANSI and ASCII text art from old <em>MS DOS PC&#8217;s<\/em> or <em>Commodore Amiga, Atari ST\/Falcon<\/em> 16 bit systems or <em>PETSCII<\/em> and <em>ATASCII<\/em> art from the <em>Commodore 64<\/em> and <em>Atari 400\/800, ZX Spectrum, Apple II<\/em> 8 Bit home computers.<\/p>\n<p>My 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.<\/p>\n<p>&nbsp;<\/p>\n<p><a class=\"download\" href=\"http:\/\/www.roysac.com\/roy-tools\/fnt-tool.html\" target=\"_blank\">Download the .FNT Tool<\/a><\/p>\n<p>&nbsp;<\/p>\n<p><b>Note:<\/b> The Tool comes already with over 300 fonts, ready to use!<\/p>\n<p>&nbsp;<\/p>\n<table class=\"cdstable\" border=\"1\" width=\"98%\" cellspacing=\"1\">\n<tbody>\n<tr>\n<td align=\"center\" valign=\"top\" width=\"50%\"><img decoding=\"async\" class=\"overlayed\" src=\"http:\/\/www.roysac.com\/blogimages\/TN_FNTTOOL_Convert.GIF\" alt=\"FNT Tool Converter\" border=\"0\" \/><\/td>\n<td align=\"center\" valign=\"top\" width=\"50%\"><img decoding=\"async\" class=\"overlayed\" src=\"http:\/\/www.roysac.com\/blogimages\/TN_FNTTOOL_Preview.GIF\" alt=\"FNT Tool Preview\" border=\"0\" \/><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2 id=\"fntspecs\" class=\"homeheader\">.FNT File Specifications<\/h2>\n<h3>Types<\/h3>\n<ol>\n<li><b>Byte<\/b> &#8211; Single 8 Bits Byte\/Character<\/li>\n<li><b>Word<\/b> &#8211; 2 Bytes Unsigned Short Integer in Little Endian Byte Order<\/li>\n<\/ol>\n<h4>Header<\/h4>\n<table class=\"cliparameters\">\n<thead>\n<tr class=\"head\">\n<th style=\"text-align: center;\">Offset<\/th>\n<th style=\"text-align: center;\">Type<\/th>\n<th style=\"text-align: center;\">Length<\/th>\n<th class=\"left\">Description<\/th>\n<th class=\"left\">Sample Value<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr class=\"row\">\n<td style=\"text-align: center; color: white;\">0<\/td>\n<td style=\"text-align: center; color: white;\">Word<\/td>\n<td style=\"text-align: center; color: white;\">2<\/td>\n<td style=\"color: white;\">Character Width<\/td>\n<td style=\"color: white;\"><code><span style=\"font-family: Lucida Console;\">08 00<\/span><\/code> = Width = 8 pixels<\/td>\n<\/tr>\n<tr class=\"row\">\n<td style=\"text-align: center; color: white;\">2<\/td>\n<td style=\"text-align: center; color: white;\">Word<\/td>\n<td style=\"text-align: center; color: white;\">2<\/td>\n<td style=\"color: white;\">Character Height<\/td>\n<td style=\"color: white;\"><code><span style=\"font-family: Lucida Console;\">10 00<\/span><\/code> = Height = 16 pixels<\/td>\n<\/tr>\n<tr class=\"row\">\n<td style=\"text-align: center; color: white;\">4<\/td>\n<td style=\"text-align: center; color: white;\">Word<\/td>\n<td style=\"text-align: center; color: white;\">2<\/td>\n<td style=\"color: white;\">Number of Characters<\/td>\n<td style=\"color: white;\"><code><span style=\"font-family: Lucida Console;\">00 01<\/span><\/code> = # Chars = 255<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3>Character Data<\/h3>\n<p>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.<\/p>\n<p>Example for MS DOS Character 01 with character size 8 pixels wide and 16 pixels high:<\/p>\n<pre>Bits      Alt View*\t\t\t\t\r\n00000000  ........                    \r\n00000000  ........                    \r\n01111110  .######.                    \r\n10000001  #......#                    \r\n10100101  #.#..#.#                    \r\n10000001  #......#                    \r\n10000001  #......#                    \r\n10111101  #.####.#                    \r\n10011001  #..##..#                    \r\n10000001  #......#                    \r\n10000001  #......#                    \r\n01111110  .######.                    \r\n00000000  ........                    \r\n00000000  ........                    \r\n00000000  ........                    \r\n00000000  ........                    \r\n\t\t\t\t                <\/pre>\n<p>&nbsp;<\/p>\n<p>*Alt View replaced 0 with . and 1 with # for better visualization<\/p>\n<p>The Hex Values in the .FNT file look like this:<br \/><code><span style=\"font-family: Lucida Console;\">00 00 7E 81 A5 81 81 A5 99 81 81 7E 00 00 00 00<\/span><\/code><\/p>\n<p><span style=\"color: red;\"><span style=\"color: #ff0000;\"><b>Again as a reminder:<\/b><br \/><\/span> 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.<\/span><\/p>\n<h3 id=\"samplecode\" class=\"homeheader\">Sample Source Code (VB.NET)<\/h3>\n<p>Here is some sample source code for processing a .FNT font file with VB.NET<\/p>\n<pre>[code language=\"vb\"]\r\nPublic Module Sample\r\n    Public Function ProcessFntFile(ByVal sFNTFile As System.String) _\r\n                                  As System.Collections.Generic.List(Of System.Drawing.Bitmap)\r\n        If sFNTFile = &quot;&quot; Then\r\n            Return Nothing\r\n            Exit Function\r\n        Else\r\n            If Not System.IO.File.Exists(sFNTFile) Then\r\n                Return Nothing\r\n                Exit Function\r\n            End If\r\n        End If\r\n        Dim lstResults As New System.Collections.Generic.List(Of System.Drawing.Bitmap)\r\n        Dim lstChars As New System.Collections.Generic.List(Of System.Byte(,))\r\n        'Build a 16 colors MS DOS PC ANSI colors palette\r\n        Dim pal As System.Drawing.Imaging.ColorPalette = BuildMSDOSAnsiColorsPalette()\r\n        Dim bteFC As System.Byte = 7\r\n        Dim bteBC As System.Byte = 0\r\n        Dim fntBytes() As Byte = System.IO.File.ReadAllBytes(sFNTFile)\r\n        Dim lngCurrPos As System.Int64 = 0\r\n        Dim intCharWidth As System.Int32 = 0\r\n        Dim intCharHeight As System.Int32 = 0\r\n        Dim intNumChars As System.Int32 = 0\r\n        intCharWidth = GetWordLE(fntBytes, lngCurrPos)\r\n        intCharHeight = GetWordLE(fntBytes, lngCurrPos)\r\n        intNumChars = GetWordLE(fntBytes, lngCurrPos)\r\n        'Read all character information into a structered array\r\n        'Dimension 1 contains all lines\/rows and Dimension 2 the row details (point bits)\r\n        For i As System.Int32 = 0 To intNumChars - 1\r\n            Dim aChar(intCharHeight - 1, intCharWidth \/ 8 - 1) As System.Byte\r\n            For y As System.Int32 = 0 To intCharHeight - 1\r\n                For x As System.Int32 = 0 To intCharWidth \/ 8 - 1\r\n                    aChar(y, x) = GetByte(fntBytes, lngCurrPos)\r\n                Next\r\n            Next\r\n            lstChars.Add(aChar)\r\n        Next\r\n        For i As System.Int32 = 0 To lstChars.Count - 1\r\n            Dim Img As New System.Drawing.Bitmap(intCharWidth, intCharHeight, _\r\n                                        System.Drawing.Imaging.PixelFormat.Format4bppIndexed)\r\n            Img.Palette = pal\r\n            Dim bmpSr As System.Drawing.Imaging.BitmapData = Img.LockBits( _\r\n                       New System.Drawing.Rectangle(0, 0, Img.Width, Img.Height), _\r\n                       System.Drawing.Imaging.ImageLockMode.ReadWrite, _\r\n                       Img.PixelFormat)\r\n            Dim ptrSr As System.IntPtr = bmpSr.Scan0\r\n            Dim bytesSr As System.Int32 = bmpSr.Stride * Img.Height\r\n            Dim rgbvaluesSr(bytesSr) As System.Byte\r\n            System.Runtime.InteropServices.Marshal.Copy(ptrSr, rgbvaluesSr, 0, bytesSr)\r\n            Dim iPos As System.Int64 = 0\r\n            Dim xOff As System.Int32 = 0\r\n            Dim yOff As System.Int32 = 0\r\n            For y As System.Int32 = 0 To intCharHeight - 1\r\n                For x As System.Int32 = 0 To intCharWidth - 1\r\n                    Dim arrPos As System.Int32 = Math.Floor((y * bmpSr.Stride) + (x \/ 2))\r\n                    Dim cb As System.Int32 = Math.Floor(x \/ 8)\r\n                    Dim bitpos As System.Byte = 8 - (x - cb * 8)\r\n                    Dim wByte As System.Byte = rgbvaluesSr(arrPos)\r\n                    If x Mod 2 &lt;&gt; 0 Then\r\n                        'odd .. right part\r\n                        rgbvaluesSr(arrPos) = (wByte - ((wByte &lt;&lt; &amp;H4) &gt;&gt; &amp;H4)) + _\r\n                                       IIf(ExamineBit(lstChars.Item(i)(y, cb), bitpos), bteFC, bteBC)\r\n                    Else\r\n                        'even .. left part\r\n                        rgbvaluesSr(arrPos) = (wByte - ((wByte &gt;&gt; &amp;H4) * 16)) + _\r\n                                      (IIf(ExamineBit(lstChars.Item(i)(y, cb), bitpos), bteFC, bteBC) * 16)\r\n                    End If\r\n\r\n                Next\r\n            Next\r\n            System.Runtime.InteropServices.Marshal.Copy(rgbvaluesSr, 0, ptrSr, bytesSr)\r\n            Img.UnlockBits(bmpSr)\r\n            bmpSr = Nothing\r\n            rgbvaluesSr = Nothing\r\n            lstResults.Add(Img.Clone)\r\n            Img.Dispose()\r\n            Img = Nothing\r\n        Next\r\n        Return lstResults\r\n    End Function\r\n\r\n    ' The ExamineBit function will return True or False\r\n    ' depending on the value of the 1 based, nth bit (MyBit)\r\n    ' of an integer (MyByte).\r\n    Public Function ExamineBit(ByVal MyByte As System.Byte, ByVal MyBit As System.Byte) _\r\n                    As System.Boolean\r\n        Dim BitMask As System.Int16\r\n        MyByte = MyByte And &amp;HFF\r\n        BitMask = 2 ^ (MyBit - 1)\r\n        Return ((MyByte And BitMask) &gt; 0)\r\n    End Function\r\n\r\n    ' The SetBit Sub will set the 1 based, nth bit\r\n    ' (MyBit) of an integer (MyByte).\r\n    Public Sub SetBit(ByRef MyByte As System.Byte, ByVal MyBit As System.Byte)\r\n        Dim BitMask As System.Int16\r\n        MyByte = MyByte And &amp;HFF\r\n        BitMask = 2 ^ (MyBit - 1)\r\n        MyByte = MyByte Or BitMask\r\n    End Sub\r\n\r\n    Public Function GetByte(ByVal arr() As System.Byte, ByRef lngPos As System.Int64) _ \r\n                            As System.Byte\r\n        'Read a single byte from a byte array at specified position\r\n        If lngPos &lt; arr.Length Then\r\n            lngPos += 1\r\n            Return arr(lngPos - 1)\r\n        Else\r\n            Return 0\r\n        End If\r\n    End Function\r\n    Public Function GetWordLE(ByVal arr() As System.Byte, ByRef lngPos As System.Int64) _\r\n                              As System.UInt16\r\n        'read 2 bytes into an unsigned 16 bit integer little endian\r\n        If lngPos + 1 &lt; arr.Length Then\r\n            Return GetByte(arr, lngPos) + (GetByte(arr, lngPos) * 256)\r\n        Else\r\n            Return 0\r\n        End If\r\n    End Function\r\n\r\n    Public Function BuildMSDOSAnsiColorsPalette() As System.Drawing.Imaging.ColorPalette\r\n        Dim tmpImg As New System.Drawing.Bitmap(1, 1, _ \r\n                          System.Drawing.Imaging.PixelFormat.Format4bppIndexed)\r\n        Dim pal As System.Drawing.Imaging.ColorPalette = tmpImg.Palette\r\n        pal.Entries(0) = System.Drawing.Color.FromArgb(255, 0, 0, 0)\r\n        pal.Entries(1) = System.Drawing.Color.FromArgb(255, 0, 0, 170)\r\n        pal.Entries(2) = System.Drawing.Color.FromArgb(255, 0, 170, 0)\r\n        pal.Entries(3) = System.Drawing.Color.FromArgb(255, 0, 170, 170)\r\n        pal.Entries(4) = System.Drawing.Color.FromArgb(255, 170, 0, 0)\r\n        pal.Entries(5) = System.Drawing.Color.FromArgb(255, 170, 0, 170)\r\n        pal.Entries(6) = System.Drawing.Color.FromArgb(255, 170, 85, 0)\r\n        pal.Entries(7) = System.Drawing.Color.FromArgb(255, 170, 170, 170)\r\n        pal.Entries(8) = System.Drawing.Color.FromArgb(255, 85, 85, 85)\r\n        pal.Entries(9) = System.Drawing.Color.FromArgb(255, 85, 85, 255)\r\n        pal.Entries(10) = System.Drawing.Color.FromArgb(255, 85, 255, 85)\r\n        pal.Entries(11) = System.Drawing.Color.FromArgb(255, 85, 255, 255)\r\n        pal.Entries(12) = System.Drawing.Color.FromArgb(255, 255, 85, 85)\r\n        pal.Entries(13) = System.Drawing.Color.FromArgb(255, 255, 85, 255)\r\n        pal.Entries(14) = System.Drawing.Color.FromArgb(255, 255, 255, 85)\r\n        pal.Entries(15) = System.Drawing.Color.FromArgb(255, 255, 255, 255)\r\n        tmpImg.Dispose()\r\n        tmpImg = Nothing\r\n        Return pal\r\n    End Function\r\n\r\nEnd Module\r\n[\/code]<\/pre>\n<p>&nbsp;<\/p>\n<p>Download the sample code<a title=\"download fntsamplevbnet.zip\" href=\"http:\/\/www.roysac.com\/blogimages\/files\/fntsamplevbnet.zip\" target=\"_blank\"> fntsamplevbnet.zip<\/a><\/p>\n<p>&nbsp;<\/p>\n<h3 id=\"samplecode2\" class=\"homeheader\">Sample Source Code (C#.NET)<\/h3>\n<p>Here is some sample source code for processing a .FNT font file with CSharp (C#.NET)<\/p>\n<pre>[code language=\"csharp\"]\r\n\/\/\/ &lt;summary&gt;\r\n\/\/\/ C# generated from VB.NET Code via\r\n\/\/\/ http:\/\/codeconverter.sharpdevelop.net\/SnippetConverter.aspx\r\n\/\/\/ (with some manual tweaks done by hand afterwards)\r\n\/\/\/ This code is still untested though, but I am pretty confident \r\n\/\/\/ that it will work just fine as the VB.NET version does\r\n\/\/\/ Cheers! Carsten aka Roy\/SAC\r\n\/\/\/ &lt;\/summary&gt;\r\npublic static class Sample {\r\n    \/\/\/ &lt;summary&gt;\r\n    \/\/\/ Reads a provided .FNT file and returns a list of images, \r\n    \/\/\/ one image for each character in the font set\r\n    \/\/\/ &lt;\/summary&gt;\r\n    \/\/\/ &lt;param name=&quot;sFNTFile&quot;&gt;&lt;\/param&gt;\r\n    \/\/\/ &lt;returns&gt;&lt;\/returns&gt;\r\n    public static System.Collections.Generic.List&lt;System.Drawing.Bitmap&gt; ProcessFntFile(\r\n                                           System.String sFNTFile) {\r\n        if (string.IsNullOrEmpty(sFNTFile)) {\r\n            return null;\r\n        } else {\r\n            if (!System.IO.File.Exists(sFNTFile)) {\r\n                return null;\r\n            }\r\n        }\r\n        System.Collections.Generic.List&lt;System.Drawing.Bitmap&gt; lstResults = \r\n                     new System.Collections.Generic.List&lt;System.Drawing.Bitmap&gt;();\r\n        System.Collections.Generic.List&lt;System.Byte[,]&gt; lstChars = \r\n                     new System.Collections.Generic.List&lt;System.Byte[,]&gt;();\r\n        \/\/Build a 16 colors MS DOS PC ANSI colors palette\r\n        System.Drawing.Imaging.ColorPalette pal = BuildMSDOSAnsiColorsPalette();\r\n        System.Byte bteFC = 7;\r\n        System.Byte bteBC = 0;\r\n        byte[] fntBytes = System.IO.File.ReadAllBytes(sFNTFile);\r\n        System.Int64 lngCurrPos = 0;\r\n        System.Int32 intCharWidth = 0;\r\n        System.Int32 intCharHeight = 0;\r\n        System.Int32 intNumChars = 0;\r\n        intCharWidth = GetWordLE(fntBytes, ref lngCurrPos);\r\n        intCharHeight = GetWordLE(fntBytes, ref lngCurrPos);\r\n        intNumChars = GetWordLE(fntBytes, ref lngCurrPos);\r\n        \/\/Read all character information into a structered array\r\n        \/\/Dimension 1 contains all lines\/rows and Dimension 2 the row details (point bits)\r\n        for (System.Int32 i = 0; i &lt;= intNumChars - 1; i++)  {\r\n            System.Byte[,] aChar = new System.Byte[intCharHeight, intCharWidth \/ 8];\r\n            for (System.Int32 y = 0; y &lt;= intCharHeight - 1; y++) {\r\n                for (System.Int32 x = 0; x &lt;= intCharWidth \/ 8 - 1; x++) {\r\n                    aChar[y, x] = GetByte(fntBytes, ref lngCurrPos);\r\n                }\r\n            }\r\n            lstChars.Add(aChar);\r\n        }\r\n        for (System.Int32 i = 0; i &lt;= lstChars.Count - 1; i++) {\r\n            System.Drawing.Bitmap oImg = new System.Drawing.Bitmap(intCharWidth, intCharHeight, \r\n                                          System.Drawing.Imaging.PixelFormat.Format4bppIndexed);\r\n            oImg.Palette = pal;\r\n            System.Drawing.Imaging.BitmapData bmpSr = \r\n                       oImg.LockBits(new System.Drawing.Rectangle(0, 0, oImg.Width, oImg.Height), \r\n                               System.Drawing.Imaging.ImageLockMode.ReadWrite, oImg.PixelFormat);\r\n            System.IntPtr ptrSr = bmpSr.Scan0;\r\n            System.Int32 bytesSr = bmpSr.Stride * oImg.Height;\r\n            System.Byte[] rgbvaluesSr = new System.Byte[bytesSr + 1];\r\n            System.Runtime.InteropServices.Marshal.Copy(ptrSr, rgbvaluesSr, 0, bytesSr);\r\n            for (System.Int32 y = 0; y &lt;= intCharHeight - 1; y++) {\r\n                for (System.Int32 x = 0; x &lt;= intCharWidth - 1; x++) {\r\n                    System.Int32 arrPos = (int)(System.Math.Floor((y * bmpSr.Stride) + ((float)x \/ 2)));\r\n                    System.Int32 cb = (int)System.Math.Floor((float)x \/ 8);\r\n                    System.Byte bitpos = (byte)(8 - ((int)x - (int)cb * 8));\r\n                    System.Byte wByte = rgbvaluesSr[arrPos];\r\n                    if (x % 2 != 0) {\r\n                        \/\/odd .. right part\r\n                        rgbvaluesSr[(int)arrPos] = \r\n                                (byte)((wByte - (byte)(((byte)wByte &lt;&lt; (byte)0x4) &gt;&gt; (byte)0x4)) \r\n                                + (byte)((ExamineBit(lstChars[i][y, cb], bitpos) ? bteFC : bteBC)));\r\n                    } else {\r\n                        \/\/even .. left part\r\n                        rgbvaluesSr[(int)arrPos] = (byte)((wByte - ((wByte &gt;&gt; 0x4) * 16)) + \r\n                            ((ExamineBit(lstChars[i][y, cb], bitpos) ? bteFC : bteBC) * (byte)16));\r\n                    }\r\n                }\r\n            }\r\n            System.Runtime.InteropServices.Marshal.Copy(rgbvaluesSr, 0, ptrSr, bytesSr);\r\n            oImg.UnlockBits(bmpSr);\r\n            bmpSr = null;\r\n            rgbvaluesSr = null;\r\n            lstResults.Add((System.Drawing.Bitmap) oImg.Clone());\r\n            oImg.Dispose();\r\n            oImg = null;\r\n        }\r\n        return lstResults;\r\n    }\r\n\r\n    \/\/\/ &lt;summary&gt;\r\n    \/\/\/ The ExamineBit function will return True or False\r\n    \/\/\/ depending on the value of the 1 based, nth bit (MyBit)\r\n    \/\/\/ of an integer (MyByte).\r\n    \/\/\/ &lt;\/summary&gt;\r\n    \/\/\/ &lt;param name=&quot;MyByte&quot;&gt;&lt;\/param&gt;\r\n    \/\/\/ &lt;param name=&quot;MyBit&quot;&gt;&lt;\/param&gt;\r\n    \/\/\/ &lt;returns&gt;&lt;\/returns&gt;\r\n    public static System.Boolean ExamineBit(System.Byte MyByte, System.Byte MyBit) {\r\n        System.Int16 BitMask = 0;\r\n        MyByte = (byte)(MyByte &amp; 0xff);\r\n        BitMask = (byte)(System.Math.Pow(2, (MyBit - 1)));\r\n        return ((MyByte &amp; BitMask) &gt; 0);\r\n    }\r\n\r\n    \/\/\/ &lt;summary&gt;\r\n    \/\/\/ The SetBit Sub will set the 1 based, nth bit (MyBit) \r\n    \/\/\/ of an integer (MyByte).\r\n    \/\/\/ &lt;\/summary&gt;\r\n    \/\/\/ &lt;param name=&quot;MyByte&quot;&gt;&lt;\/param&gt;\r\n    \/\/\/ &lt;param name=&quot;MyBit&quot;&gt;&lt;\/param&gt;\r\n    public static void SetBit(ref System.Byte MyByte, System.Byte MyBit) {\r\n        System.Int16 BitMask = 0;\r\n        MyByte = (byte)(MyByte &amp; 0xff);\r\n        BitMask = (byte)(System.Math.Pow(2, (MyBit - 1)));\r\n        MyByte = (byte)(MyByte | (byte)BitMask);\r\n    }\r\n    \/\/\/ &lt;summary&gt;\r\n    \/\/\/ Read a single byte from a byte array at specified position\r\n    \/\/\/ &lt;\/summary&gt;\r\n    \/\/\/ &lt;param name=&quot;arr&quot;&gt;&lt;\/param&gt;\r\n    \/\/\/ &lt;param name=&quot;lngPos&quot;&gt;&lt;\/param&gt;\r\n    \/\/\/ &lt;returns&gt;&lt;\/returns&gt;\r\n    public static System.Byte GetByte(System.Byte[] arr, ref System.Int64 lngPos) {\r\n        if (lngPos &lt; arr.Length) {\r\n            lngPos += 1;\r\n            return arr[lngPos - 1];\r\n        } else {\r\n            return 0;\r\n        }\r\n    }\r\n    \/\/\/ &lt;summary&gt;\r\n    \/\/\/ read 2 bytes into an unsigned 16 bit integer little endian\r\n    \/\/\/ &lt;\/summary&gt;\r\n    \/\/\/ &lt;param name=&quot;arr&quot;&gt;&lt;\/param&gt;\r\n    \/\/\/ &lt;param name=&quot;lngPos&quot;&gt;&lt;\/param&gt;\r\n    \/\/\/ &lt;returns&gt;&lt;\/returns&gt;\r\n    public static System.UInt16 GetWordLE(System.Byte[] arr, ref System.Int64 lngPos) {\r\n        if (lngPos + 1 &lt; arr.Length) {\r\n            return (ushort)(GetByte(arr, ref lngPos) + (GetByte(arr, ref lngPos) * 256));\r\n        } else {\r\n            return 0;\r\n        }\r\n    }\r\n    \/\/\/ &lt;summary&gt;\r\n    \/\/\/ Build Ansi Colors Image Palette (16 Colors)\r\n    \/\/\/ &lt;\/summary&gt;\r\n    \/\/\/ &lt;returns&gt;&lt;\/returns&gt;\r\n    public static System.Drawing.Imaging.ColorPalette BuildMSDOSAnsiColorsPalette() {\r\n        System.Drawing.Bitmap tmpImg = new System.Drawing.Bitmap(1, 1, \r\n                          System.Drawing.Imaging.PixelFormat.Format4bppIndexed);\r\n        System.Drawing.Imaging.ColorPalette pal = tmpImg.Palette;\r\n        pal.Entries[0] = System.Drawing.Color.FromArgb(255, 0, 0, 0);\r\n        pal.Entries[1] = System.Drawing.Color.FromArgb(255, 0, 0, 170);\r\n        pal.Entries[2] = System.Drawing.Color.FromArgb(255, 0, 170, 0);\r\n        pal.Entries[3] = System.Drawing.Color.FromArgb(255, 0, 170, 170);\r\n        pal.Entries[4] = System.Drawing.Color.FromArgb(255, 170, 0, 0);\r\n        pal.Entries[5] = System.Drawing.Color.FromArgb(255, 170, 0, 170);\r\n        pal.Entries[6] = System.Drawing.Color.FromArgb(255, 170, 85, 0);\r\n        pal.Entries[7] = System.Drawing.Color.FromArgb(255, 170, 170, 170);\r\n        pal.Entries[8] = System.Drawing.Color.FromArgb(255, 85, 85, 85);\r\n        pal.Entries[9] = System.Drawing.Color.FromArgb(255, 85, 85, 255);\r\n        pal.Entries[10] = System.Drawing.Color.FromArgb(255, 85, 255, 85);\r\n        pal.Entries[11] = System.Drawing.Color.FromArgb(255, 85, 255, 255);\r\n        pal.Entries[12] = System.Drawing.Color.FromArgb(255, 255, 85, 85);\r\n        pal.Entries[13] = System.Drawing.Color.FromArgb(255, 255, 85, 255);\r\n        pal.Entries[14] = System.Drawing.Color.FromArgb(255, 255, 255, 85);\r\n        pal.Entries[15] = System.Drawing.Color.FromArgb(255, 255, 255, 255);\r\n        tmpImg.Dispose();\r\n        tmpImg = null;\r\n        return pal;\r\n    }\r\n\r\n}\r\n\r\n[\/code]<\/pre>\n<p>&nbsp;<\/p>\n<p>Download the sample code<a title=\"download fntsamplec#net.zip\" href=\"http:\/\/www.roysac.com\/blogimages\/files\/fntsamplec#net.zip\" target=\"_blank\"> fntsamplec#net.zip<\/a><\/p>\n<p>&nbsp;<\/p>\n<p>Enjoy!<\/p>\n<p><b>Carsten<\/b> aka <a href=\"http:\/\/www.roysac.com\/\" target=\"_blank\">Roy\/SAC<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>&nbsp; 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. I saw it again used for a EGA\/VGA DOS Font collection from 1992 by Joseph (Yossi) Gil (fntcol16.zip), which also comes with a set of tools, such as BREAKCPI.COM, [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[42,31,3],"tags":[71,56],"class_list":["post-970","post","type-post","status-publish","format-standard","hentry","category-education","category-programming","category-tools","tag-information","tag-tool-2"],"_links":{"self":[{"href":"https:\/\/www.roysac.com\/blog\/wp-json\/wp\/v2\/posts\/970","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.roysac.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.roysac.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.roysac.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.roysac.com\/blog\/wp-json\/wp\/v2\/comments?post=970"}],"version-history":[{"count":20,"href":"https:\/\/www.roysac.com\/blog\/wp-json\/wp\/v2\/posts\/970\/revisions"}],"predecessor-version":[{"id":991,"href":"https:\/\/www.roysac.com\/blog\/wp-json\/wp\/v2\/posts\/970\/revisions\/991"}],"wp:attachment":[{"href":"https:\/\/www.roysac.com\/blog\/wp-json\/wp\/v2\/media?parent=970"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.roysac.com\/blog\/wp-json\/wp\/v2\/categories?post=970"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.roysac.com\/blog\/wp-json\/wp\/v2\/tags?post=970"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}