Created
August 6, 2018 22:21
-
-
Save madebr/3216e7ff23701caffc25a8925570c0e1 to your computer and use it in GitHub Desktop.
OpenRW fonts kerning tool
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import sys | |
from pathlib import Path | |
from collections import namedtuple | |
from PyQt5 import QtCore, QtGui, QtWidgets | |
from PyQt5.QtCore import Qt | |
curdir = Path(__file__).resolve().parent | |
pagerGlyphWidths = [ | |
3, 3, 6, 8, 6, 10, 8, 3, 5, 5, 7, 0, 3, 7, 3, 0, | |
6, 4, 6, 6, 7, 6, 6, 6, 6, 6, 3, 0, 0, 0, 0, 6, | |
0, 6, 6, 6, 6, 6, 6, 6, 6, 3, 6, 6, 5, 8, 7, 6, | |
6, 7, 6, 6, 5, 6, 6, 8, 6, 7, 7, 0, 0, 0, 0, 0, | |
0, 6, 6, 6, 6, 6, 5, 6, 6, 3, 4, 6, 3, 9, 6, 6, | |
6, 6, 5, 6, 5, 6, 6, 8, 6, 6, 5, 0, 0, 0, 0, 0, | |
6, 6, 6, 6, 8, 6, 6, 6, 6, 6, 5, 5, 6, 6, 6, 6, | |
6, 6, 6, 6, 6, 6, 7, 6, 6, 6, 6, 9, 6, 6, 6, 6, | |
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 6, 6, | |
3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
] | |
pricedownGlyphWidths = [ | |
11, 13, 30, 27, 20, 24, 22, 12, 14, 14, 0, 26, 9, 14, 9, 26, | |
20, 19, 20, 20, 22, 20, 20, 19, 20, 20, 13, 29, 24, 29, 24, 20, | |
27, 20, 20, 20, 20, 20, 17, 20, 20, 10, 20, 20, 15, 30, 20, 20, | |
20, 20, 20, 20, 22, 20, 22, 32, 20, 20, 19, 27, 20, 32, 23, 13, | |
27, 21, 21, 21, 21, 21, 18, 22, 21, 12, 20, 22, 17, 30, 22, 21, | |
21, 21, 21, 22, 21, 21, 21, 29, 19, 23, 21, 28, 25, 0, 0, 0, | |
20, 20, 20, 20, 30, 20, 20, 20, 20, 20, 10, 10, 10, 10, 21, 21, | |
21, 21, 20, 20, 20, 20, 21, 21, 21, 21, 21, 32, 23, 21, 21, 21, | |
21, 12, 12, 12, 12, 21, 21, 21, 21, 21, 21, 21, 21, 20, 20, 20, | |
13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
] | |
arialGlyphWidths = [ | |
27, 25, 55, 43, 47, 65, 53, 19, 29, 31, 21, 45, 23, 35, 27, 29, | |
47, 33, 45, 43, 49, 47, 47, 41, 47, 45, 25, 23, 53, 43, 53, 39, | |
61, 53, 51, 47, 49, 45, 43, 49, 53, 23, 41, 53, 45, 59, 53, 51, | |
47, 51, 49, 49, 45, 51, 49, 59, 59, 47, 51, 31, 27, 31, 29, 27, | |
19, 43, 45, 43, 43, 45, 27, 45, 43, 21, 33, 45, 23, 65, 43, 43, | |
47, 45, 33, 41, 29, 43, 41, 61, 51, 43, 43, 67, 53, 67, 67, 71, | |
53, 53, 53, 53, 65, 49, 45, 45, 45, 45, 23, 23, 23, 23, 51, 51, | |
51, 51, 51, 51, 51, 51, 51, 43, 43, 43, 43, 65, 43, 45, 45, 45, | |
45, 21, 21, 21, 21, 43, 43, 43, 43, 43, 43, 43, 43, 53, 43, 39, | |
25, 19, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, | |
53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 37, 53, 53, | |
53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, | |
41, | |
] | |
FontMetaData = namedtuple('FontMetaData', ('texturePath', 'aspectratio', 'monoWidth', 'glyphWidths', 'binpath')) | |
pagerMetaData = FontMetaData(curdir / 'pager.png', 1, 11, pagerGlyphWidths, None) | |
pricedownMetaData = FontMetaData(curdir / 'pricedown.png', 1.25, None, pricedownGlyphWidths, None) | |
arialMetaData = FontMetaData(curdir / 'arial.png', 1.25, None, arialGlyphWidths, None) | |
fileMetaData = FontMetaData(curdir / 'file.png', None, None, None, curdir / 'file.bin') | |
class FontMapViewerWidget(QtWidgets.QWidget): | |
def __init__(self, metadata: FontMetaData): | |
QtWidgets.QWidget.__init__(self) | |
self.metadata = metadata | |
self.image = QtGui.QImage(str(metadata.texturePath)) | |
self.s1 = 'THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG' | |
self.s2 = 'this is a string' | |
self.aspectratio = metadata.aspectratio | |
self.glyphWidths = metadata.glyphWidths | |
if metadata.binpath: | |
with metadata.binpath.open('rb') as f: | |
self.aspectratio = float(f.readline()) | |
self.glyphWidths = [int(line) for line in f.readlines()] | |
self.glyphWidths += [0] * 200 | |
if not self.glyphWidths: | |
raise ValueError('Need glyphWidths') | |
def numberColumns(self): | |
return 16 | |
def rasterWidth(self): | |
return self.image.width() // self.numberColumns() | |
def rasterHeight(self): | |
return int(self.rasterWidth() * self.aspectratio) | |
def numberRows(self): | |
return self.image.height() // self.rasterHeight() | |
def toIndex(self, column, row): | |
return row * self.numberColumns() + column | |
def toCoord(self, index): | |
row = index // self.numberColumns() | |
column = index % self.numberColumns() | |
return column, row | |
def minimumSizeHint(self): | |
return QtCore.QSize(100, 100 * ((self.image.height() + 2 * self.rasterHeight()) / self.image.width())) | |
def paintEvent(self, event: QtGui.QPaintEvent): | |
painter = QtGui.QPainter(self) | |
painter.setPen(QtGui.QPen(Qt.darkGray, 3)) | |
brush = QtGui.QBrush(Qt.SolidPattern) | |
brush.setColor(Qt.gray) | |
painter.fillRect(event.rect(), brush) | |
pen = QtGui.QPen() | |
pen.setWidth(0.5) | |
brush.setColor(Qt.red) | |
pen.setBrush(brush) | |
painter.setPen(pen) | |
scale = min(self.width() / self.image.width(), (self.height() * (self.numberRows() - 2) / self.numberRows()) / self.image.height()) | |
painter.scale(scale, scale) | |
image_size = self.image.size() | |
srcRectF = QtCore.QRectF(0, 0, image_size.width(), image_size.height()) | |
for i in range(self.numberRows()): | |
painter.drawLine(QtCore.QLineF(0, (i+1) * self.rasterHeight(), self.numberColumns() * self.rasterWidth(), (i+1) * self.rasterHeight())) | |
for i in range(self.numberColumns()): | |
painter.drawLine(QtCore.QLineF(i * self.rasterWidth(), 0, i * self.rasterWidth(), self.numberRows() * self.rasterHeight())) | |
brush.setColor(Qt.yellow) | |
pen.setBrush(brush) | |
painter.setPen(pen) | |
for i in range(self.numberRows()): | |
painter.drawLine(QtCore.QLineF(0, (i+0.77) * self.rasterHeight(), self.numberColumns() * self.rasterWidth(), (i+0.77) * self.rasterHeight())) | |
brush.setColor(Qt.green) | |
pen.setBrush(brush) | |
painter.setPen(pen) | |
for column in range(self.numberColumns()): | |
for row in range(self.numberRows()): | |
index = self.toIndex(column, row) | |
glyphWidth = self.glyphWidths[index] | |
x = column * self.rasterWidth() + glyphWidth | |
painter.drawLine(QtCore.QLineF(x, row * self.rasterHeight(), | |
x, (row+1) * self.rasterHeight())) | |
painter.drawImage(srcRectF, self.image) | |
def printStr(s, x, y): | |
for c in s: | |
ascii = ord(c) | |
index = ascii - 32 | |
column, row = self.toCoord(index) | |
glyphWidth = self.glyphWidths[index] | |
srcRectF = QtCore.QRectF(column * self.rasterWidth(), row * self.rasterHeight(), | |
self.rasterWidth(), self.rasterHeight()) | |
dstRectF = QtCore.QRectF(x, y, | |
self.rasterWidth(), self.rasterHeight()) | |
painter.drawImage(dstRectF, self.image, srcRectF) | |
if self.metadata.monoWidth: | |
x += self.metadata.monoWidth | |
else: | |
x += glyphWidth | |
printStr(self.s1, 0, image_size.height()) | |
printStr(self.s2, 0, image_size.height()+ self.rasterHeight()) | |
@QtCore.pyqtSlot(str) | |
def textChanged(self, s: str): | |
self.s1 = s | |
self.update() | |
class MainWindow(QtWidgets.QMainWindow): | |
def __init__(self): | |
widgets = [] | |
widgets.append((FontMapViewerWidget(pagerMetaData), 'pager',)) | |
widgets.append((FontMapViewerWidget(pricedownMetaData), 'pricedown',)) | |
widgets.append((FontMapViewerWidget(arialMetaData), 'arial',)) | |
try: | |
widgets.append((FontMapViewerWidget(fileMetaData), 'file',)) | |
except ValueError: | |
print('No file widget') | |
layout = QtWidgets.QVBoxLayout() | |
l = QtWidgets.QLineEdit() | |
s = QtWidgets.QTabWidget() | |
for w, t in widgets: | |
s.addTab(w, t) | |
l.textChanged.connect(w.textChanged) | |
layout.addWidget(s) | |
layout.addWidget(l) | |
w = QtWidgets.QWidget() | |
w.setLayout(layout) | |
QtWidgets.QMainWindow.__init__(self) | |
self.setCentralWidget(w) | |
def main(): | |
app = QtWidgets.QApplication(sys.argv) | |
mw = MainWindow() | |
mw.show() | |
return app.exec_() | |
if __name__ == '__main__': | |
sys.exit(main()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment