#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ erzeugt aus in Inkscape gezeichneten Buchstaben (SVG) die Glyphen und die Fontconfig für piccreate (Ersatz für extract-glyph.sh, extract-font.sh und fonttest.sh, läuft auch unter Windows). Die Auswahl der Zeilen folgt bewusst den früheren grep/sed Aufrufen, damit die erzeugten Glyphen gleich bleiben. """ __version__ = '0.1.0' __license__ = 'BSD' import glob import locale import optparse import os import re import sys from decimal import Decimal, InvalidOperation # Wortgrenzen wie \< und \> bei grep WB = r'(?|style') LINE_OUT = re.compile(WB + 'text' + WE + '|id=|http:') CIRCLE_IN = re.compile('circle|translate|' + WB + 'r' + WE) TEXT_IN = re.compile('<' + WB + 'text|text' + WE + '>|' + WB + 'x' + WE + '=|' + WB + 'y' + WE + '=|tspan|style|preserve') TEXT_OUT = re.compile(WB + 'transform-center-x' + WE + '|' + WB + 'window-|' + WB + 'id' + WE + '=') CENTER_X = re.compile(r'inkscape:transform-center-x=".*"') CENTER_Y = re.compile(r'inkscape:transform-center-y=".*"') PATTERN = re.compile(r'>(x[0-9]+)<') NUMBER = re.compile(r'\s*[+-]?(\d+\.?\d*|\.\d+)([eE][+-]?\d+)?') TEST_BEGIN = '' TEST_END = '' GLYPH_BEGIN = '' GLYPH_END = '' def split_lines(text): ''' zerlegt einen Text in Zeilen (wie grep, ohne Zeilenende) ''' lines = text.split('\n') if lines and lines[-1] == '': lines.pop() return lines def strip_center(line): line = CENTER_X.sub('', line) return CENTER_Y.sub('', line) def number_key(value): ''' Sortierschlüssel wie bei "sort -g": Zeilen ohne Zahl zuerst ''' m = NUMBER.match(value) if not m: return (0, 0.0, value) return (1, float(m.group(0)), value) def coordinates(glyph_lines, axis): ''' sammelt alle x- bzw. y-Koordinaten aus Texten, Kreisen und Linien ''' values = [] if axis == 'x': att = re.compile(WB + 'x' + WE + '=') else: att = re.compile('y=') for line in glyph_lines: if att.search(line): values.append(re.sub(r'^\s+', '', line).replace(axis + '=', '').replace('"', '')) # Kreise: transform="translate(x,y)" for line in glyph_lines: if 'x[0-9]+<', l)) glyph = [PATTERN.sub(r'>${\1}<', l) for l in glyph] base = os.path.splitext(os.path.basename(svg_path))[0] config = [ '[' + base + ']', 'XSTEP=' + difference(xmax, xmin), 'XMIN=' + xmin, 'XMAX=' + xmax, 'YSTEP=' + difference(ymax, ymin), 'YMIN=' + ymin, 'YMAX=' + ymax, 'NPATTERN=' + str(npattern), 'FONTNAME=' + base + '.svg', '#', ] return '\n'.join(glyph) + '\n', '\n'.join(config) + '\n' def write_glyph(svg_path, out_dir, extract=True): ''' schreibt Glyph und Fontconfig-Sektion ins Ausgabeverzeichnis ''' glyph, config = extract_glyph(svg_path, extract) base = os.path.splitext(os.path.basename(svg_path))[0] with open(os.path.join(out_dir, base + '.svg'), 'w', encoding='utf-8', newline='\n') as fh: fh.write(glyph) return base, config def font_source(name): ''' sucht das Verzeichnis mit den Buchstaben eines Fonts ''' in_dir = os.path.join(os.environ.get('PICCREATE_IN', ''), name) if os.path.isdir(in_dir): return in_dir if os.path.isdir(name): return name raise SystemExit('"' + name + '" is no directory. Please give a directory with .svg glyphs as input') def sorted_glyphs(source): ''' alle .svg Dateien, sortiert wie die Shell (a A ä b B ...) ''' try: locale.setlocale(locale.LC_COLLATE, '') except locale.Error: pass return sorted(glob.glob(os.path.join(source, '*.svg')), key=locale.strxfrm) def main(): out_dir = options.outdir if not os.path.isdir(out_dir): print('"' + out_dir + '" does not exist. Please give the directory for the output!') return 1 if options.infile: # ein Buchstabe (extract-glyph.sh) if not os.path.isfile(options.infile) or not os.path.getsize(options.infile): print('input file does not exist') return 1 base, config = write_glyph(options.infile, out_dir, options.extract) with open(os.path.join(out_dir, base + '.cfg'), 'w', encoding='utf-8', newline='\n') as fh: fh.write(config) return 0 name = options.font or options.test source = font_source(name) configs = [] for svg_path in sorted_glyphs(source): base, config = write_glyph(svg_path, out_dir, extract=bool(options.font)) print(base) configs.append((base, config)) if options.font: # ein Font (extract-font.sh): alle Sektionen in .cfg cfg_name = os.path.basename(os.path.normpath(source)) + '.cfg' with open(os.path.join(out_dir, cfg_name), 'w', encoding='utf-8', newline='\n') as fh: fh.write(''.join(config for _, config in configs)) print('->', os.path.join(out_dir, cfg_name)) else: # Testbilder (fonttest.sh): je Buchstabe eine .cfg daneben for base, config in configs: with open(os.path.join(out_dir, base + '.cfg'), 'w', encoding='utf-8', newline='\n') as fh: fh.write(config) return 0 if __name__ == '__main__': parser = optparse.OptionParser(usage="""%prog [options] Example usage ------------- one glyph, to test it later with inkscape: $ %prog -i ../in/ausgangsschrift/a.svg one glyph, extract the points and text for the font: $ %prog -i ../in/ausgangsschrift/a.svg -e all glyphs of a font (directory in in/) including the font config: $ %prog -f ausgangsschrift test pictures of all glyphs of a font: $ %prog -t ausgangsschrift """, version='%prog ' + __version__) parser.add_option("-i", "--infile", dest="infile", help="svg file of one glyph") parser.add_option("-e", "--extract", dest="extract", action='store_true', default=False, help="with -i: extract the glyph for the font instead of a test picture") parser.add_option("-f", "--font", dest="font", help="directory with the glyphs of a font: create glyphs and font config") parser.add_option("-t", "--test", dest="test", help="directory with the glyphs of a font: create test pictures") parser.add_option("-o", "--outdir", dest="outdir", default=os.environ.get('PICCREATE_OUT', '.'), help="directory for the output. default is $PICCREATE_OUT") (options, args) = parser.parse_args() if sum(1 for o in (options.infile, options.font, options.test) if o) != 1: parser.error('please give exactly one of -i, -f or -t') sys.exit(main()) # vim: set tw=80 ft=python ts=4 sw=4: