59 lines
2.6 KiB
Python
59 lines
2.6 KiB
Python
# Reconstructs assets/SingeText.jpeg as assets/SingeText.svg: thresholds the logotype, traces it
|
|
# with potrace into Bezier outlines, and writes a tightly cropped SVG with a transparent background.
|
|
# Usage: python3 util/traceText.py assets/SingeText.jpeg assets/SingeText.svg [potrace] [check.svg]
|
|
# Needs Pillow and potrace (https://potrace.sourceforge.net). check.svg keeps the full page so it
|
|
# can be rendered over the original for comparison.
|
|
import os
|
|
import re
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
from PIL import Image, ImageFilter
|
|
|
|
src = sys.argv[1]
|
|
out = sys.argv[2]
|
|
potrace = sys.argv[3] if len(sys.argv) > 3 else 'potrace'
|
|
check = sys.argv[4] if len(sys.argv) > 4 else None
|
|
|
|
# Trace at 4x so the anti-aliased edges of the JPEG turn into smooth curves rather than steps.
|
|
scale = 4
|
|
BLUR = 3.5
|
|
grey = Image.open(src).convert('L')
|
|
w, h = grey.size
|
|
big = grey.resize((w * scale, h * scale), Image.LANCZOS)
|
|
# A light blur removes JPEG ringing along the edges, which would otherwise trace as tiny wobbles.
|
|
big = big.filter(ImageFilter.GaussianBlur(BLUR))
|
|
mono = big.point(lambda v: 255 if v >= 128 else 0).convert('1')
|
|
|
|
work = tempfile.mkdtemp()
|
|
pbm = os.path.join(work, 'text.pbm')
|
|
mono.save(pbm)
|
|
|
|
def trace(tight):
|
|
args = [potrace, pbm, '-s', '--flat', '-a', '1.0', '-O', '0.2', '-u', '1', '-t', str(4 * scale * scale), '-o', '-']
|
|
if tight:
|
|
args.append('--tight')
|
|
svg = subprocess.run(args, check=True, capture_output=True, text=True).stdout
|
|
width = float(re.search(r'width="([\d.]+)pt"', svg).group(1))
|
|
height = float(re.search(r'height="([\d.]+)pt"', svg).group(1))
|
|
transform = re.search(r'transform="([^"]+)"', svg).group(1)
|
|
path = re.search(r'<path[^>]*\bd="([^"]+)"', svg, re.S).group(1)
|
|
path = re.sub(r'\s+', ' ', path).strip()
|
|
return width, height, transform, path
|
|
|
|
def write(name, tight):
|
|
width, height, transform, path = trace(tight)
|
|
lines = ['<?xml version="1.0" encoding="UTF-8"?>',
|
|
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 %.2f %.2f" width="%.2f" height="%.2f">' % (width / scale, height / scale, width / scale, height / scale),
|
|
' <!-- Singe logotype, traced from SingeText.jpeg; transparent background. -->',
|
|
' <title>Singe</title>',
|
|
' <g transform="scale(%g) %s" fill="#000" stroke="none">' % (1.0 / scale, transform),
|
|
' <path d="%s"/>' % path,
|
|
' </g>',
|
|
'</svg>']
|
|
open(name, 'w').write('\n'.join(lines) + '\n')
|
|
print('%s: %.0fx%.0f, %d bytes' % (name, width / scale, height / scale, os.path.getsize(name)))
|
|
|
|
write(out, True)
|
|
if check:
|
|
write(check, False)
|