From 19f675e957a1158b5e3ce6322a98b4f22044c5a8 Mon Sep 17 00:00:00 2001 From: Xavier <xavier@c-est-simple.com> Date: Fri, 20 Oct 2017 22:18:22 +0200 Subject: [PATCH] Font generator --- resources/glyph2font.html | 225 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 225 insertions(+) create mode 100644 resources/glyph2font.html diff --git a/resources/glyph2font.html b/resources/glyph2font.html new file mode 100644 index 0000000..b1d63d2 --- /dev/null +++ b/resources/glyph2font.html @@ -0,0 +1,225 @@ +<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>Height:</span> <input placeholder="Font height" type="number" id="height" value="13" max="64"/><br/> + <span>Width:</span> <input placeholder="Font width" type="number" id="width" value="10"/><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 + // Implement methods to move glyphs, symetrical input, ... + // Implement char insertion, non displayable char, ... + + 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 removeCharHeader = charContainer.appendChild(document.createElement("th")); + removeCharHeader.setAttribute("action", "remove"); + removeCharHeader.textContent = "x"; + 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'; + } + + 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:'); + 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'); + + for(let col = 0; col < this.width ; col++) { + var bits = ""; // using string because js uses 32b ints when performing bit operations + //for(let r = 0; r < rows.length; r++) { + 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 an odd number of bytes + 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(',')},`); + 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> + -- GitLab