Windows-Unterstützung: .bat-Skripte, Font-Werkzeuge in Python

- libs/glyphextract.py ersetzt die grep/sed/bc-Logik von extract-glyph.sh,
  extract-font.sh und fonttest.sh (die .sh rufen es nur noch auf);
  schreibt FONTNAME= und <font>.cfg nach $PICCREATE_OUT
- bin/*.bat: setenv, piccreate, svgconvert, webscan, extract-glyph,
  extract-font, fonttest, setup-venv; .gitattributes für CRLF
- piccreate.py: Hintergrund als file:// URL (Windows-Pfade)
- svgconvert.py: magick statt convert, Configs/CSV als UTF-8
- webscan.py: Installationshinweise für Windows
- doc/README.md: Abschnitt Windows, Font-Werkzeuge aktualisiert

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Michael Stangl
2026-10-09 09:29:02 +02:00
co-authored by Claude Opus 5.5
parent 4897883938
commit 29c066b45a
18 changed files with 471 additions and 209 deletions
+3
View File
@@ -0,0 +1,3 @@
*.bat text eol=crlf
*.sh text eol=lf
*.py text eol=lf
+10
View File
@@ -0,0 +1,10 @@
@echo off
rem Glyphen und Font-Config eines Fonts nach %PICCREATE_OUT% schreiben
setlocal
call "%~dp0setenv.bat" || exit /b 1
if "%~1"=="" (
echo please give a directory in the in folder with .svg glyphs as input
exit /b 1
)
"%PICCREATE_PYTHON%" "%PICCREATE_LIBS%\glyphextract.py" -f %1
exit /b %errorlevel%
+3 -20
View File
@@ -2,25 +2,8 @@
. setenv.sh . setenv.sh
if [ -z "$1" ]; then if [ -z "$1" ]; then
echo "please give a directory in the templates folder with .svg glyphs as input" echo "please give a directory in the in folder with .svg glyphs as input"
exit 1 exit 1
fi fi
if [ -d "$PICCREATE_IN/$1" ]; then # Glyphen und <font>.cfg eines Fonts nach $PICCREATE_OUT schreiben
export SOURCE="$PICCREATE_IN/$1" python3 $PICCREATE_LIBS/glyphextract.py -f "$1"
elif [ ! -d "$1" ]; then
export SOURCE="$1"
else
echo "directory does not exist"
echo "please give a directory with .svg files as input"
exit 1
fi
export TARGET=$PICCREATE_OUT
for i in `ls $SOURCE/*.svg`
do
echo `basename $i .svg`
$PICCREATE_BIN/extract-glyph.sh -i $i -e
done
CONFIG=`basename $SOURCE`
( cat $TARGET/*.cfg >> $CONFIG.cfg_ ; rm $TARGET/*.cfg; mv $CONFIG.cfg_ $CONFIG.cfg)
+6
View File
@@ -0,0 +1,6 @@
@echo off
rem Einen Buchstaben extrahieren (-i datei.svg [-e])
setlocal
call "%~dp0setenv.bat" || exit /b 1
"%PICCREATE_PYTHON%" "%PICCREATE_LIBS%\glyphextract.py" %*
exit /b %errorlevel%
+4 -146
View File
@@ -1,149 +1,7 @@
#!/bin/bash #!/bin/bash
. setenv.sh . setenv.sh
if [ -z "$PICCREATE" ]; then # Einen Buchstaben extrahieren
echo "please source the environment" # extract-glyph.sh -i ../in/ausgangsschrift/a.svg Testbild fuer Inkscape
exit 1 # extract-glyph.sh -i ../in/ausgangsschrift/a.svg -e Glyph fuer den Font
fi python3 $PICCREATE_LIBS/glyphextract.py "$@"
O_ARGS=0
E_OPTERROR=85
USAGE="create a jpg file with the purl inside
Usage: `basename $0` [-hie]
-i id
-e extract
Examples:
to test the glyph later with inkscape:
`basename $0` -i ../in/buchstabe_a.svg
to extract the points and text from the glyph:
`basename $0` -i ../in/buchstabe_a.svg -e "
while getopts "i:eu:" Option
do
case $Option in
i) ID=$OPTARG;;
e) EXTRACT=1;;
*) echo "$USAGE" >&2; exit 1; # Default.
esac
done
shift $(($OPTIND - 1))
if [ -z $ID ] ; then
echo "-> no id/filename given"
echo "$USAGE" >&2
exit 1
fi
if [ -z "$ID" ]; then
echo "please give a .svg file of a glyph as input"
echo "$USAGE" >&2
exit 1
fi
if [ -s "$ID" ]; then
export BASE=`basename $ID .svg`
export GLYPH=$PICCREATE_OUT/$BASE.svg
export CONFIG=$PICCREATE_OUT/$BASE.cfg
else
echo "input file does not exist"
echo "$USAGE" >&2
exit 1
fi
# extrahiere die wichtigen Zeilen aus dem Font
cat $ID | egrep '<\<line\>|x1|x2|y1|y2|/>|style' | egrep -v '\<text\>|id=|http:' > line-$BASE.svg
cat $ID | egrep 'circle|translate|\<r\>' > circles-$BASE.svg
cat $ID | egrep '<\<text|text\>>|\<x\>=|\<y\>=|tspan|style|preserve' | egrep -v '\<transform-center-x\>|\<window-|\<id\>=' > text-$BASE.svg
# reduziere einige Zeilen um bestimmte Muster
cat line-$BASE.svg | sed -e 's/inkscape:transform-center-x=".*"//g' > $$; mv $$ line-$BASE.svg
cat line-$BASE.svg | sed -e 's/inkscape:transform-center-y=".*"//g' > $$; mv $$ line-$BASE.svg
cat text-$BASE.svg | sed -e 's/inkscape:transform-center-x=".*"//g' > $$; mv $$ text-$BASE.svg
cat text-$BASE.svg | sed -e 's/inkscape:transform-center-y=".*"//g' > $$; mv $$ text-$BASE.svg
cat circles-$BASE.svg | sed -e 's/inkscape:transform-center-x=".*"//g' > $$; mv $$ circles-$BASE.svg
cat circles-$BASE.svg | sed -e 's/inkscape:transform-center-y=".*"//g' > $$; mv $$ circles-$BASE.svg
# den eventuell alten Buchstaben vorher wegschmeissen
rm -f $GLYPH
if [ -z "$EXTRACT" ];
then
# schreib einen kompletten neuen Buchstaben zum testen
echo '<svg xmlns="http://www.w3.org/2000/svg" version="1.1">' >> $GLYPH
cat text-$BASE.svg >> $GLYPH
cat circles-$BASE.svg >> $GLYPH
cat line-$BASE.svg >> $GLYPH
echo '</svg>' >> $GLYPH
else
# schreib nur das extract zur Verwertung als Font in die Ausgabe
#echo '<g transform="translate(${posx},${posy})">' >> $GLYPH
echo '<g transform="translate(${posx},${posy})">' >> $GLYPH
cat text-$BASE.svg >> $GLYPH
cat circles-$BASE.svg >> $GLYPH
cat line-$BASE.svg >> $GLYPH
echo '</g>' >> $GLYPH
fi
rm line-$BASE.svg
rm circles-$BASE.svg
rm text-$BASE.svg
## alle Zusatzinfos zum Buchstaben rausholen
XCOORDS=./xcoords
# hole das Minium und Maxium der X-Koordinaten um die Schrittweite des Buchstabens zu bestimmen
# zuerst aus den Texten
cat $GLYPH | egrep "\<x\>=" | sed "s/^\s\+//g;s/x=//g;s/\"//g" > $XCOORDS
# dann aus Kreisen
cat $GLYPH | egrep -v '<g' | egrep "transform=" | sed 's/^\s\+//g;s/translate//g;s/transform=//g;s/["|(|)]//g;s/,.*//g' >> $XCOORDS
# dann aus den Linien
cat $GLYPH | grep x1= | sed "s/^\s\+//g;s/x1=//g;s/\"//g" >> $XCOORDS
cat $GLYPH | grep x2= | sed "s/^\s\+//g;s/x2=//g;s/\"//g" >> $XCOORDS
# sortiere die Koordinaten numerisch
cat $XCOORDS | sort -g | uniq > $$ ; mv $$ $XCOORDS;
XMAX=`tail -n 1 $XCOORDS`
XMIN=`head -n 1 $XCOORDS`
rm $XCOORDS
YCOORDS=./ycoords
# hole das Minium und Maxium der Y-Koordinaten um die Schrittweite des Buchstabens zu bestimmen
# zuerst aus den Texten
cat $GLYPH | grep y= | sed "s/^\s\+//g;s/y=//g;s/\"//g" > $YCOORDS
# dann aus Kreisen
cat $GLYPH | egrep -v '<g' | egrep "transform=" | sed 's/^\s\+//g;s/translate//g;s/transform=//g;s/["|(|)]//g;s/.*,//g' >> $YCOORDS
# dann aus den Linien
cat $GLYPH | grep y1= | sed "s/^\s\+//g;s/y1=//g;s/\"//g" >> $YCOORDS
cat $GLYPH | grep y2= | sed "s/^\s\+//g;s/y2=//g;s/\"//g" >> $YCOORDS
# sortiere die Koordinaten numerisch
cat $YCOORDS | sort -g | uniq > $$ ; mv $$ $YCOORDS;
YMAX=`tail -n 1 $YCOORDS`
YMIN=`head -n 1 $YCOORDS`
rm $YCOORDS
XSTEP=`echo "$XMAX-$XMIN" | bc`
YSTEP=`echo "$YMAX-$YMIN" | bc`
# hole raus wieviele x1-n Muster zu ersetzen sind
NPATTERN=`cat $GLYPH | egrep ">x[0-9]+<" | sed "s/.*\(x[0-9]\+\).*/\1/g" | wc -l`
# ersetze die Muster von x1-xn durch Templatezeichen
cat $GLYPH | sed "s/>\(x[0-9]\+\)</>\${\1}</g" > $$ ; mv $$ $GLYPH;
## und in die Buchstabenconfig schreiben
rm -f $CONFIG
echo [$BASE] >> $CONFIG
echo "XSTEP=$XSTEP" >> $CONFIG
echo "XMIN=$XMIN" >> $CONFIG
echo "XMAX=$XMAX" >> $CONFIG
echo "YSTEP=$YSTEP" >> $CONFIG
echo "YMIN=$YMIN" >> $CONFIG
echo "YMAX=$YMAX" >> $CONFIG
echo "NPATTERN=$NPATTERN" >> $CONFIG
echo "FILENAME=$BASE.svg" >> $CONFIG
echo "#" >> $CONFIG
+10
View File
@@ -0,0 +1,10 @@
@echo off
rem Testbilder aller Glyphen eines Fonts nach %PICCREATE_OUT% schreiben
setlocal
call "%~dp0setenv.bat" || exit /b 1
if "%~1"=="" (
echo please give a directory in the in folder with .svg glyphs as input
exit /b 1
)
"%PICCREATE_PYTHON%" "%PICCREATE_LIBS%\glyphextract.py" -t %1
exit /b %errorlevel%
+3 -18
View File
@@ -2,23 +2,8 @@
. setenv.sh . setenv.sh
if [ -z "$1" ]; then if [ -z "$1" ]; then
echo "please give a directory in the templates folder with .svg glyphs as input" echo "please give a directory in the in folder with .svg glyphs as input"
exit 1 exit 1
fi fi
if [ -d "$PICCREATE_IN/$1" ]; then # Testbilder aller Glyphen eines Fonts nach $PICCREATE_OUT schreiben
export SOURCE="$PICCREATE_IN/$1" python3 $PICCREATE_LIBS/glyphextract.py -t "$1"
elif [ ! -d "$1" ]; then
export SOURCE="$1"
else
echo "directory does not exist"
echo "please give a directory with .svg files as input"
exit 1
fi
export TARGET=$PICCREATE_OUT
for i in `ls $SOURCE/*.svg`
do
echo `basename $i .svg`
$PICCREATE_BIN/extract-glyph.sh -i $i
done
+6
View File
@@ -0,0 +1,6 @@
@echo off
rem Startet das Programm
setlocal
call "%~dp0setenv.bat" || exit /b 1
"%PICCREATE_PYTHON%" "%PICCREATE_LIBS%\piccreate.py" %*
exit /b %errorlevel%
+38
View File
@@ -0,0 +1,38 @@
@echo off
rem ------------------
rem Umgebung fuer piccreate unter Windows setzen
rem (Gegenstueck zu setenv.sh, wird von den anderen .bat Dateien aufgerufen)
rem ------------------
rem Wo ist das Programm hinkopiert: das Verzeichnis ueber bin\
if not defined PICCREATE for %%I in ("%~dp0..") do set "PICCREATE=%%~fI"
echo setting environment to %PICCREATE%
set "PICCREATE_BIN=%PICCREATE%\bin"
set "PICCREATE_CFG=%PICCREATE%\cfg"
set "PICCREATE_LIBS=%PICCREATE%\libs"
set "PICCREATE_FONTS=%PICCREATE%\fonts"
set "PICCREATE_IN=%PICCREATE%\in"
set "PICCREATE_OUT=%PICCREATE%\out"
set "PICCREATE_BACKGROUNDS=%PICCREATE%\backgrounds"
set "PICCREATE_LOG=%PICCREATE%\log"
rem Wo sind die Pythonskripte ?
set "PYTHONPATH=%PICCREATE_LIBS%;%PYTHONPATH%"
rem Dateien und Ausgaben immer als UTF-8
set "PYTHONUTF8=1"
rem Welches Python: zuerst das aus .venv, dann der Python Launcher "py",
rem dann "python" aus dem PATH
if defined PICCREATE_PYTHON exit /b 0
if exist "%PICCREATE%\.venv\Scripts\python.exe" (
set "PICCREATE_PYTHON=%PICCREATE%\.venv\Scripts\python.exe"
exit /b 0
)
for /f "delims=" %%P in ('py -3 -c "import sys; print(sys.executable)" 2^>nul') do set "PICCREATE_PYTHON=%%P"
if defined PICCREATE_PYTHON exit /b 0
for /f "delims=" %%P in ('python -c "import sys; print(sys.executable)" 2^>nul') do set "PICCREATE_PYTHON=%%P"
if defined PICCREATE_PYTHON exit /b 0
echo Python 3 not found. Please install it from https://www.python.org
echo or with: winget install Python.Python.3.13
exit /b 1
+47
View File
@@ -0,0 +1,47 @@
@echo off
rem ================================================================
rem PICCREATE - Python Virtual Environment einrichten (Windows)
rem ================================================================
setlocal
rem nicht das Python aus einer alten .venv nehmen
set "PICCREATE_PYTHON="
if exist "%~dp0..\.venv\Scripts\python.exe" goto :installed
rem Python fuer das Anlegen der .venv suchen
for /f "delims=" %%P in ('py -3 -c "import sys; print(sys.executable)" 2^>nul') do set "PICCREATE_PYTHON=%%P"
if not defined PICCREATE_PYTHON for /f "delims=" %%P in ('python -c "import sys; print(sys.executable)" 2^>nul') do set "PICCREATE_PYTHON=%%P"
if not defined PICCREATE_PYTHON (
echo Python 3 nicht gefunden. Bitte installieren von https://www.python.org
echo oder mit: winget install Python.Python.3.13
exit /b 1
)
call "%~dp0setenv.bat" || exit /b 1
echo Initialisiere Python virtual environment...
"%PICCREATE_PYTHON%" -m venv "%PICCREATE%\.venv" --upgrade-deps
if errorlevel 1 (
rmdir /s /q "%PICCREATE%\.venv" 2>nul
echo Fehlgeschlagen.
exit /b 1
)
echo Erfolgreich.
echo Installiere erforderliche Python Packages...
"%PICCREATE%\.venv\Scripts\pip" install -r "%PICCREATE%\requirements.txt" -q || exit /b 1
echo Erfolgreich.
goto :browser
:installed
call "%~dp0setenv.bat" || exit /b 1
echo Erforderliche Python Packages bereits installiert!
:browser
rem Browser fuer webscan
if exist "%LOCALAPPDATA%\ms-playwright\chromium*" (
echo Playwright Browser bereits installiert!
exit /b 0
)
echo Installiere Playwright Browser...
"%PICCREATE%\.venv\Scripts\playwright" install chromium || exit /b 1
echo Erfolgreich.
exit /b 0
+6
View File
@@ -0,0 +1,6 @@
@echo off
rem SVG Bilder mit ImageMagick in JPG/PNG umwandeln
setlocal
call "%~dp0setenv.bat" || exit /b 1
"%PICCREATE_PYTHON%" "%PICCREATE_LIBS%\svgconvert.py" %*
exit /b %errorlevel%
+6
View File
@@ -0,0 +1,6 @@
@echo off
rem Vorschaubilder von Webseiten erzeugen (Playwright)
setlocal
call "%~dp0setenv.bat" || exit /b 1
"%PICCREATE_PYTHON%" "%PICCREATE_LIBS%\webscan.py" %*
exit /b %errorlevel%
+42 -8
View File
@@ -19,17 +19,20 @@ Die Punkte werden über das ganze Wort fortlaufend nummeriert (1–32).
## Voraussetzungen ## Voraussetzungen
- Python 3 (für `piccreate.py` und `svgconvert.py` keine weiteren Pakete nötig) - Python 3 (für `piccreate.py`, `svgconvert.py` und `glyphextract.py` keine
- ImageMagick (`convert`) für die Umwandlung SVG → JPG/PNG mit `svgconvert.py` weiteren Pakete nötig)
- `bash`, `bc`, `sed`, `grep` für die Font-Werkzeuge in `bin/` - ImageMagick (`magick`, ältere Versionen `convert`) für die Umwandlung
SVG → JPG/PNG mit `svgconvert.py`
- nur für Webseiten-Vorschauen (`webscan`): Playwright, siehe unten - nur für Webseiten-Vorschauen (`webscan`): Playwright, siehe unten
Alles läuft unter Linux und Windows, siehe [Windows](#windows).
## Verzeichnisse ## Verzeichnisse
| Verzeichnis | Inhalt | | Verzeichnis | Inhalt |
|----------------|-----------------------------------------------------------| |----------------|-----------------------------------------------------------|
| `bin/` | Shell-Skripte (Aufruf, Umgebung, Font-Extraktion) | | `bin/` | Startskripte: `.sh` für Linux, `.bat` für Windows |
| `libs/` | Python-Programme `piccreate.py`, `svgconvert.py`, `webscan.py` | | `libs/` | Python-Programme `piccreate.py`, `svgconvert.py`, `webscan.py`, `glyphextract.py` |
| `cfg/` | Auftrags-Konfigurationen (`*.cfg`) | | `cfg/` | Auftrags-Konfigurationen (`*.cfg`) |
| `in/` | Eingabedateien (`*.csv`) und Rohglyphen für neue Fonts | | `in/` | Eingabedateien (`*.csv`) und Rohglyphen für neue Fonts |
| `out/` | Ausgabe der erzeugten Bilder | | `out/` | Ausgabe der erzeugten Bilder |
@@ -240,9 +243,40 @@ Neue Fonts entstehen aus in Inkscape gezeichneten Glyphen (Punkte als Kreise,
Nummern als Text `x1`, `x2`, …): Nummern als Text `x1`, `x2`, …):
```sh ```sh
./extract-font.sh ausgangsschrift # Glyphen aus in/ausgangsschrift/ extrahieren ./extract-font.sh ausgangsschrift # Glyphen + ausgangsschrift.cfg erzeugen
./fonttest.sh ausgangsschrift # Testbilder der einzelnen Glyphen erzeugen ./fonttest.sh ausgangsschrift # Testbilder der einzelnen Glyphen erzeugen
./extract-glyph.sh -i ../in/ausgangsschrift/a.svg -e # nur ein Buchstabe
``` ```
Das Ergebnis (Glyph-SVGs und `.cfg`) wird anschließend nach `fonts/<name>/` Alle drei rufen `libs/glyphextract.py` auf (`-f`, `-t` bzw. `-i [-e]`) und
übernommen. schreiben nach `$PICCREATE_OUT` (oder `-o <ordner>`). Das Ergebnis
(Glyph-SVGs und `<name>.cfg`) wird anschließend nach `fonts/<name>/`
übernommen. Werte wie `XSTEP` kann man danach in der `.cfg` noch von Hand
anpassen.
## Windows
Für jedes Shell-Skript in `bin/` gibt es eine `.bat`-Datei mit denselben
Optionen: `piccreate.bat`, `svgconvert.bat`, `webscan.bat`,
`extract-glyph.bat`, `extract-font.bat`, `fonttest.bat`, `setup-venv.bat`.
`setenv.bat` setzt die Umgebung; das Projektverzeichnis ermittelt es selbst
(das Verzeichnis über `bin\`), ein fester Pfad ist nicht nötig.
Einrichten:
1. Python 3 installieren (https://www.python.org oder
`winget install Python.Python.3.13`)
2. ImageMagick installieren (https://imagemagick.org), nur für `svgconvert`
3. nur für `webscan`: `bin\setup-venv.bat` ausführen (legt `.venv` an und
installiert Playwright mit Chromium)
Beispiel:
```bat
cd bin
piccreate.bat -c punkteraetsel -i test
svgconvert.bat -c punkteraetsel.cfg --format png -p
```
Die `.bat`-Dateien nehmen das Python aus `.venv`, falls vorhanden, sonst den
Python Launcher `py` oder `python` aus dem `PATH`.
+246
View File
@@ -0,0 +1,246 @@
#!/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'(?<!\w)(?=\w)'
WE = r'(?<=\w)(?!\w)'
LINE_IN = re.compile('<' + WB + 'line' + WE + '|x1|x2|y1|y2|/>|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 = '<svg xmlns="http://www.w3.org/2000/svg" version="1.1">'
TEST_END = '</svg>'
GLYPH_BEGIN = '<g transform="translate(${posx},${posy})">'
GLYPH_END = '</g>'
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 '<g' not in line and 'transform=' in line:
value = re.sub(r'^\s+', '', line).replace('translate', '').replace('transform=', '')
value = re.sub(r'["|()]', '', value)
if axis == 'x':
value = re.sub(r',.*', '', value)
else:
value = re.sub(r'.*,', '', value)
values.append(value)
# Linien: x1/x2 bzw. y1/y2
for name in (axis + '1=', axis + '2='):
for line in glyph_lines:
if name in line:
values.append(re.sub(r'^\s+', '', line).replace(name, '').replace('"', ''))
values = sorted(set(values), key=number_key)
if not values:
return '', ''
return values[0], values[-1]
def difference(maximum, minimum):
''' maximum - minimum, formatiert wie bc '''
try:
a, b = Decimal(maximum), Decimal(minimum)
except InvalidOperation:
return ''
scale = max(-a.as_tuple().exponent, -b.as_tuple().exponent, 0)
result = (a - b).quantize(Decimal(1).scaleb(-scale))
if result == 0:
return '0'
text = format(result, 'f')
return text.replace('-0.', '-.') if text.startswith('-0.') else re.sub(r'^0\.', '.', text)
def extract_glyph(svg_path, extract=True):
''' liefert (Glyph-SVG, Fontconfig-Sektion) für einen Buchstaben '''
with open(svg_path, encoding='utf-8', newline='') as fh:
source = split_lines(fh.read())
lines = [strip_center(l) for l in source if LINE_IN.search(l) and not LINE_OUT.search(l)]
circles = [strip_center(l) for l in source if CIRCLE_IN.search(l)]
texts = [strip_center(l) for l in source if TEXT_IN.search(l) and not TEXT_OUT.search(l)]
if extract:
glyph = [GLYPH_BEGIN] + texts + circles + lines + [GLYPH_END]
else:
glyph = [TEST_BEGIN] + texts + circles + lines + [TEST_END]
xmin, xmax = coordinates(glyph, 'x')
ymin, ymax = coordinates(glyph, 'y')
# Anzahl der Platzhalter x1..xn, dann durch Templatezeichen ${x1} ersetzen
npattern = sum(1 for l in glyph if re.search(r'>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 <font>.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:
+4 -2
View File
@@ -10,6 +10,7 @@ import optparse
import os import os
import re import re
import configparser import configparser
import pathlib
from utils import CSVImport, CompleteEnding, get_translation from utils import CSVImport, CompleteEnding, get_translation
from string import Template from string import Template
@@ -39,12 +40,13 @@ def create_picture_frame( config ):
try: try:
params['background'] = config.get('globals', 'background') params['background'] = config.get('globals', 'background')
imagetpl = ''' <image width="${width}" height="${height}" imagetpl = ''' <image width="${width}" height="${height}"
xlink:href="file://${background}"> xlink:href="${background}">
</image> </image>
''' '''
background = config.get('globals', 'background') background = config.get('globals', 'background')
font_path = os.path.expandvars(os.path.join('$PICCREATE_BACKGROUNDS', background )) font_path = os.path.expandvars(os.path.join('$PICCREATE_BACKGROUNDS', background ))
params['background'] = os.path.normpath(font_path) # als file:// URL, damit es auch mit Windows-Pfaden (C:\...) klappt
params['background'] = pathlib.Path(os.path.abspath(font_path)).as_uri()
svgbegin = svgbegin + Template( imagetpl ).substitute(params) svgbegin = svgbegin + Template( imagetpl ).substitute(params)
except configparser.NoOptionError: except configparser.NoOptionError:
# dann eben kein Hintergrundbild # dann eben kein Hintergrundbild
+1 -1
View File
@@ -96,7 +96,7 @@ def bufcount(filename):
if not os.path.exists(filename): if not os.path.exists(filename):
raise Exception raise Exception
try: try:
fh = open(filename) fh = open(filename, encoding='utf-8', errors='replace')
lines = 0 lines = 0
buf_size = 1024 * 1024 buf_size = 1024 * 1024
read_f = fh.read # loop optimization read_f = fh.read # loop optimization
+18 -8
View File
@@ -11,6 +11,7 @@ import cProfile
import optparse import optparse
import configparser import configparser
import re import re
import shutil
import subprocess import subprocess
import csv import csv
from string import Template from string import Template
@@ -18,10 +19,14 @@ from concurrent import futures
from progressbar import EasyProgressBar from progressbar import EasyProgressBar
# ImageMagick 7 heisst "magick"; unter Windows ist "convert" ein Systemprogramm
IMAGEMAGICK = shutil.which('magick') or shutil.which('convert')
def get_translation(cfg_path, sec_name): def get_translation(cfg_path, sec_name):
""" lädt die Zuordnung zwischen einem .csv Eingabefile und den Attributen""" """ lädt die Zuordnung zwischen einem .csv Eingabefile und den Attributen"""
config = configparser.RawConfigParser() config = configparser.RawConfigParser()
config.read(cfg_path) config.read(cfg_path, encoding='utf-8')
trans = dict(config.items(sec_name)) trans = dict(config.items(sec_name))
return dict([[v,k] for k,v in trans.items()]) return dict([[v,k] for k,v in trans.items()])
@@ -42,12 +47,14 @@ def convertSVG(in_path,filename,pic_config):
if options.verbose: if options.verbose:
print (filename, 'already exist!') print (filename, 'already exist!')
else: else:
background = " -background " + pic_config['background'] + " " cmdline = [IMAGEMAGICK,
resize = " -resize " + pic_config['width'] + "x" + pic_config['height'] + " " '-density', pic_config['density'],
density = " -density " + pic_config['density'] '-background', pic_config['background'],
cmd = "convert" inpath,
'-resize', pic_config['width'] + "x" + pic_config['height'],
jpgpath]
if not options.dry: if not options.dry:
subprocess.check_call(cmd + density + background + inpath + resize + jpgpath, shell = True) subprocess.check_call(cmdline)
if options.verbose: if options.verbose:
print ('start converting', filename) print ('start converting', filename)
Epb.slide_progbar() Epb.slide_progbar()
@@ -111,6 +118,9 @@ font-weight:normal;font-stretch:normal;font-family:Ubuntu;\
def main(): def main():
"""get all information from the switches an start the parallel conversion""" """get all information from the switches an start the parallel conversion"""
if not IMAGEMAGICK and not options.dry:
print('ImageMagick not found. Please install it (https://imagemagick.org).')
return None
#set the workpath and the default config #set the workpath and the default config
work_path = os.path.expandvars('$PICCREATE_OUT') work_path = os.path.expandvars('$PICCREATE_OUT')
if options.svgfolder: if options.svgfolder:
@@ -149,7 +159,7 @@ def main():
print('\"'+ config_path +'\" does not exist. Please give the name of a config file!') print('\"'+ config_path +'\" does not exist. Please give the name of a config file!')
return None return None
config = configparser.RawConfigParser() config = configparser.RawConfigParser()
config.read(config_path) config.read(config_path, encoding='utf-8')
# fill the config # fill the config
pic_config = dict(config.items(options.format)) pic_config = dict(config.items(options.format))
if options.background: if options.background:
@@ -173,7 +183,7 @@ def main():
print ("you must give a config file for checking the svg files") print ("you must give a config file for checking the svg files")
return None return None
svglist = [] svglist = []
with open(csv_path, newline='') as csvfile: with open(csv_path, newline='', encoding='utf-8') as csvfile:
reader = csv.DictReader(csvfile,delimiter = ';') reader = csv.DictReader(csvfile,delimiter = ';')
for row in reader: for row in reader:
if row[pic_config['customerid']] not in filelist: if row[pic_config['customerid']] not in filelist:
+18 -6
View File
@@ -37,6 +37,10 @@ INSTALL_HINTS = {
export PICCREATE_BROWSER=/usr/bin/chromium export PICCREATE_BROWSER=/usr/bin/chromium
or the Playwright browser: or the Playwright browser:
{venv}/bin/playwright install chromium''', {venv}/bin/playwright install chromium''',
'windows': r'''Windows (or simply run bin\setup-venv.bat):
py -m venv {venv}
{venv}\Scripts\pip install -r {project}\requirements.txt
{venv}\Scripts\playwright install chromium''',
} }
BROWSER_HINTS = { BROWSER_HINTS = {
@@ -48,11 +52,16 @@ BROWSER_HINTS = {
export PICCREATE_BROWSER=/usr/bin/chromium export PICCREATE_BROWSER=/usr/bin/chromium
or the Playwright browser: or the Playwright browser:
{venv}/bin/playwright install chromium''', {venv}/bin/playwright install chromium''',
'windows': r'''Windows:
{venv}\Scripts\playwright install chromium''',
} }
def linux_distro(): def platform_name():
''' liefert 'ubuntu' oder 'arch' (aus /etc/os-release), sonst None ''' ''' liefert 'windows', 'ubuntu' oder 'arch' (aus /etc/os-release),
sonst None '''
if sys.platform == 'win32':
return 'windows'
try: try:
with open('/etc/os-release', encoding='utf-8') as fh: with open('/etc/os-release', encoding='utf-8') as fh:
info = dict(line.rstrip('\n').split('=', 1) for line in fh if '=' in line) info = dict(line.rstrip('\n').split('=', 1) for line in fh if '=' in line)
@@ -67,10 +76,13 @@ def linux_distro():
def print_hint(hints): def print_hint(hints):
''' gibt die Installationshinweise für diese Distribution aus ''' gibt die Installationshinweise für dieses System aus
(bei unbekannter Distribution alle) ''' (bei unbekanntem Linux die für alle Linux-Distributionen) '''
distro = linux_distro() distro = platform_name()
keys = [distro] if distro in hints else sorted(hints) if distro in hints:
keys = [distro]
else:
keys = sorted(k for k in hints if k != 'windows')
for key in keys: for key in keys:
print(hints[key].format(venv=VENV, project=PROJECT_DIR), file=sys.stderr) print(hints[key].format(venv=VENV, project=PROJECT_DIR), file=sys.stderr)