Skip to content
Snippets Groups Projects
Commit 0893d319 authored by Xavier's avatar Xavier
Browse files

Fixed big fonts handling, started char array font parsing

parent 25197e66
No related branches found
No related tags found
No related merge requests found
<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>
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment