From 0893d3194eedbf89abc3c902ba78d109ec420a22 Mon Sep 17 00:00:00 2001
From: Xavier <xavier@c-est-simple.com>
Date: Sat, 21 Oct 2017 13:31:07 +0200
Subject: [PATCH] Fixed big fonts handling, started char array font parsing

---
 resources/glyph2font.html  | 236 -----------
 resources/glyphEditor.html | 842 +++++++++++++++++++++++++++++++++++++
 2 files changed, 842 insertions(+), 236 deletions(-)
 delete mode 100644 resources/glyph2font.html
 create mode 100644 resources/glyphEditor.html

diff --git a/resources/glyph2font.html b/resources/glyph2font.html
deleted file mode 100644
index 8f02cf2..0000000
--- a/resources/glyph2font.html
+++ /dev/null
@@ -1,236 +0,0 @@
-<html>
-  <head>
-    <style>
-      #form {
-        user-select: none; 
-      }
-      table {
-        margin-top: 5px;
-      }
-      table, tr, td, th {
-        user-select: none; 
-        border-collapse: collapse;
-      }
-      td, th {
-        border: 1px solid #CCC;
-        width: 12px;
-        height: 15px;
-      }
-      td.on {
-        background-color: #CCC;
-      }
-      
-      #addChar, #generate {
-        display: none;
-      }
-      body.started #addChar, body.started #generate {
-        display: inline;
-      }
-      body.started #create {
-        display: none;
-      }
-      body.started input {
-        pointer-events:none;
-      }
-      #page {
-        position:relative;
-      }
-      #page>div {
-        position: relative;
-        float: left;
-      }
-
-      #output {
-        margin-left: 20px;
-        margin-top: 12px;
-        font-size:12px;
-        user-select: all;
-      }
-      
-    </style>
-  </head>
-  <body>
-    <div id="form">
-      <span>Font array name:</span> <input placeholder="Font array name" type="text" id="name" value="My_Font"/><br/>
-      <span>Width:</span> <input placeholder="Font width" type="number" id="width" value="10"/><br/>
-      <span>Height:</span> <input placeholder="Font height" type="number" id="height" value="13" max="64"/><br/>
-      <span>First char code:</span> <input placeholder="First char code" type="number" id="code" value="1" min="1"/><br/>
-      <br/>
-      <button id="create">Create</button>
-      <button id="addChar">Add a character</button>
-      <button id="generate">Generate</button>
-    </div>
-    <div id="page">
-    <div id="chars" ondragstart="return false;"></div>
-    <div id="output">
-      <div class="output" id="header"> </div>
-      <div class="output" id="jump"> </div>
-      <div class="output" id="data"> </div>
-    </div>
-    </div>
-    <script language="JavaScript1.5">
-    (function() {
-      // 100% vanilla ECS6, no framework or library was injured for this project.
-      // This page allows drawing icons in grids and generating the map with the format required by 
-      // library for OLED SD1306 screen: https://github.com/squix78/esp8266-oled-ssd1306
-     
-      // TODO: 
-      // Implement data parsing to edit existing font: from char array data to pixels matrix
-      // Implement methods to move glyphs, symetrical input, ...
-      // Implement char insertion, non displayable char, ...
-      // Submit PR to original project.
-      
-      let font;
-      class Font {
-        constructor(height, width, code) {
-          this.height = height;
-          this.width = width;
-          this.firstCharCode = code;
-          this.currentCharCode = code;
-          this.chars = [];
-          this.jumpMap = [];
-        }
-      
-        addChar() {
-          let fontContainer = document.getElementById('chars');
-          let charContainer = fontContainer.appendChild(document.createElement("table"));
-          charContainer.setAttribute("code", this.currentCharCode);
-          let header = charContainer.appendChild(document.createElement("th"));
-          header.setAttribute("colspan", this.width-1);
-          header.textContent = `Character ${this.currentCharCode}`;
-          let deletePixels = charContainer.appendChild(document.createElement("th"));
-          deletePixels.setAttribute("action", "remove");
-          deletePixels.textContent = "x";
-          deletePixels.addEventListener('click', function() {
-            let result = confirm("Delete the pixels ?");
-            if(result) {
-              let pixels = charContainer.getElementsByTagName('td');
-              for(let p = 0; p < pixels.length; p++) {
-                pixels[p].className = '';
-              }
-            } 
-          });
-          for(let r = 0; r < this.height; r++) {
-          	let rowContainer = charContainer.appendChild(document.createElement("tr"));
-            for(let c = 0; c < this.width; c++) {
-          		let pixContainer = rowContainer.appendChild(document.createElement("td"));
-            }
-          }
-          this.currentCharCode++;
-        }
-        
-        togglePixel(pixel) {
-          pixel.className = pixel.className == 'on' ? '': 'on';
-        }
-        
-        // Read from the <td> css class the pixels that need to be on
-        // generates the jump table and font data 
-        generate() {
-          document.getElementById('header').textContent = '';
-          document.getElementById('jump').textContent = '';
-          document.getElementById('data').textContent = '';
-          let name = document.getElementById('name').value.replace(/[-.*+= ]/g, '_');
-          let bits2add = (1 + ((this.height - 1) >> 3))*8 - this.height;  // number of missing bits to fill leftmost byte
-          let chars = document.getElementsByTagName('table');
-          let charCount = chars.length;
-          let charAddr = 0;
-          output('jump', '  // Jump table:');
-          output('data', '  // Data:');
-          // Browse each character
-          for(let ch = 0; ch < charCount; ch++) {
-            let charBytes = [];
-            let charBits = [];
-            let charWidth = 1; // always add one row of off pixels to the right ?
-            let rows = chars[ch].getElementsByTagName('tr');
-            // Browse each column
-            for(let col = 0; col < this.width ; col++) {
-              var bits = ""; // using string because js uses 32b ints when performing bit operations
-              // Browse each row starting from the bottom one, going up, and accumulate pixels in
-              // a string: this rotates the glyph
-              for(let r = rows.length-1; r >=0 ; r--) {
-                let pixelState = rows[r].children[col].className;
-                bits += (pixelState == 'on' ? '1': '0');           
-              }
-              // Need to complete missing bits to have a sizeof byte multiple number of bits
-              for(let b = 0; b < bits2add; b++) {
-                bits +=  '0';
-              }
-              // output('data', `  // ${bits}`);  // Debugging help: rotated bitmap
-              for(let b = 0 ; b < bits.length/16; b+=16) {
-                let word = parseInt(bits.substring(b, b+15), 2);
-                charBytes.push(getLsB(word));
-                charBytes.push(getMsB(word));               
-              } 
-            }
-            // Remove bytes with value 0 at the end of the array.
-            while(charBytes[charBytes.length-1] == '0x0') {
-              charBytes.pop();
-            }
-            
-            output('data', `  ${charBytes.join(',')},`);
-            // TODO: last param width is not the best value. Need to compute the actual occupied width
-            output('jump', `  ${getMsB(charAddr)}, ${getLsB(charAddr)}, ${toHexString(charBytes.length)}, ${toHexString(this.width)}, `);
-            charAddr += charBytes.length;                                           
-          }
-          output('data', '};');
-          
-          output('header', `const char ${name}[] PROGMEM = {`);
-          output('header', `  ${toHexString(this.width)}, // Width: ${this.width}`);
-          output('header', `  ${toHexString(this.height)}, // Height: ${this.height}`);          
-          output('header', `  ${toHexString(this.firstCharCode)}, // First char: ${this.firstCharCode}`);
-          output('header', `  ${toHexString(charCount)}, // Number of chars: ${charCount}`);
-        }
-      }
-      
-      // Return anInt as hex string
-      toHexString = function(anInt) {
-        return `0x${anInt.toString(16)}`
-      }
-      
-      // Return least significant byte as hex string
-      getLsB = function(anInt) {
-        return toHexString(anInt & 0xFF);      
-      }
-      // Return most significant byte as hex string
-      getMsB = function(anInt) {
-        return toHexString(anInt>>>8);      
-      }
-     
-      output = function(targetId, msg) {
-        var output = document.getElementById(targetId);
-        var line = output.appendChild(document.createElement('div'));
-        line.textContent = msg;
-        
-      }
-      
-      document.getElementById('generate').addEventListener('click', function() {
-        font.generate();
-      });
-      
-      document.getElementById('addChar').addEventListener('click', function() {
-        font.addChar();
-      });
-      document.getElementById('create').addEventListener('click', function(button) {
-        document.body.className = "started";      
-      	font = new Font(parseInt(document.getElementById('height').value), parseInt(document.getElementById('width').value), parseInt(document.getElementById('code').value));
-        font.addChar();
-      });
-      document.getElementById('chars').addEventListener('mousedown', function(e) {
-        let target = e.target;
-        if (target.nodeName != 'TD') return;
-        font.togglePixel(target);
-      });
-      document.getElementById('chars').addEventListener('mouseover', function(e) {
-        let target = e.target;
-        if (target.nodeName != 'TD' || e.buttons != 1) return;
-        font.togglePixel(target);
-      });
-      document.getElementById('chars').addEventListener('dragstart', function(e) {
-        return;
-      });
-        
-      })();
-    </script>  
-  </body>
-</html>
-
diff --git a/resources/glyphEditor.html b/resources/glyphEditor.html
new file mode 100644
index 0000000..8693ec5
--- /dev/null
+++ b/resources/glyphEditor.html
@@ -0,0 +1,842 @@
+<!--The MIT License (MIT)
+
+Copyright (c) 2017 by Xavier Grosjean
+
+Based on work 
+Copyright (c) 2016 by Daniel Eichhorn
+Copyright (c) 2016 by Fabrice Weinberg
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+-->
+
+<html>
+  <head>
+    <style>
+      #form {
+        user-select: none; 
+      }
+      #chars table {
+        margin-top: 5px;
+        user-select: none; 
+      }
+      #chars table, tr, td, th {
+        border-collapse: collapse;
+      }
+      #chars td, th {
+        border: 1px solid #CCC;
+        width: 12px;
+        height: 15px;
+      }
+      #chars td.on {
+        background-color: #CCC;
+      }
+      
+      #addChar, #generate {
+        display: none;
+      }
+      body.started #addChar, body.started #generate {
+        display: inline;
+      }
+      body.started #create {
+        display: none;
+      }
+      body.started input {
+        pointer-events:none;
+      }
+      #page {
+        position:relative;
+      }
+      #page>div {
+        position: relative;
+        float: left;
+      }
+
+      #output {
+        margin-left: 20px;
+        margin-top: 12px;
+        font-size:12px;
+        user-select: all;
+      }
+      #input {
+        position:absolute;
+        top:0;
+        right:0;
+        padding: 20px;
+        width:50%;
+      }
+      #input textarea {
+        width: 100%;
+        height: 500px;
+        margin-bottom: 10px;
+      }
+      
+    </style>
+  </head>
+  <body>
+    <div id="form">
+      <table>
+        <tr>
+          <td>Font array name:</td><td><input placeholder="Font array name" type="text" id="name" value="My_Font"/></td>
+        </tr>
+        <tr>
+          <td>Width:</td><td><input placeholder="Font width" type="number" id="width" value="10"/></td>
+        </tr>
+        <tr>
+          <td>Height:</td><td><input placeholder="Font height" type="number" id="height" value="13" max="64"/></td>
+        </tr>
+        <tr>
+          <td>First char code:</td><td><input placeholder="First char code" type="number" id="code" value="1" min="1"/></td>
+        </tr>
+      </table>
+      <br/>
+      <button id="create">Create</button>
+      <button id="addChar">Add a character</button>
+      <button id="generate">Generate</button>
+    </div>
+    <div id="page">
+      <div id="chars" ondragstart="return false;"></div>
+      <div id="output">
+        <div class="output" id="header"> </div>
+        <div class="output" id="jump"> </div>
+        <div class="output" id="data"> </div>
+      </div>
+    </div>
+    <div id="input">
+      <textarea id="inputText" placeholder="Paste a char array font definition here">
+        
+#ifndef OLEDDISPLAYFONTS_h
+#define OLEDDISPLAYFONTS_h
+
+const char ArialMT_Plain_10[] PROGMEM = {
+  0x0A, // Width: 10
+  0x0D, // Height: 13
+  0x20, // First Char: 32
+  0xE0, // Numbers of Chars: 224
+
+  // Jump Table:
+  0xFF, 0xFF, 0x00, 0x03,  // 32:65535
+  0x00, 0x00, 0x04, 0x03,  // 33:0
+  0x00, 0x04, 0x05, 0x04,  // 34:4
+  0x00, 0x09, 0x09, 0x06,  // 35:9
+  0x00, 0x12, 0x0A, 0x06,  // 36:18
+  0x00, 0x1C, 0x10, 0x09,  // 37:28
+  0x00, 0x2C, 0x0E, 0x07,  // 38:44
+  0x00, 0x3A, 0x01, 0x02,  // 39:58
+  0x00, 0x3B, 0x06, 0x03,  // 40:59
+  0x00, 0x41, 0x06, 0x03,  // 41:65
+  0x00, 0x47, 0x05, 0x04,  // 42:71
+  0x00, 0x4C, 0x09, 0x06,  // 43:76
+  0x00, 0x55, 0x04, 0x03,  // 44:85
+  0x00, 0x59, 0x03, 0x03,  // 45:89
+  0x00, 0x5C, 0x04, 0x03,  // 46:92
+  0x00, 0x60, 0x05, 0x03,  // 47:96
+  0x00, 0x65, 0x0A, 0x06,  // 48:101
+  0x00, 0x6F, 0x08, 0x06,  // 49:111
+  0x00, 0x77, 0x0A, 0x06,  // 50:119
+  0x00, 0x81, 0x0A, 0x06,  // 51:129
+  0x00, 0x8B, 0x0B, 0x06,  // 52:139
+  0x00, 0x96, 0x0A, 0x06,  // 53:150
+  0x00, 0xA0, 0x0A, 0x06,  // 54:160
+  0x00, 0xAA, 0x09, 0x06,  // 55:170
+  0x00, 0xB3, 0x0A, 0x06,  // 56:179
+  0x00, 0xBD, 0x0A, 0x06,  // 57:189
+  0x00, 0xC7, 0x04, 0x03,  // 58:199
+  0x00, 0xCB, 0x04, 0x03,  // 59:203
+  0x00, 0xCF, 0x0A, 0x06,  // 60:207
+  0x00, 0xD9, 0x09, 0x06,  // 61:217
+  0x00, 0xE2, 0x09, 0x06,  // 62:226
+  0x00, 0xEB, 0x0B, 0x06,  // 63:235
+  0x00, 0xF6, 0x14, 0x0A,  // 64:246
+  0x01, 0x0A, 0x0E, 0x07,  // 65:266
+  0x01, 0x18, 0x0C, 0x07,  // 66:280
+  0x01, 0x24, 0x0C, 0x07,  // 67:292
+  0x01, 0x30, 0x0B, 0x07,  // 68:304
+  0x01, 0x3B, 0x0C, 0x07,  // 69:315
+  0x01, 0x47, 0x09, 0x06,  // 70:327
+  0x01, 0x50, 0x0D, 0x08,  // 71:336
+  0x01, 0x5D, 0x0C, 0x07,  // 72:349
+  0x01, 0x69, 0x04, 0x03,  // 73:361
+  0x01, 0x6D, 0x08, 0x05,  // 74:365
+  0x01, 0x75, 0x0E, 0x07,  // 75:373
+  0x01, 0x83, 0x0C, 0x06,  // 76:387
+  0x01, 0x8F, 0x10, 0x08,  // 77:399
+  0x01, 0x9F, 0x0C, 0x07,  // 78:415
+  0x01, 0xAB, 0x0E, 0x08,  // 79:427
+  0x01, 0xB9, 0x0B, 0x07,  // 80:441
+  0x01, 0xC4, 0x0E, 0x08,  // 81:452
+  0x01, 0xD2, 0x0C, 0x07,  // 82:466
+  0x01, 0xDE, 0x0C, 0x07,  // 83:478
+  0x01, 0xEA, 0x0B, 0x06,  // 84:490
+  0x01, 0xF5, 0x0C, 0x07,  // 85:501
+  0x02, 0x01, 0x0D, 0x07,  // 86:513
+  0x02, 0x0E, 0x11, 0x09,  // 87:526
+  0x02, 0x1F, 0x0E, 0x07,  // 88:543
+  0x02, 0x2D, 0x0D, 0x07,  // 89:557
+  0x02, 0x3A, 0x0C, 0x06,  // 90:570
+  0x02, 0x46, 0x06, 0x03,  // 91:582
+  0x02, 0x4C, 0x06, 0x03,  // 92:588
+  0x02, 0x52, 0x04, 0x03,  // 93:594
+  0x02, 0x56, 0x09, 0x05,  // 94:598
+  0x02, 0x5F, 0x0C, 0x06,  // 95:607
+  0x02, 0x6B, 0x03, 0x03,  // 96:619
+  0x02, 0x6E, 0x0A, 0x06,  // 97:622
+  0x02, 0x78, 0x0A, 0x06,  // 98:632
+  0x02, 0x82, 0x0A, 0x05,  // 99:642
+  0x02, 0x8C, 0x0A, 0x06,  // 100:652
+  0x02, 0x96, 0x0A, 0x06,  // 101:662
+  0x02, 0xA0, 0x05, 0x03,  // 102:672
+  0x02, 0xA5, 0x0A, 0x06,  // 103:677
+  0x02, 0xAF, 0x0A, 0x06,  // 104:687
+  0x02, 0xB9, 0x04, 0x02,  // 105:697
+  0x02, 0xBD, 0x04, 0x02,  // 106:701
+  0x02, 0xC1, 0x08, 0x05,  // 107:705
+  0x02, 0xC9, 0x04, 0x02,  // 108:713
+  0x02, 0xCD, 0x10, 0x08,  // 109:717
+  0x02, 0xDD, 0x0A, 0x06,  // 110:733
+  0x02, 0xE7, 0x0A, 0x06,  // 111:743
+  0x02, 0xF1, 0x0A, 0x06,  // 112:753
+  0x02, 0xFB, 0x0A, 0x06,  // 113:763
+  0x03, 0x05, 0x05, 0x03,  // 114:773
+  0x03, 0x0A, 0x08, 0x05,  // 115:778
+  0x03, 0x12, 0x06, 0x03,  // 116:786
+  0x03, 0x18, 0x0A, 0x06,  // 117:792
+  0x03, 0x22, 0x09, 0x05,  // 118:802
+  0x03, 0x2B, 0x0E, 0x07,  // 119:811
+  0x03, 0x39, 0x0A, 0x05,  // 120:825
+  0x03, 0x43, 0x09, 0x05,  // 121:835
+  0x03, 0x4C, 0x0A, 0x05,  // 122:844
+  0x03, 0x56, 0x06, 0x03,  // 123:854
+  0x03, 0x5C, 0x04, 0x03,  // 124:860
+  0x03, 0x60, 0x05, 0x03,  // 125:864
+  0x03, 0x65, 0x09, 0x06,  // 126:869
+  0xFF, 0xFF, 0x00, 0x00,  // 127:65535
+  0xFF, 0xFF, 0x00, 0x0A,  // 128:65535
+  0xFF, 0xFF, 0x00, 0x0A,  // 129:65535
+  0xFF, 0xFF, 0x00, 0x0A,  // 130:65535
+  0xFF, 0xFF, 0x00, 0x0A,  // 131:65535
+  0xFF, 0xFF, 0x00, 0x0A,  // 132:65535
+  0xFF, 0xFF, 0x00, 0x0A,  // 133:65535
+  0xFF, 0xFF, 0x00, 0x0A,  // 134:65535
+  0xFF, 0xFF, 0x00, 0x0A,  // 135:65535
+  0xFF, 0xFF, 0x00, 0x0A,  // 136:65535
+  0xFF, 0xFF, 0x00, 0x0A,  // 137:65535
+  0xFF, 0xFF, 0x00, 0x0A,  // 138:65535
+  0xFF, 0xFF, 0x00, 0x0A,  // 139:65535
+  0xFF, 0xFF, 0x00, 0x0A,  // 140:65535
+  0xFF, 0xFF, 0x00, 0x0A,  // 141:65535
+  0xFF, 0xFF, 0x00, 0x0A,  // 142:65535
+  0xFF, 0xFF, 0x00, 0x0A,  // 143:65535
+  0xFF, 0xFF, 0x00, 0x0A,  // 144:65535
+  0xFF, 0xFF, 0x00, 0x0A,  // 145:65535
+  0xFF, 0xFF, 0x00, 0x0A,  // 146:65535
+  0xFF, 0xFF, 0x00, 0x0A,  // 147:65535
+  0xFF, 0xFF, 0x00, 0x0A,  // 148:65535
+  0xFF, 0xFF, 0x00, 0x0A,  // 149:65535
+  0xFF, 0xFF, 0x00, 0x0A,  // 150:65535
+  0xFF, 0xFF, 0x00, 0x0A,  // 151:65535
+  0xFF, 0xFF, 0x00, 0x0A,  // 152:65535
+  0xFF, 0xFF, 0x00, 0x0A,  // 153:65535
+  0xFF, 0xFF, 0x00, 0x0A,  // 154:65535
+  0xFF, 0xFF, 0x00, 0x0A,  // 155:65535
+  0xFF, 0xFF, 0x00, 0x0A,  // 156:65535
+  0xFF, 0xFF, 0x00, 0x0A,  // 157:65535
+  0xFF, 0xFF, 0x00, 0x0A,  // 158:65535
+  0xFF, 0xFF, 0x00, 0x0A,  // 159:65535
+  0xFF, 0xFF, 0x00, 0x03,  // 160:65535
+  0x03, 0x6E, 0x04, 0x03,  // 161:878
+  0x03, 0x72, 0x0A, 0x06,  // 162:882
+  0x03, 0x7C, 0x0C, 0x06,  // 163:892
+  0x03, 0x88, 0x0A, 0x06,  // 164:904
+  0x03, 0x92, 0x0A, 0x06,  // 165:914
+  0x03, 0x9C, 0x04, 0x03,  // 166:924
+  0x03, 0xA0, 0x0A, 0x06,  // 167:928
+  0x03, 0xAA, 0x05, 0x03,  // 168:938
+  0x03, 0xAF, 0x0D, 0x07,  // 169:943
+  0x03, 0xBC, 0x07, 0x04,  // 170:956
+  0x03, 0xC3, 0x0A, 0x06,  // 171:963
+  0x03, 0xCD, 0x09, 0x06,  // 172:973
+  0x03, 0xD6, 0x03, 0x03,  // 173:982
+  0x03, 0xD9, 0x0D, 0x07,  // 174:985
+  0x03, 0xE6, 0x0B, 0x06,  // 175:998
+  0x03, 0xF1, 0x07, 0x04,  // 176:1009
+  0x03, 0xF8, 0x0A, 0x05,  // 177:1016
+  0x04, 0x02, 0x05, 0x03,  // 178:1026
+  0x04, 0x07, 0x05, 0x03,  // 179:1031
+  0x04, 0x0C, 0x05, 0x03,  // 180:1036
+  0x04, 0x11, 0x0A, 0x06,  // 181:1041
+  0x04, 0x1B, 0x09, 0x05,  // 182:1051
+  0x04, 0x24, 0x03, 0x03,  // 183:1060
+  0x04, 0x27, 0x06, 0x03,  // 184:1063
+  0x04, 0x2D, 0x05, 0x03,  // 185:1069
+  0x04, 0x32, 0x07, 0x04,  // 186:1074
+  0x04, 0x39, 0x0A, 0x06,  // 187:1081
+  0x04, 0x43, 0x10, 0x08,  // 188:1091
+  0x04, 0x53, 0x10, 0x08,  // 189:1107
+  0x04, 0x63, 0x10, 0x08,  // 190:1123
+  0x04, 0x73, 0x0A, 0x06,  // 191:1139
+  0x04, 0x7D, 0x0E, 0x07,  // 192:1149
+  0x04, 0x8B, 0x0E, 0x07,  // 193:1163
+  0x04, 0x99, 0x0E, 0x07,  // 194:1177
+  0x04, 0xA7, 0x0E, 0x07,  // 195:1191
+  0x04, 0xB5, 0x0E, 0x07,  // 196:1205
+  0x04, 0xC3, 0x0E, 0x07,  // 197:1219
+  0x04, 0xD1, 0x12, 0x0A,  // 198:1233
+  0x04, 0xE3, 0x0C, 0x07,  // 199:1251
+  0x04, 0xEF, 0x0C, 0x07,  // 200:1263
+  0x04, 0xFB, 0x0C, 0x07,  // 201:1275
+  0x05, 0x07, 0x0C, 0x07,  // 202:1287
+  0x05, 0x13, 0x0C, 0x07,  // 203:1299
+  0x05, 0x1F, 0x05, 0x03,  // 204:1311
+  0x05, 0x24, 0x04, 0x03,  // 205:1316
+  0x05, 0x28, 0x04, 0x03,  // 206:1320
+  0x05, 0x2C, 0x05, 0x03,  // 207:1324
+  0x05, 0x31, 0x0B, 0x07,  // 208:1329
+  0x05, 0x3C, 0x0C, 0x07,  // 209:1340
+  0x05, 0x48, 0x0E, 0x08,  // 210:1352
+  0x05, 0x56, 0x0E, 0x08,  // 211:1366
+  0x05, 0x64, 0x0E, 0x08,  // 212:1380
+  0x05, 0x72, 0x0E, 0x08,  // 213:1394
+  0x05, 0x80, 0x0E, 0x08,  // 214:1408
+  0x05, 0x8E, 0x0A, 0x06,  // 215:1422
+  0x05, 0x98, 0x0D, 0x08,  // 216:1432
+  0x05, 0xA5, 0x0C, 0x07,  // 217:1445
+  0x05, 0xB1, 0x0C, 0x07,  // 218:1457
+  0x05, 0xBD, 0x0C, 0x07,  // 219:1469
+  0x05, 0xC9, 0x0C, 0x07,  // 220:1481
+  0x05, 0xD5, 0x0D, 0x07,  // 221:1493
+  0x05, 0xE2, 0x0B, 0x07,  // 222:1506
+  0x05, 0xED, 0x0C, 0x06,  // 223:1517
+  0x05, 0xF9, 0x0A, 0x06,  // 224:1529
+  0x06, 0x03, 0x0A, 0x06,  // 225:1539
+  0x06, 0x0D, 0x0A, 0x06,  // 226:1549
+  0x06, 0x17, 0x0A, 0x06,  // 227:1559
+  0x06, 0x21, 0x0A, 0x06,  // 228:1569
+  0x06, 0x2B, 0x0A, 0x06,  // 229:1579
+  0x06, 0x35, 0x10, 0x09,  // 230:1589
+  0x06, 0x45, 0x0A, 0x05,  // 231:1605
+  0x06, 0x4F, 0x0A, 0x06,  // 232:1615
+  0x06, 0x59, 0x0A, 0x06,  // 233:1625
+  0x06, 0x63, 0x0A, 0x06,  // 234:1635
+  0x06, 0x6D, 0x0A, 0x06,  // 235:1645
+  0x06, 0x77, 0x05, 0x03,  // 236:1655
+  0x06, 0x7C, 0x04, 0x03,  // 237:1660
+  0x06, 0x80, 0x05, 0x03,  // 238:1664
+  0x06, 0x85, 0x05, 0x03,  // 239:1669
+  0x06, 0x8A, 0x0A, 0x06,  // 240:1674
+  0x06, 0x94, 0x0A, 0x06,  // 241:1684
+  0x06, 0x9E, 0x0A, 0x06,  // 242:1694
+  0x06, 0xA8, 0x0A, 0x06,  // 243:1704
+  0x06, 0xB2, 0x0A, 0x06,  // 244:1714
+  0x06, 0xBC, 0x0A, 0x06,  // 245:1724
+  0x06, 0xC6, 0x0A, 0x06,  // 246:1734
+  0x06, 0xD0, 0x09, 0x05,  // 247:1744
+  0x06, 0xD9, 0x0A, 0x06,  // 248:1753
+  0x06, 0xE3, 0x0A, 0x06,  // 249:1763
+  0x06, 0xED, 0x0A, 0x06,  // 250:1773
+  0x06, 0xF7, 0x0A, 0x06,  // 251:1783
+  0x07, 0x01, 0x0A, 0x06,  // 252:1793
+  0x07, 0x0B, 0x09, 0x05,  // 253:1803
+  0x07, 0x14, 0x0A, 0x06,  // 254:1812
+  0x07, 0x1E, 0x09, 0x05,  // 255:1822
+
+  // Font Data:
+  0x00,0x00,0xF8,0x02,  // 33
+  0x38,0x00,0x00,0x00,0x38, // 34
+  0xA0,0x03,0xE0,0x00,0xB8,0x03,0xE0,0x00,0xB8, // 35
+  0x30,0x01,0x28,0x02,0xF8,0x07,0x48,0x02,0x90,0x01,  // 36
+  0x00,0x00,0x30,0x00,0x48,0x00,0x30,0x03,0xC0,0x00,0xB0,0x01,0x48,0x02,0x80,0x01,  // 37
+  0x80,0x01,0x50,0x02,0x68,0x02,0xA8,0x02,0x18,0x01,0x80,0x03,0x80,0x02,  // 38
+  0x38, // 39
+  0xE0,0x03,0x10,0x04,0x08,0x08,  // 40
+  0x08,0x08,0x10,0x04,0xE0,0x03,  // 41
+  0x28,0x00,0x18,0x00,0x28, // 42
+  0x40,0x00,0x40,0x00,0xF0,0x01,0x40,0x00,0x40, // 43
+  0x00,0x00,0x00,0x06,  // 44
+  0x80,0x00,0x80, // 45
+  0x00,0x00,0x00,0x02,  // 46
+  0x00,0x03,0xE0,0x00,0x18, // 47
+  0xF0,0x01,0x08,0x02,0x08,0x02,0x08,0x02,0xF0,0x01,  // 48
+  0x00,0x00,0x20,0x00,0x10,0x00,0xF8,0x03,  // 49
+  0x10,0x02,0x08,0x03,0x88,0x02,0x48,0x02,0x30,0x02,  // 50
+  0x10,0x01,0x08,0x02,0x48,0x02,0x48,0x02,0xB0,0x01,  // 51
+  0xC0,0x00,0xA0,0x00,0x90,0x00,0x88,0x00,0xF8,0x03,0x80, // 52
+  0x60,0x01,0x38,0x02,0x28,0x02,0x28,0x02,0xC8,0x01,  // 53
+  0xF0,0x01,0x28,0x02,0x28,0x02,0x28,0x02,0xD0,0x01,  // 54
+  0x08,0x00,0x08,0x03,0xC8,0x00,0x38,0x00,0x08, // 55
+  0xB0,0x01,0x48,0x02,0x48,0x02,0x48,0x02,0xB0,0x01,  // 56
+  0x70,0x01,0x88,0x02,0x88,0x02,0x88,0x02,0xF0,0x01,  // 57
+  0x00,0x00,0x20,0x02,  // 58
+  0x00,0x00,0x20,0x06,  // 59
+  0x00,0x00,0x40,0x00,0xA0,0x00,0xA0,0x00,0x10,0x01,  // 60
+  0xA0,0x00,0xA0,0x00,0xA0,0x00,0xA0,0x00,0xA0, // 61
+  0x00,0x00,0x10,0x01,0xA0,0x00,0xA0,0x00,0x40, // 62
+  0x10,0x00,0x08,0x00,0x08,0x00,0xC8,0x02,0x48,0x00,0x30, // 63
+  0x00,0x00,0xC0,0x03,0x30,0x04,0xD0,0x09,0x28,0x0A,0x28,0x0A,0xC8,0x0B,0x68,0x0A,0x10,0x05,0xE0,0x04,  // 64
+  0x00,0x02,0xC0,0x01,0xB0,0x00,0x88,0x00,0xB0,0x00,0xC0,0x01,0x00,0x02,  // 65
+  0x00,0x00,0xF8,0x03,0x48,0x02,0x48,0x02,0x48,0x02,0xF0,0x01,  // 66
+  0x00,0x00,0xF0,0x01,0x08,0x02,0x08,0x02,0x08,0x02,0x10,0x01,  // 67
+  0x00,0x00,0xF8,0x03,0x08,0x02,0x08,0x02,0x10,0x01,0xE0, // 68
+  0x00,0x00,0xF8,0x03,0x48,0x02,0x48,0x02,0x48,0x02,0x48,0x02,  // 69
+  0x00,0x00,0xF8,0x03,0x48,0x00,0x48,0x00,0x08, // 70
+  0x00,0x00,0xE0,0x00,0x10,0x01,0x08,0x02,0x48,0x02,0x50,0x01,0xC0, // 71
+  0x00,0x00,0xF8,0x03,0x40,0x00,0x40,0x00,0x40,0x00,0xF8,0x03,  // 72
+  0x00,0x00,0xF8,0x03,  // 73
+  0x00,0x03,0x00,0x02,0x00,0x02,0xF8,0x01,  // 74
+  0x00,0x00,0xF8,0x03,0x80,0x00,0x60,0x00,0x90,0x00,0x08,0x01,0x00,0x02,  // 75
+  0x00,0x00,0xF8,0x03,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02,  // 76
+  0x00,0x00,0xF8,0x03,0x30,0x00,0xC0,0x01,0x00,0x02,0xC0,0x01,0x30,0x00,0xF8,0x03,  // 77
+  0x00,0x00,0xF8,0x03,0x30,0x00,0x40,0x00,0x80,0x01,0xF8,0x03,  // 78
+  0x00,0x00,0xF0,0x01,0x08,0x02,0x08,0x02,0x08,0x02,0x08,0x02,0xF0,0x01,  // 79
+  0x00,0x00,0xF8,0x03,0x48,0x00,0x48,0x00,0x48,0x00,0x30, // 80
+  0x00,0x00,0xF0,0x01,0x08,0x02,0x08,0x02,0x08,0x03,0x08,0x03,0xF0,0x02,  // 81
+  0x00,0x00,0xF8,0x03,0x48,0x00,0x48,0x00,0xC8,0x00,0x30,0x03,  // 82
+  0x00,0x00,0x30,0x01,0x48,0x02,0x48,0x02,0x48,0x02,0x90,0x01,  // 83
+  0x00,0x00,0x08,0x00,0x08,0x00,0xF8,0x03,0x08,0x00,0x08, // 84
+  0x00,0x00,0xF8,0x01,0x00,0x02,0x00,0x02,0x00,0x02,0xF8,0x01,  // 85
+  0x08,0x00,0x70,0x00,0x80,0x01,0x00,0x02,0x80,0x01,0x70,0x00,0x08, // 86
+  0x18,0x00,0xE0,0x01,0x00,0x02,0xF0,0x01,0x08,0x00,0xF0,0x01,0x00,0x02,0xE0,0x01,0x18, // 87
+  0x00,0x02,0x08,0x01,0x90,0x00,0x60,0x00,0x90,0x00,0x08,0x01,0x00,0x02,  // 88
+  0x08,0x00,0x10,0x00,0x20,0x00,0xC0,0x03,0x20,0x00,0x10,0x00,0x08, // 89
+  0x08,0x03,0x88,0x02,0xC8,0x02,0x68,0x02,0x38,0x02,0x18,0x02,  // 90
+  0x00,0x00,0xF8,0x0F,0x08,0x08,  // 91
+  0x18,0x00,0xE0,0x00,0x00,0x03,  // 92
+  0x08,0x08,0xF8,0x0F,  // 93
+  0x40,0x00,0x30,0x00,0x08,0x00,0x30,0x00,0x40, // 94
+  0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,  // 95
+  0x08,0x00,0x10, // 96
+  0x00,0x00,0x00,0x03,0xA0,0x02,0xA0,0x02,0xE0,0x03,  // 97
+  0x00,0x00,0xF8,0x03,0x20,0x02,0x20,0x02,0xC0,0x01,  // 98
+  0x00,0x00,0xC0,0x01,0x20,0x02,0x20,0x02,0x40,0x01,  // 99
+  0x00,0x00,0xC0,0x01,0x20,0x02,0x20,0x02,0xF8,0x03,  // 100
+  0x00,0x00,0xC0,0x01,0xA0,0x02,0xA0,0x02,0xC0,0x02,  // 101
+  0x20,0x00,0xF0,0x03,0x28, // 102
+  0x00,0x00,0xC0,0x05,0x20,0x0A,0x20,0x0A,0xE0,0x07,  // 103
+  0x00,0x00,0xF8,0x03,0x20,0x00,0x20,0x00,0xC0,0x03,  // 104
+  0x00,0x00,0xE8,0x03,  // 105
+  0x00,0x08,0xE8,0x07,  // 106
+  0xF8,0x03,0x80,0x00,0xC0,0x01,0x20,0x02,  // 107
+  0x00,0x00,0xF8,0x03,  // 108
+  0x00,0x00,0xE0,0x03,0x20,0x00,0x20,0x00,0xE0,0x03,0x20,0x00,0x20,0x00,0xC0,0x03,  // 109
+  0x00,0x00,0xE0,0x03,0x20,0x00,0x20,0x00,0xC0,0x03,  // 110
+  0x00,0x00,0xC0,0x01,0x20,0x02,0x20,0x02,0xC0,0x01,  // 111
+  0x00,0x00,0xE0,0x0F,0x20,0x02,0x20,0x02,0xC0,0x01,  // 112
+  0x00,0x00,0xC0,0x01,0x20,0x02,0x20,0x02,0xE0,0x0F,  // 113
+  0x00,0x00,0xE0,0x03,0x20, // 114
+  0x40,0x02,0xA0,0x02,0xA0,0x02,0x20,0x01,  // 115
+  0x20,0x00,0xF8,0x03,0x20,0x02,  // 116
+  0x00,0x00,0xE0,0x01,0x00,0x02,0x00,0x02,0xE0,0x03,  // 117
+  0x20,0x00,0xC0,0x01,0x00,0x02,0xC0,0x01,0x20, // 118
+  0xE0,0x01,0x00,0x02,0xC0,0x01,0x20,0x00,0xC0,0x01,0x00,0x02,0xE0,0x01,  // 119
+  0x20,0x02,0x40,0x01,0x80,0x00,0x40,0x01,0x20,0x02,  // 120
+  0x20,0x00,0xC0,0x09,0x00,0x06,0xC0,0x01,0x20, // 121
+  0x20,0x02,0x20,0x03,0xA0,0x02,0x60,0x02,0x20,0x02,  // 122
+  0x80,0x00,0x78,0x0F,0x08,0x08,  // 123
+  0x00,0x00,0xF8,0x0F,  // 124
+  0x08,0x08,0x78,0x0F,0x80, // 125
+  0xC0,0x00,0x40,0x00,0xC0,0x00,0x80,0x00,0xC0, // 126
+  0x00,0x00,0xA0,0x0F,  // 161
+  0x00,0x00,0xC0,0x01,0xA0,0x0F,0x78,0x02,0x40,0x01,  // 162
+  0x40,0x02,0x70,0x03,0xC8,0x02,0x48,0x02,0x08,0x02,0x10,0x02,  // 163
+  0x00,0x00,0xE0,0x01,0x20,0x01,0x20,0x01,0xE0,0x01,  // 164
+  0x48,0x01,0x70,0x01,0xC0,0x03,0x70,0x01,0x48,0x01,  // 165
+  0x00,0x00,0x38,0x0F,  // 166
+  0xD0,0x04,0x28,0x09,0x48,0x09,0x48,0x0A,0x90,0x05,  // 167
+  0x08,0x00,0x00,0x00,0x08, // 168
+  0xE0,0x00,0x10,0x01,0x48,0x02,0xA8,0x02,0xA8,0x02,0x10,0x01,0xE0, // 169
+  0x68,0x00,0x68,0x00,0x68,0x00,0x78, // 170
+  0x00,0x00,0x80,0x01,0x40,0x02,0x80,0x01,0x40,0x02,  // 171
+  0x20,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0xE0, // 172
+  0x80,0x00,0x80, // 173
+  0xE0,0x00,0x10,0x01,0xE8,0x02,0x68,0x02,0xC8,0x02,0x10,0x01,0xE0, // 174
+  0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02, // 175
+  0x00,0x00,0x38,0x00,0x28,0x00,0x38, // 176
+  0x40,0x02,0x40,0x02,0xF0,0x03,0x40,0x02,0x40,0x02,  // 177
+  0x48,0x00,0x68,0x00,0x58, // 178
+  0x48,0x00,0x58,0x00,0x68, // 179
+  0x00,0x00,0x10,0x00,0x08, // 180
+  0x00,0x00,0xE0,0x0F,0x00,0x02,0x00,0x02,0xE0,0x03,  // 181
+  0x70,0x00,0xF8,0x0F,0x08,0x00,0xF8,0x0F,0x08, // 182
+  0x00,0x00,0x40, // 183
+  0x00,0x00,0x00,0x14,0x00,0x18,  // 184
+  0x00,0x00,0x10,0x00,0x78, // 185
+  0x30,0x00,0x48,0x00,0x48,0x00,0x30, // 186
+  0x00,0x00,0x40,0x02,0x80,0x01,0x40,0x02,0x80,0x01,  // 187
+  0x00,0x00,0x10,0x02,0x78,0x01,0xC0,0x00,0x20,0x01,0x90,0x01,0xC8,0x03,0x00,0x01,  // 188
+  0x00,0x00,0x10,0x02,0x78,0x01,0x80,0x00,0x60,0x00,0x50,0x02,0x48,0x03,0xC0,0x02,  // 189
+  0x48,0x00,0x58,0x00,0x68,0x03,0x80,0x00,0x60,0x01,0x90,0x01,0xC8,0x03,0x00,0x01,  // 190
+  0x00,0x00,0x00,0x06,0x00,0x09,0xA0,0x09,0x00,0x04,  // 191
+  0x00,0x02,0xC0,0x01,0xB0,0x00,0x89,0x00,0xB2,0x00,0xC0,0x01,0x00,0x02,  // 192
+  0x00,0x02,0xC0,0x01,0xB0,0x00,0x8A,0x00,0xB1,0x00,0xC0,0x01,0x00,0x02,  // 193
+  0x00,0x02,0xC0,0x01,0xB2,0x00,0x89,0x00,0xB2,0x00,0xC0,0x01,0x00,0x02,  // 194
+  0x00,0x02,0xC2,0x01,0xB1,0x00,0x8A,0x00,0xB1,0x00,0xC0,0x01,0x00,0x02,  // 195
+  0x00,0x02,0xC0,0x01,0xB2,0x00,0x88,0x00,0xB2,0x00,0xC0,0x01,0x00,0x02,  // 196
+  0x00,0x02,0xC0,0x01,0xBE,0x00,0x8A,0x00,0xBE,0x00,0xC0,0x01,0x00,0x02,  // 197
+  0x00,0x03,0xC0,0x00,0xE0,0x00,0x98,0x00,0x88,0x00,0xF8,0x03,0x48,0x02,0x48,0x02,0x48,0x02,  // 198
+  0x00,0x00,0xF0,0x01,0x08,0x02,0x08,0x16,0x08,0x1A,0x10,0x01,  // 199
+  0x00,0x00,0xF8,0x03,0x49,0x02,0x4A,0x02,0x48,0x02,0x48,0x02,  // 200
+  0x00,0x00,0xF8,0x03,0x48,0x02,0x4A,0x02,0x49,0x02,0x48,0x02,  // 201
+  0x00,0x00,0xFA,0x03,0x49,0x02,0x4A,0x02,0x48,0x02,0x48,0x02,  // 202
+  0x00,0x00,0xF8,0x03,0x4A,0x02,0x48,0x02,0x4A,0x02,0x48,0x02,  // 203
+  0x00,0x00,0xF9,0x03,0x02, // 204
+  0x02,0x00,0xF9,0x03,  // 205
+  0x01,0x00,0xFA,0x03,  // 206
+  0x02,0x00,0xF8,0x03,0x02, // 207
+  0x40,0x00,0xF8,0x03,0x48,0x02,0x48,0x02,0x10,0x01,0xE0, // 208
+  0x00,0x00,0xFA,0x03,0x31,0x00,0x42,0x00,0x81,0x01,0xF8,0x03,  // 209
+  0x00,0x00,0xF0,0x01,0x08,0x02,0x09,0x02,0x0A,0x02,0x08,0x02,0xF0,0x01,  // 210
+  0x00,0x00,0xF0,0x01,0x08,0x02,0x0A,0x02,0x09,0x02,0x08,0x02,0xF0,0x01,  // 211
+  0x00,0x00,0xF0,0x01,0x08,0x02,0x0A,0x02,0x09,0x02,0x0A,0x02,0xF0,0x01,  // 212
+  0x00,0x00,0xF0,0x01,0x0A,0x02,0x09,0x02,0x0A,0x02,0x09,0x02,0xF0,0x01,  // 213
+  0x00,0x00,0xF0,0x01,0x0A,0x02,0x08,0x02,0x0A,0x02,0x08,0x02,0xF0,0x01,  // 214
+  0x10,0x01,0xA0,0x00,0xE0,0x00,0xA0,0x00,0x10,0x01,  // 215
+  0x00,0x00,0xF0,0x02,0x08,0x03,0xC8,0x02,0x28,0x02,0x18,0x03,0xE8, // 216
+  0x00,0x00,0xF8,0x01,0x01,0x02,0x02,0x02,0x00,0x02,0xF8,0x01,  // 217
+  0x00,0x00,0xF8,0x01,0x02,0x02,0x01,0x02,0x00,0x02,0xF8,0x01,  // 218
+  0x00,0x00,0xF8,0x01,0x02,0x02,0x01,0x02,0x02,0x02,0xF8,0x01,  // 219
+  0x00,0x00,0xF8,0x01,0x02,0x02,0x00,0x02,0x02,0x02,0xF8,0x01,  // 220
+  0x08,0x00,0x10,0x00,0x20,0x00,0xC2,0x03,0x21,0x00,0x10,0x00,0x08, // 221
+  0x00,0x00,0xF8,0x03,0x10,0x01,0x10,0x01,0x10,0x01,0xE0, // 222
+  0x00,0x00,0xF0,0x03,0x08,0x01,0x48,0x02,0xB0,0x02,0x80,0x01,  // 223
+  0x00,0x00,0x00,0x03,0xA4,0x02,0xA8,0x02,0xE0,0x03,  // 224
+  0x00,0x00,0x00,0x03,0xA8,0x02,0xA4,0x02,0xE0,0x03,  // 225
+  0x00,0x00,0x00,0x03,0xA8,0x02,0xA4,0x02,0xE8,0x03,  // 226
+  0x00,0x00,0x08,0x03,0xA4,0x02,0xA8,0x02,0xE4,0x03,  // 227
+  0x00,0x00,0x00,0x03,0xA8,0x02,0xA0,0x02,0xE8,0x03,  // 228
+  0x00,0x00,0x00,0x03,0xAE,0x02,0xAA,0x02,0xEE,0x03,  // 229
+  0x00,0x00,0x40,0x03,0xA0,0x02,0xA0,0x02,0xC0,0x01,0xA0,0x02,0xA0,0x02,0xC0,0x02,  // 230
+  0x00,0x00,0xC0,0x01,0x20,0x16,0x20,0x1A,0x40,0x01,  // 231
+  0x00,0x00,0xC0,0x01,0xA4,0x02,0xA8,0x02,0xC0,0x02,  // 232
+  0x00,0x00,0xC0,0x01,0xA8,0x02,0xA4,0x02,0xC0,0x02,  // 233
+  0x00,0x00,0xC0,0x01,0xA8,0x02,0xA4,0x02,0xC8,0x02,  // 234
+  0x00,0x00,0xC0,0x01,0xA8,0x02,0xA0,0x02,0xC8,0x02,  // 235
+  0x00,0x00,0xE4,0x03,0x08, // 236
+  0x08,0x00,0xE4,0x03,  // 237
+  0x08,0x00,0xE4,0x03,0x08, // 238
+  0x08,0x00,0xE0,0x03,0x08, // 239
+  0x00,0x00,0xC0,0x01,0x28,0x02,0x38,0x02,0xE0,0x01,  // 240
+  0x00,0x00,0xE8,0x03,0x24,0x00,0x28,0x00,0xC4,0x03,  // 241
+  0x00,0x00,0xC0,0x01,0x24,0x02,0x28,0x02,0xC0,0x01,  // 242
+  0x00,0x00,0xC0,0x01,0x28,0x02,0x24,0x02,0xC0,0x01,  // 243
+  0x00,0x00,0xC0,0x01,0x28,0x02,0x24,0x02,0xC8,0x01,  // 244
+  0x00,0x00,0xC8,0x01,0x24,0x02,0x28,0x02,0xC4,0x01,  // 245
+  0x00,0x00,0xC0,0x01,0x28,0x02,0x20,0x02,0xC8,0x01,  // 246
+  0x40,0x00,0x40,0x00,0x50,0x01,0x40,0x00,0x40, // 247
+  0x00,0x00,0xC0,0x02,0xA0,0x03,0x60,0x02,0xA0,0x01,  // 248
+  0x00,0x00,0xE0,0x01,0x04,0x02,0x08,0x02,0xE0,0x03,  // 249
+  0x00,0x00,0xE0,0x01,0x08,0x02,0x04,0x02,0xE0,0x03,  // 250
+  0x00,0x00,0xE8,0x01,0x04,0x02,0x08,0x02,0xE0,0x03,  // 251
+  0x00,0x00,0xE0,0x01,0x08,0x02,0x00,0x02,0xE8,0x03,  // 252
+  0x20,0x00,0xC0,0x09,0x08,0x06,0xC4,0x01,0x20, // 253
+  0x00,0x00,0xF8,0x0F,0x20,0x02,0x20,0x02,0xC0,0x01,  // 254
+  0x20,0x00,0xC8,0x09,0x00,0x06,0xC8,0x01,0x20  // 255
+};        
+      </textarea>
+      <button id="parse">Parse</button>
+    </div>
+    <script>
+    (function() {
+      // This page allows drawing icons in grids and generating the map with the format required by 
+      // library for OLED SD1306 screen: https://github.com/squix78/esp8266-oled-ssd1306
+      // 100% quick and dirty vanilla ECS6, no framework or library was injured for this project.
+     
+      // TODO: 
+      // Implement data parsing to edit existing font: from char array data to pixels matrix
+      // Implement methods to move glyphs in their matrix, copy one from another, symetrical input, ...
+      // Implement char insertion, non displayable char (?), ...
+      // Submit PR to original project.
+      
+      let font;
+      class Font {
+        constructor() {
+          this.height = parseInt(document.getElementById('height').value);
+          this.width = parseInt(document.getElementById('width').value);
+          this.firstCharCode = parseInt(document.getElementById('code').value);
+          this.currentCharCode = this.firstCharCode;
+          this.chars = [];
+          this.jumpMap = [];
+          this.fontContainer = document.getElementById('chars');
+        }
+        
+        // Should we have a Char and a Pixel class ? not sure it's worth it.
+        // Let's use the DOM to store everything for now
+        
+        // Add a pixel matrix to draw a new character
+        addChar(jumpData, charData) {         
+          let charContainer = this.fontContainer.appendChild(document.createElement("table"));
+          charContainer.setAttribute("code", this.currentCharCode);
+          let header = charContainer.appendChild(document.createElement("th"));
+          header.setAttribute("colspan", this.width-1);
+          // Non displayable characters 
+          if (charData && !charData.length) {
+            header.textContent = `No character ${this.currentCharCode}`;
+            return;
+          } else {
+            header.textContent = `Character ${this.currentCharCode}`;
+          }
+          let deletePixels = charContainer.appendChild(document.createElement("th"));
+          deletePixels.setAttribute("action", "remove");
+          deletePixels.textContent = "x";
+          deletePixels.addEventListener('click', function() {
+            let result = confirm("Delete the pixels ?");
+            if(result) {
+              let pixels = charContainer.getElementsByTagName('td');
+              for(let p = 0; p < pixels.length; p++) {
+                pixels[p].className = '';
+              }
+            } 
+          });
+          // If data is provided, decode it to pixel initialization structure
+          let pixelInit = [];
+          if (charData && charData.length) {
+            
+            
+          }
+          
+          for(let r = 0; r < this.height; r++) {
+          	let rowContainer = charContainer.appendChild(document.createElement("tr"));
+            for(let c = 0; c < this.width; c++) {
+          		let pixContainer = rowContainer.appendChild(document.createElement("td"));
+            }
+          }
+          this.currentCharCode++;
+        }
+        
+        static togglePixel(pixel) {
+          pixel.className = pixel.className === 'on' ? '': 'on';
+        }
+        
+        // Return anInt as hex string
+        static toHexString(anInt) {
+          return `0x${anInt.toString(16)}`
+        }
+        
+        // Return least significant byte as hex string
+        static getLsB(anInt) {
+          return Font.toHexString(anInt & 0xFF);      
+        }
+        // Return most significant byte as hex string
+        static getMsB(anInt) {
+          return Font.toHexString(anInt>>>8);      
+        }
+       
+        static output(targetId, msg) {
+          let output = document.getElementById(targetId);
+          let line = output.appendChild(document.createElement('div'));
+          line.textContent = msg;
+        }
+        
+        // Read from the <td> css class the pixels that need to be on
+        // generates the jump table and font data 
+        generate() {
+          document.getElementById('header').textContent = '';
+          document.getElementById('jump').textContent = '';
+          document.getElementById('data').textContent = '';
+          let name = document.getElementById('name').value.replace(/[^a-zA-Z0-9_\$]/g, '_');
+          let byteCount = (1 + ((this.height - 1) >> 3));  // number of bytes needed for this font height
+          let bits2add = byteCount*8 - this.height;  // number of missing bits to fill leftmost byte
+          let chars = this.fontContainer.getElementsByTagName('table');
+          let charCount = chars.length;
+          let charAddr = 0;
+          // Comments are used when parsing back a generated font
+          Font.output('jump', '  // Jump Table:');
+          Font.output('data', '  // Font Data:');
+          // Browse each character
+          for(let ch = 0; ch < charCount; ch++) {
+            let charBytes = [];
+            let charBits = [];
+            let charWidth = 1; // always add one row of off pixels to the right ?
+            let rows = chars[ch].getElementsByTagName('tr');
+            // Browse each column
+            for(let col = 0; col < this.width ; col++) {
+              let bits = ""; // using string because js uses 32b ints when performing bit operations
+              // Browse each row starting from the bottom one, going up, and accumulate pixels in
+              // a string: this rotates the glyph
+              for(let r = rows.length-1; r >=0 ; r--) {
+                let pixelState = rows[r].children[col].className;
+                bits += (pixelState === 'on' ? '1': '0');           
+              }
+              
+              // Need to complete missing bits to have a sizeof byte multiple number of bits
+              for(let b = 0; b < bits2add; b++) {
+                bits +=  '0';
+              }
+              Font.output('data', `  // ${bits}`);  // Debugging help: rotated bitmap
+
+              // read bytes from the end
+              for(let b = bits.length - 1; b >= 7; b -= 8) {
+                //Font.output('data', `  // ${bits.substring(b-7, b)}`);  // Debugging help: rotated bitmap
+                let byte = parseInt(bits.substring(b-8, b), 2);
+                charBytes.push(Font.toHexString(byte));
+              } 
+            }
+            // Remove bytes with value 0 at the end of the array.
+            while(charBytes[charBytes.length-1] === '0x0' && charBytes.length != 1) {
+              charBytes.pop();
+            }
+            
+            Font.output('data', `  ${charBytes.join(',')},`);
+            // TODO: last param width is not the best value. Need to compute the actual occupied width
+            Font.output('jump', `  ${Font.getMsB(charAddr)}, ${Font.getLsB(charAddr)}, ${Font.toHexString(charBytes.length)}, ${Font.toHexString(this.width)}, `);
+            charAddr += charBytes.length;                                           
+          }
+          Font.output('data', '};');
+          
+          Font.output('header', `const char ${name}[] PROGMEM = {`);
+          // Comments are used when parsing back a generated font
+          Font.output('header', `  ${Font.toHexString(this.width)}, // Width: ${this.width}`);
+          Font.output('header', `  ${Font.toHexString(this.height)}, // Height: ${this.height}`);          
+          Font.output('header', `  ${Font.toHexString(this.firstCharCode)}, // First char: ${this.firstCharCode}`);
+          Font.output('header', `  ${Font.toHexString(charCount)}, // Number of chars: ${charCount}`);
+        }
+      }
+      
+     
+      document.getElementById('generate').addEventListener('click', function() {
+        font.generate();
+      });
+      
+      document.getElementById('addChar').addEventListener('click', function() {
+        font.addChar();
+      });
+      document.getElementById('chars').addEventListener('mousedown', function(e) {
+        let target = e.target;
+        if (target.nodeName !== 'TD') return;
+        Font.togglePixel(target);
+      });
+      document.getElementById('chars').addEventListener('mouseover', function(e) {
+        let target = e.target;
+        if (target.nodeName !== 'TD' || e.buttons !== 1) return;
+        Font.togglePixel(target);
+      });
+      document.getElementById('chars').addEventListener('dragstart', function(e) {
+        return false;
+      });
+
+      document.getElementById('create').addEventListener('click', function(button) {
+        document.body.className = "started";      
+      	font = new Font();
+        font.addChar();
+      });
+
+      // parse a char array declaration for an existing font.
+      // parsing heavily relies on comments.
+      document.getElementById('parse').addEventListener('click', function(e) {
+        let lines = document.getElementById('inputText').value.split('\n');
+        let name = '';
+        let height = 0;
+        let width = 0;
+        let firstCharCode = 0;
+        let jumpTable = [];
+        let charData = [];
+        let readingJumpTable = false;
+        let readingData = false;
+        
+        for(let l = 0 ; l < lines.length; l++) {
+          // TODO ? keep C compilation directives to copy them (not lowercased :)) to newly generated char array
+          let line = lines[l].trim();
+          //alert(line);
+          let fields;
+
+          // Declaration line: grab the name
+          if (line.indexOf('PROGMEM') > 0) {
+            fields = line.split(' ');
+            name = fields[2];
+            continue;
+          }
+          line = line.toLowerCase();
+          // Todo: could rely on line order...
+          // width line: grab the width
+          if (line.indexOf('width') > 0) {
+            fields = line.split(',');
+            width = fields[0];
+            continue;
+          }
+          // height line: grab the height 
+          if (line.indexOf('height') > 0) {
+            fields = line.split(',');
+            height = fields[0];
+            continue;
+          }
+          // first char code line: grab the first char code 
+          if (line.indexOf('first char') > 0) {
+            fields = line.split(',');
+            firstCharCode = fields[0];
+            continue;
+          }
+          // End of array declaration
+          // TODO warn if more lines: next fonts are ignored
+          if (line.indexOf('};') === 0) {
+            break;
+            alert(l);
+          }
+          
+          if (readingJumpTable || readingData) {
+            if (line.indexOf('#') !== 0 && line.length !== 0 && line.indexOf('//') !== 0) {
+              line = line.replace(/\/\/.*/, ''); // get rid of end of line comments
+              fields = line.split(',');
+              let newEntry = [];
+              for(let f=0; f < fields.length; f++) {
+                if (readingData) {
+                  charData.push(parseInt(fields[f]));
+                }
+                if (readingJumpTable) {
+                  newEntry.push(parseInt(fields[f]));
+                }
+              }
+              if (readingJumpTable) {
+                jumpTable.push(newEntry);
+              }
+            }            
+          }
+          
+          // Begining of data
+          if (line.indexOf('font data') > 0) {
+            readingData = true;
+            readingJumpTable = false;
+            alert(line);
+          }
+          // Begining of jump table
+          if (line.indexOf('jump table') > 0) {
+            readingJumpTable = true;
+            alert(line);
+          }
+        }
+        document.getElementById('name').value = name;
+        document.getElementById('height').value = parseInt(height);
+        document.getElementById('width').value = parseInt(width);
+        document.getElementById('code').value = parseInt(firstCharCode);
+      	font = new Font();
+      	for(let c = 0 ; c < jumpTable.length; c++) {
+      	  let jumpEntry = jumpTable[c];
+      	  let charEntry = [];
+      	  // displayable character 
+      	  if (jumpEntry[0] !== 255 || jumpEntry[1] !== 255) {
+      	    charEntry = charData.splice(0, jumpEntry[2]);
+          }
+      	  font.addChar(jumpEntry, charEntry);
+        }
+        document.body.className = "started";
+      });        
+      
+      })();
+    </script>  
+  </body>
+</html>
+
-- 
GitLab