Skip to content

Instantly share code, notes, and snippets.

@elzekool
Created June 3, 2019 19:21
Show Gist options
  • Save elzekool/538efd2b8fbfc26123a73b6cccf74f62 to your computer and use it in GitHub Desktop.
Save elzekool/538efd2b8fbfc26123a73b6cccf74f62 to your computer and use it in GitHub Desktop.
import * as fs from "fs";
import {Shape} from "@laser-dac/draw/dist/Shape";
import {Color, Point} from "@laser-dac/draw/dist/Point";
import {Path} from "@laser-dac/draw";
interface HersheyCharacter {
leftPos : number,
rightPos : number,
vertexCount : number,
vertices : string[]
}
interface HersheyFontOptions {
x : number,
y : number,
font : HersheyCharacter[],
charWidth : number,
spacingFactor? : number,
text : string,
color : Color
}
// Render text using hershey font
export class HersheyFont implements Shape
{
private x : number;
private y : number;
private font : HersheyCharacter[];
private charWidth : number;
private spacingFactor : number;
private text : string;
private color : Color;
constructor(options : HersheyFontOptions) {
this.x = options.x;
this.y = options.y;
this.font = options.font;
this.charWidth = options.charWidth;
this.spacingFactor = options.spacingFactor || 1.0;
this.text = options.text;
this.color = options.color;
}
draw(resolution: number): Point[] {
const paths : string[] = [];
let xpos = 0;
for(let i = 0; i < this.text.length; i++) {
const characterIndex = this.text.charCodeAt(i) - 32;
if (characterIndex < 0 || characterIndex >= this.font.length) {
continue;
}
paths.push(convertHersheyToPath(this.font[characterIndex], xpos - this.font[characterIndex].leftPos, 5, this.charWidth / 10));
xpos += (this.font[characterIndex].rightPos - this.font[characterIndex].leftPos) * this.spacingFactor;
}
if (paths.length === 0) {
return [];
}
return new Path({
x : this.x,
y : this.y,
color : this.color,
path : paths.join(' ')
}).draw(resolution);
}
}
// Load Hershey .jhf file. See https://emergent.unpythonic.net/software/hershey for source files
// futural.jhf is a good candidate as it is a single stroke sans-serif font
export function loadHersheyFont(path: string) : HersheyCharacter[] {
const fontFile = fs.readFileSync(path, 'binary');
const characters : HersheyCharacter[] = [];
let readPos = 0;
function readNextCharacter() : HersheyCharacter {
// 0-4 number (not used)
// 5-7 number of vertices
// 8 left pos
// 9 right pos
// 10- vertices
// newline
const vertexCount : number = Number.parseInt(fontFile.substr(readPos+5, 3), 10);
const leftPos : number = hersheyCharToNumber(fontFile.charAt(readPos+8));
const rightPos : number = hersheyCharToNumber(fontFile.charAt(readPos+9));
const vertices : string[] = [];
readPos += 10;
while(vertices.length < vertexCount-1) {
let vertex = '';
for(let i = 0; i < 2; i++) {
while(fontFile.charAt(readPos) === '\n') {
readPos++;
}
vertex += fontFile.charAt(readPos);
readPos++;
}
vertices.push(vertex);
}
readPos++;
return {
leftPos,
rightPos,
vertexCount,
vertices
};
}
while(readPos < fontFile.length) {
characters.push(readNextCharacter());
}
return characters;
}
function hersheyCharToNumber(char : string) : number {
return char.charCodeAt(0) - 'R'.charCodeAt(0);
}
function convertHersheyToPath(character : HersheyCharacter, x : number, y : number, scale : number) : string {
const pathElements = [];
let nextIsMove = true;
for(let i = 0; i < character.vertices.length; i++) {
const vertice = character.vertices[i];
if (vertice === ' R') {
nextIsMove = true;
continue;
}
const vertexX = (x + hersheyCharToNumber(vertice.charAt(0))) * scale;
const vertexY = (y + hersheyCharToNumber(vertice.charAt(1))) * scale;
pathElements.push(`${nextIsMove ? 'M' : 'L'} ${vertexX},${vertexY}`);
nextIsMove = false;
}
return pathElements.join(' ');
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment