From 29c066b45adf4dbdbc1687d43a893022013c1232 Mon Sep 17 00:00:00 2001 From: Michael Stangl Date: Fri, 9 Oct 2026 09:29:02 +0200 Subject: [PATCH] =?UTF-8?q?Windows-Unterst=C3=BCtzung:=20.bat-Skripte,=20F?= =?UTF-8?q?ont-Werkzeuge=20in=20Python?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 .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 --- .gitattributes | 3 + bin/extract-font.bat | 10 ++ bin/extract-font.sh | 23 +--- bin/extract-glyph.bat | 6 ++ bin/extract-glyph.sh | 150 +------------------------- bin/fonttest.bat | 10 ++ bin/fonttest.sh | 21 +--- bin/piccreate.bat | 6 ++ bin/setenv.bat | 38 +++++++ bin/setup-venv.bat | 47 ++++++++ bin/svgconvert.bat | 6 ++ bin/webscan.bat | 6 ++ doc/README.md | 50 +++++++-- libs/glyphextract.py | 246 ++++++++++++++++++++++++++++++++++++++++++ libs/piccreate.py | 6 +- libs/progressbar.py | 2 +- libs/svgconvert.py | 26 +++-- libs/webscan.py | 24 +++-- 18 files changed, 471 insertions(+), 209 deletions(-) create mode 100644 .gitattributes create mode 100644 bin/extract-font.bat create mode 100644 bin/extract-glyph.bat create mode 100644 bin/fonttest.bat create mode 100644 bin/piccreate.bat create mode 100644 bin/setenv.bat create mode 100644 bin/setup-venv.bat create mode 100644 bin/svgconvert.bat create mode 100644 bin/webscan.bat create mode 100644 libs/glyphextract.py diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..98a2356 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +*.bat text eol=crlf +*.sh text eol=lf +*.py text eol=lf diff --git a/bin/extract-font.bat b/bin/extract-font.bat new file mode 100644 index 0000000..db4d908 --- /dev/null +++ b/bin/extract-font.bat @@ -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% diff --git a/bin/extract-font.sh b/bin/extract-font.sh index 956b132..873bffa 100755 --- a/bin/extract-font.sh +++ b/bin/extract-font.sh @@ -2,25 +2,8 @@ . setenv.sh 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 fi -if [ -d "$PICCREATE_IN/$1" ]; then - export SOURCE="$PICCREATE_IN/$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) +# Glyphen und .cfg eines Fonts nach $PICCREATE_OUT schreiben +python3 $PICCREATE_LIBS/glyphextract.py -f "$1" diff --git a/bin/extract-glyph.bat b/bin/extract-glyph.bat new file mode 100644 index 0000000..bd220c5 --- /dev/null +++ b/bin/extract-glyph.bat @@ -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% diff --git a/bin/extract-glyph.sh b/bin/extract-glyph.sh index 35d63a1..3c86ce6 100755 --- a/bin/extract-glyph.sh +++ b/bin/extract-glyph.sh @@ -1,149 +1,7 @@ #!/bin/bash . setenv.sh -if [ -z "$PICCREATE" ]; then - echo "please source the environment" - exit 1 -fi - -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 '<\|x1|x2|y1|y2|/>|style' | egrep -v '\|id=|http:' > line-$BASE.svg -cat $ID | egrep 'circle|translate|\' > circles-$BASE.svg -cat $ID | egrep '<\>|\=|\=|tspan|style|preserve' | egrep -v '\|\=' > 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 '' >> $GLYPH - cat text-$BASE.svg >> $GLYPH - cat circles-$BASE.svg >> $GLYPH - cat line-$BASE.svg >> $GLYPH - echo '' >> $GLYPH -else - # schreib nur das extract zur Verwertung als Font in die Ausgabe - #echo '' >> $GLYPH - echo '' >> $GLYPH - cat text-$BASE.svg >> $GLYPH - cat circles-$BASE.svg >> $GLYPH - cat line-$BASE.svg >> $GLYPH - echo '' >> $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 "\=" | sed "s/^\s\+//g;s/x=//g;s/\"//g" > $XCOORDS -# dann aus Kreisen -cat $GLYPH | egrep -v '> $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 '> $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} $$ ; 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 - - - - - +# Einen Buchstaben extrahieren +# extract-glyph.sh -i ../in/ausgangsschrift/a.svg Testbild fuer Inkscape +# extract-glyph.sh -i ../in/ausgangsschrift/a.svg -e Glyph fuer den Font +python3 $PICCREATE_LIBS/glyphextract.py "$@" diff --git a/bin/fonttest.bat b/bin/fonttest.bat new file mode 100644 index 0000000..a25172f --- /dev/null +++ b/bin/fonttest.bat @@ -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% diff --git a/bin/fonttest.sh b/bin/fonttest.sh index b666235..e8664e5 100755 --- a/bin/fonttest.sh +++ b/bin/fonttest.sh @@ -2,23 +2,8 @@ . setenv.sh 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 fi -if [ -d "$PICCREATE_IN/$1" ]; then - export SOURCE="$PICCREATE_IN/$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 - +# Testbilder aller Glyphen eines Fonts nach $PICCREATE_OUT schreiben +python3 $PICCREATE_LIBS/glyphextract.py -t "$1" diff --git a/bin/piccreate.bat b/bin/piccreate.bat new file mode 100644 index 0000000..4dbe5d6 --- /dev/null +++ b/bin/piccreate.bat @@ -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% diff --git a/bin/setenv.bat b/bin/setenv.bat new file mode 100644 index 0000000..b9597dd --- /dev/null +++ b/bin/setenv.bat @@ -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 diff --git a/bin/setup-venv.bat b/bin/setup-venv.bat new file mode 100644 index 0000000..76327da --- /dev/null +++ b/bin/setup-venv.bat @@ -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 diff --git a/bin/svgconvert.bat b/bin/svgconvert.bat new file mode 100644 index 0000000..361e6ac --- /dev/null +++ b/bin/svgconvert.bat @@ -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% diff --git a/bin/webscan.bat b/bin/webscan.bat new file mode 100644 index 0000000..18ada1c --- /dev/null +++ b/bin/webscan.bat @@ -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% diff --git a/doc/README.md b/doc/README.md index 0ac1f63..0c72dab 100644 --- a/doc/README.md +++ b/doc/README.md @@ -19,17 +19,20 @@ Die Punkte werden über das ganze Wort fortlaufend nummeriert (1–32). ## Voraussetzungen -- Python 3 (für `piccreate.py` und `svgconvert.py` keine weiteren Pakete nötig) -- ImageMagick (`convert`) für die Umwandlung SVG → JPG/PNG mit `svgconvert.py` -- `bash`, `bc`, `sed`, `grep` für die Font-Werkzeuge in `bin/` +- Python 3 (für `piccreate.py`, `svgconvert.py` und `glyphextract.py` keine + weiteren Pakete nötig) +- ImageMagick (`magick`, ältere Versionen `convert`) für die Umwandlung + SVG → JPG/PNG mit `svgconvert.py` - nur für Webseiten-Vorschauen (`webscan`): Playwright, siehe unten +Alles läuft unter Linux und Windows, siehe [Windows](#windows). + ## Verzeichnisse | Verzeichnis | Inhalt | |----------------|-----------------------------------------------------------| -| `bin/` | Shell-Skripte (Aufruf, Umgebung, Font-Extraktion) | -| `libs/` | Python-Programme `piccreate.py`, `svgconvert.py`, `webscan.py` | +| `bin/` | Startskripte: `.sh` für Linux, `.bat` für Windows | +| `libs/` | Python-Programme `piccreate.py`, `svgconvert.py`, `webscan.py`, `glyphextract.py` | | `cfg/` | Auftrags-Konfigurationen (`*.cfg`) | | `in/` | Eingabedateien (`*.csv`) und Rohglyphen für neue Fonts | | `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`, …): ```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 +./extract-glyph.sh -i ../in/ausgangsschrift/a.svg -e # nur ein Buchstabe ``` -Das Ergebnis (Glyph-SVGs und `.cfg`) wird anschließend nach `fonts//` -übernommen. +Alle drei rufen `libs/glyphextract.py` auf (`-f`, `-t` bzw. `-i [-e]`) und +schreiben nach `$PICCREATE_OUT` (oder `-o `). Das Ergebnis +(Glyph-SVGs und `.cfg`) wird anschließend nach `fonts//` +ü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`. diff --git a/libs/glyphextract.py b/libs/glyphextract.py new file mode 100644 index 0000000..d8bdb26 --- /dev/null +++ b/libs/glyphextract.py @@ -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'(?|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: diff --git a/libs/piccreate.py b/libs/piccreate.py index c8b7be6..22d2cae 100644 --- a/libs/piccreate.py +++ b/libs/piccreate.py @@ -10,6 +10,7 @@ import optparse import os import re import configparser +import pathlib from utils import CSVImport, CompleteEnding, get_translation from string import Template @@ -39,12 +40,13 @@ def create_picture_frame( config ): try: params['background'] = config.get('globals', 'background') imagetpl = ''' + xlink:href="${background}"> ''' background = config.get('globals', '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) except configparser.NoOptionError: # dann eben kein Hintergrundbild diff --git a/libs/progressbar.py b/libs/progressbar.py index c86c1e8..7d03b1c 100644 --- a/libs/progressbar.py +++ b/libs/progressbar.py @@ -96,7 +96,7 @@ def bufcount(filename): if not os.path.exists(filename): raise Exception try: - fh = open(filename) + fh = open(filename, encoding='utf-8', errors='replace') lines = 0 buf_size = 1024 * 1024 read_f = fh.read # loop optimization diff --git a/libs/svgconvert.py b/libs/svgconvert.py index d2cc2e7..2f94f5e 100644 --- a/libs/svgconvert.py +++ b/libs/svgconvert.py @@ -11,6 +11,7 @@ import cProfile import optparse import configparser import re +import shutil import subprocess import csv from string import Template @@ -18,10 +19,14 @@ from concurrent import futures 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): """ lädt die Zuordnung zwischen einem .csv Eingabefile und den Attributen""" config = configparser.RawConfigParser() - config.read(cfg_path) + config.read(cfg_path, encoding='utf-8') trans = dict(config.items(sec_name)) return dict([[v,k] for k,v in trans.items()]) @@ -42,12 +47,14 @@ def convertSVG(in_path,filename,pic_config): if options.verbose: print (filename, 'already exist!') else: - background = " -background " + pic_config['background'] + " " - resize = " -resize " + pic_config['width'] + "x" + pic_config['height'] + " " - density = " -density " + pic_config['density'] - cmd = "convert" + cmdline = [IMAGEMAGICK, + '-density', pic_config['density'], + '-background', pic_config['background'], + inpath, + '-resize', pic_config['width'] + "x" + pic_config['height'], + jpgpath] if not options.dry: - subprocess.check_call(cmd + density + background + inpath + resize + jpgpath, shell = True) + subprocess.check_call(cmdline) if options.verbose: print ('start converting', filename) Epb.slide_progbar() @@ -111,6 +118,9 @@ font-weight:normal;font-stretch:normal;font-family:Ubuntu;\ def main(): """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 work_path = os.path.expandvars('$PICCREATE_OUT') if options.svgfolder: @@ -149,7 +159,7 @@ def main(): print('\"'+ config_path +'\" does not exist. Please give the name of a config file!') return None config = configparser.RawConfigParser() - config.read(config_path) + config.read(config_path, encoding='utf-8') # fill the config pic_config = dict(config.items(options.format)) if options.background: @@ -173,7 +183,7 @@ def main(): print ("you must give a config file for checking the svg files") return None svglist = [] - with open(csv_path, newline='') as csvfile: + with open(csv_path, newline='', encoding='utf-8') as csvfile: reader = csv.DictReader(csvfile,delimiter = ';') for row in reader: if row[pic_config['customerid']] not in filelist: diff --git a/libs/webscan.py b/libs/webscan.py index 0989e43..3c793c0 100644 --- a/libs/webscan.py +++ b/libs/webscan.py @@ -37,6 +37,10 @@ INSTALL_HINTS = { export PICCREATE_BROWSER=/usr/bin/chromium or the Playwright browser: {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 = { @@ -48,11 +52,16 @@ BROWSER_HINTS = { export PICCREATE_BROWSER=/usr/bin/chromium or the Playwright browser: {venv}/bin/playwright install chromium''', + 'windows': r'''Windows: + {venv}\Scripts\playwright install chromium''', } -def linux_distro(): - ''' liefert 'ubuntu' oder 'arch' (aus /etc/os-release), sonst None ''' +def platform_name(): + ''' liefert 'windows', 'ubuntu' oder 'arch' (aus /etc/os-release), + sonst None ''' + if sys.platform == 'win32': + return 'windows' try: with open('/etc/os-release', encoding='utf-8') as fh: 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): - ''' gibt die Installationshinweise für diese Distribution aus - (bei unbekannter Distribution alle) ''' - distro = linux_distro() - keys = [distro] if distro in hints else sorted(hints) + ''' gibt die Installationshinweise für dieses System aus + (bei unbekanntem Linux die für alle Linux-Distributionen) ''' + distro = platform_name() + if distro in hints: + keys = [distro] + else: + keys = sorted(k for k in hints if k != 'windows') for key in keys: print(hints[key].format(venv=VENV, project=PROJECT_DIR), file=sys.stderr)