mirror of
https://github.com/skishore/makemeahanzi.git
synced 2025-10-29 09:57:38 +08:00
Switch to JSON rendering frontend
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,4 +1,2 @@
|
||||
*.pyc
|
||||
*.swp
|
||||
chars.html
|
||||
chars.log
|
||||
|
||||
110
main.py
110
main.py
@ -1,110 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
'''
|
||||
Extracts one or more characters from each of the svg fonts in the SVG directory
|
||||
and packages them into a 'chars.html' output file.
|
||||
'''
|
||||
import math
|
||||
import os
|
||||
import random
|
||||
import sys
|
||||
|
||||
import median
|
||||
import stroke_extractor
|
||||
|
||||
|
||||
COLORS = ['#0074D9', '#2ECC40', '#FFDC00', '#FF4136', '#7FDBFF',
|
||||
'#001F3F', '#39CCCC', '#3D9970', '#01FF70', '#FF851B']
|
||||
SCALE = 0.16
|
||||
SVG_DIR = 'derived'
|
||||
TRANSFORM = 'scale({0:.2g}, -{0:0.2g}) translate(0, -900)'.format(SCALE)
|
||||
|
||||
|
||||
def augment_glyph(glyph):
|
||||
'''
|
||||
Takes an HTML SVG object and returns a list of addition SVG elements that
|
||||
should be added to the glyph to show diagnostic data for our algorithm.
|
||||
'''
|
||||
name = get_html_attribute(glyph, 'glyph-name')
|
||||
d = get_html_attribute(glyph, 'd')
|
||||
assert name and d, 'Missing glyph-name or d for glyph:\n{0}'.format(glyph)
|
||||
extractor = stroke_extractor.StrokeExtractor(name, d)
|
||||
# We augment the glyph with three types of information:
|
||||
# - The extracted strokes. Each one is drawn in a random color.
|
||||
# - The endpoints of the original paths, with corners in red, others in blue.
|
||||
# - The detected bridges, line segments drawn in white.
|
||||
result = []
|
||||
for i, stroke in enumerate(extractor.strokes):
|
||||
result.append('<path fill="{0}" {1} d="{2}" />'.format(
|
||||
COLORS[i % len(COLORS)], 'stroke="black" stroke-width="2"', stroke.d()))
|
||||
for path in extractor.paths:
|
||||
for element in path:
|
||||
result.append(
|
||||
'<circle cx="{0}" cy="{1}" r="4" fill="blue" stroke="blue"/>'.format(
|
||||
int(element.end.real), int(element.end.imag)))
|
||||
corners = extractor.corners
|
||||
for corner in corners.itervalues():
|
||||
result.append(
|
||||
'<circle cx="{0}" cy="{1}" r="4" fill="red" stroke="red" '
|
||||
'data-angle="{2}"/>'.format(
|
||||
int(corner.point.real), int(corner.point.imag), corner.angle))
|
||||
for index1 in extractor.bridges:
|
||||
for index2 in extractor.bridges[index1]:
|
||||
if index1 > index2:
|
||||
continue
|
||||
result.append(
|
||||
'<line x1="{0}" y1="{1}" x2="{2}" y2="{3}" style="{4}"/>'.format(
|
||||
int(corners[index1].point.real), int(corners[index1].point.imag),
|
||||
int(corners[index2].point.real), int(corners[index2].point.imag),
|
||||
'stroke:white;stroke-width:8'))
|
||||
return result
|
||||
|
||||
|
||||
def get_html_attribute(glyph, attribute):
|
||||
'''
|
||||
Takes an HTML SVG object and returns the path data from the "d" field.
|
||||
'''
|
||||
left = ' {0}="'.format(attribute)
|
||||
start = max(glyph.find(left), glyph.find(left.replace(' ', '\n')))
|
||||
end = glyph.find('"', start + len(left))
|
||||
assert start >= 0 and end >= 0, \
|
||||
'Glyph missing {0}=".*" block:\n{1}'.format(attribute, repr(glyph))
|
||||
return glyph[start + len(left):end].replace('\n', ' ')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
assert len(sys.argv) > 1, 'Usage: ./getchar.py <unicode_codepoint>+'
|
||||
svgs = [file_name for file_name in os.listdir(SVG_DIR)
|
||||
if file_name.endswith('.svg') and not file_name.startswith('.')]
|
||||
glyphs = []
|
||||
for file_name in svgs:
|
||||
glyphs.append([])
|
||||
with open(os.path.join(SVG_DIR, file_name)) as file:
|
||||
data = file.read()
|
||||
for codepoint in sys.argv[1:]:
|
||||
index = data.find('unicode="&#x{0};"'.format(codepoint))
|
||||
if index < 0:
|
||||
print >> sys.stderr, '{0}: missing {1}'.format(file_name, codepoint)
|
||||
continue
|
||||
(left, right) = ('<glyph', '/>')
|
||||
(start, end) = (data.rfind(left, 0, index), data.find(right, index))
|
||||
if start < 0 or end < 0:
|
||||
print >> sys.stderr, '{0}: malformed {1}'.format(file_name, codepoint)
|
||||
continue
|
||||
glyphs[-1].append(data[start:end + len(right)])
|
||||
# Construct an HTML file that includes the extracted glyphs, along with
|
||||
# diagnostic data for our stroke extraction algorithm.
|
||||
with open('chars.html', 'w') as f:
|
||||
f.write('<!DOCTYPE html>\n <html>\n <body>\n')
|
||||
for row in glyphs:
|
||||
f.write(' <div>\n')
|
||||
for glyph in row:
|
||||
size = int(1024*SCALE)
|
||||
f.write(' <svg width="{0}" height="{0}">\n'.format(size))
|
||||
f.write(' <g transform="{0}">\n'.format(TRANSFORM))
|
||||
f.write(glyph.replace('<glyph', '<path') + '\n')
|
||||
for extra in augment_glyph(glyph):
|
||||
f.write(extra + '\n')
|
||||
f.write(' </g>\n')
|
||||
f.write(' </svg>\n')
|
||||
f.write(' </div>\n')
|
||||
f.write(' </body>\n </html>')
|
||||
59
scripts/main.py
Executable file
59
scripts/main.py
Executable file
@ -0,0 +1,59 @@
|
||||
#!/usr/bin/python
|
||||
'''
|
||||
Extracts one or more characters from each of the svg fonts in the SVG directory
|
||||
and prints data for them to stderr in JSON format. The output data is a list of
|
||||
dictionaries with the following keys:
|
||||
- name: string glyph name
|
||||
- d: string SVG path data
|
||||
- extractor: stroke data + diagnostics (see stroke_extractor for details)
|
||||
'''
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
|
||||
import stroke_extractor
|
||||
|
||||
|
||||
def get_html_attribute(glyph, attribute):
|
||||
'''
|
||||
Takes an HTML SVG object and returns the path data from the "d" field.
|
||||
'''
|
||||
left = ' {0}="'.format(attribute)
|
||||
start = max(glyph.find(left), glyph.find(left.replace(' ', '\n')))
|
||||
end = glyph.find('"', start + len(left))
|
||||
assert start >= 0 and end >= 0, \
|
||||
'Glyph missing {0}=".*" block:\n{1}'.format(attribute, repr(glyph))
|
||||
return glyph[start + len(left):end].replace('\n', ' ')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('-f', '--font', dest='font',
|
||||
help='SVG font to read characters from.', required=True)
|
||||
(options, args) = parser.parse_known_args()
|
||||
# For each Unicode codepoint among the positional arguments, extract the glyph
|
||||
# that corresponds to that codepoint from the given SVG font.
|
||||
glyphs = []
|
||||
with open(options.font) as font:
|
||||
data = font.read()
|
||||
for codepoint in args:
|
||||
index = data.find('unicode="&#x{0};"'.format(codepoint))
|
||||
if index < 0:
|
||||
print >> sys.stderr, '{0}: missing {1}'.format(options.font, codepoint)
|
||||
continue
|
||||
(left, right) = ('<glyph', '/>')
|
||||
(start, end) = (data.rfind(left, 0, index), data.find(right, index))
|
||||
if start < 0 or end < 0:
|
||||
print >> sys.stderr, '{0}: malformed {1}'.format(options.font, codepoint)
|
||||
continue
|
||||
glyphs.append(data[start:end + len(right)])
|
||||
# Print data for each of the extracted glyphs in JSON format.
|
||||
result = []
|
||||
for glyph in glyphs:
|
||||
name = get_html_attribute(glyph, 'glyph-name')
|
||||
d = get_html_attribute(glyph, 'd')
|
||||
assert name and d, 'Missing glyph-name or d for glyph:\n{0}'.format(glyph)
|
||||
extractor = stroke_extractor.StrokeExtractor(name, d)
|
||||
data = {'name': name, 'd': d, 'extractor': extractor.get_data()}
|
||||
result.append(data)
|
||||
print json.dumps(result)
|
||||
0
median.py → scripts/median.py
Executable file → Normal file
0
median.py → scripts/median.py
Executable file → Normal file
21
stroke_extractor.py → scripts/stroke_extractor.py
Executable file → Normal file
21
stroke_extractor.py → scripts/stroke_extractor.py
Executable file → Normal file
@ -346,6 +346,27 @@ class StrokeExtractor(object):
|
||||
result[corner.index] = corner
|
||||
return result
|
||||
|
||||
def get_data(self):
|
||||
'''
|
||||
Returns a representation of the data extracted from this glyph that can be
|
||||
serialized to JSON. The result is a dictionary with the following keys:
|
||||
- points: list of [x, y] pairs of endpoints on the glyph's SVG path
|
||||
- corners: list of [x, y] pairs of points that are also corners
|
||||
- bridges: list of pairs of corners [[x1, y1], [x2, y2]] that are bridges
|
||||
- strokes: list of SVG path data strings for the extracted strokes
|
||||
'''
|
||||
pair = lambda point: [int(point.real), int(point.imag)]
|
||||
return {
|
||||
'points': [pair(element.end) for path in self.paths for element in path],
|
||||
'corners': [pair(corner.point) for corner in self.corners.itervalues()],
|
||||
'bridges': [
|
||||
[pair(self.corners[index1].point), pair(self.corners[index2].point)]
|
||||
for (index1, others) in self.bridges.iteritems() for index2 in others
|
||||
if index1 < index2
|
||||
],
|
||||
'strokes': [stroke.d() for stroke in self.strokes],
|
||||
}
|
||||
|
||||
def log(self, message):
|
||||
self.messages.append(message)
|
||||
|
||||
7
test
7
test
@ -1,7 +0,0 @@
|
||||
#!/bin/bash
|
||||
#./main.py 4f60 597d 5b78 5b66 4e08 4e18 4e28 4e38 4e48 4e58 4e68 4e78 4e80 4e81 4e82 4e83 4e70 4e71 4e72 4e73 4e74 4e75 4e76 4e77 4e07 4e17 4e27 4e37 4e47 4e57 4e67 4e77 > chars.log
|
||||
#./main.py 4e00 4e10 4e20 4e30 4e40 4e50 4e60 4e70 4e80 4e90 4ea0 4eb0 4ec0 4ed0 4ee0 4ef0 \
|
||||
# 4e01 4e11 4e21 4e31 4e41 4e51 4e61 4e71 4e81 4e91 4ea1 4eb1 4ec1 4ed1 4ee1 4ef1 \
|
||||
# 4e02 4e12 4e22 4e32 4e42 4e52 4e62 4e72 4e82 4e92 4ea2 4eb2 4ec2 4ed2 4ee2 4ef2 \
|
||||
# 4e03 4e13 4e23 4e33 4e43 4e53 4e63 4e73 4e83 4e93 4ea3 4eb3 4ec3 4ed3 4ee3 4ef3
|
||||
./main.py 51b0 72d0 6211 5fc3 4ea1 56db 534d 7fbd 4e5f 53c8 4eca 98de 4e5d 5f13 9a6c 8ba1 9ce9 53ca 961d 90ae 6295 51f8 5927 5927 4e03 4e2d 4e4f 6708 4e38 56db 758b 5b50 5c71 4e1c
|
||||
Reference in New Issue
Block a user