Background is now white, export to png or pdf is possible
This commit is contained in:
parent
29a7a66085
commit
308ccd5a6c
3 changed files with 69 additions and 38 deletions
11
README.md
11
README.md
|
@ -1,4 +1,4 @@
|
||||||
# qrr-py
|
# qrr.py
|
||||||
|
|
||||||
Erstelle ein vektorisierter QR Code für die [QR Rechnung](
|
Erstelle ein vektorisierter QR Code für die [QR Rechnung](
|
||||||
https://www.einfach-zahlen.ch/de/home/issuer/qr-bill.html).
|
https://www.einfach-zahlen.ch/de/home/issuer/qr-bill.html).
|
||||||
|
@ -9,9 +9,10 @@ SVG Datei daraus.
|
||||||
|
|
||||||
## Installationsanleitung
|
## Installationsanleitung
|
||||||
|
|
||||||
Zuerst müssen Sie Python3 für Ihr Betriebssystem installieren.
|
Zuerst müssen Sie [Python3](https://www.python.org/)
|
||||||
|
für Ihr Betriebssystem installieren.
|
||||||
|
|
||||||
Mit `pip3 install --user qrcode svgutils` können sie sich die
|
Mit `pip3 install --user qrcode svgutils cairosvg` können sie sich die
|
||||||
notwendigen Pakete herunterladen.
|
notwendigen Pakete herunterladen.
|
||||||
|
|
||||||
## Ausführen des Programms
|
## Ausführen des Programms
|
||||||
|
@ -21,8 +22,8 @@ gestartet.
|
||||||
Wenn das Programm keinen Output generiert, so gab es keine Fehler und
|
Wenn das Programm keinen Output generiert, so gab es keine Fehler und
|
||||||
die SVG Datei sollte erstellt sein.
|
die SVG Datei sollte erstellt sein.
|
||||||
|
|
||||||
# `CH-Kreuz_7mm.svg` Datei
|
# CH-Kreuz
|
||||||
Diese Datei ist von [SIX Group AG](
|
Diese Graphik ist von [SIX Group AG](
|
||||||
https://www.paymentstandards.ch/de/home/software-partner.html) zur
|
https://www.paymentstandards.ch/de/home/software-partner.html) zur
|
||||||
Verfügung gestellt. Der direkte Download ist dieser:
|
Verfügung gestellt. Der direkte Download ist dieser:
|
||||||
https://www.paymentstandards.ch/dam/downloads/swiss-cross.zip
|
https://www.paymentstandards.ch/dam/downloads/swiss-cross.zip
|
||||||
|
|
30
ch_kreuz.py
30
ch_kreuz.py
|
@ -5,16 +5,20 @@ import svgutils.transform as st
|
||||||
|
|
||||||
def swisscross():
|
def swisscross():
|
||||||
return st.fromstring(
|
return st.fromstring(
|
||||||
'<?xml version="1.0" encoding="utf-8"?>\
|
'<svg width="49.5mm" height="49.5mm" version="1.1" viewBox="0 0 49.5 49.5" xmlns="http://www.w3.org/2000/svg">\
|
||||||
<svg width="7mm" height="7mm" version="1.1" id="Ebene_2" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"\
|
<style type="text/css">.st0{fill:#FFFFFF;}\
|
||||||
viewBox="0 0 19.8 19.8" style="enable-background:new 0 0 19.8 19.8;" xml:space="preserve">\
|
.st1{fill:none;stroke:#FFFFFF;stroke-width:1.4357;stroke-miterlimit:10;}</style>\
|
||||||
<style type="text/css">\
|
<style type="text/css">.st0{fill:#FFFFFF;}\
|
||||||
.st0{fill:#FFFFFF;}\
|
.st1{fill:none;stroke:#FFFFFF;stroke-width:1.4357;stroke-miterlimit:10;}</style>\
|
||||||
.st1{fill:none;stroke:#FFFFFF;stroke-width:1.4357;stroke-miterlimit:10;}\
|
<polygon transform="matrix(.34905 0 0 .34905 21.294 21.294)" points="0.7 18.3 0.7 19.1 1.6 19.1 18.3 19.1 19.1 19.1 19.1 18.3 19.1 1.6 19.1 0.7 18.3 0.7 1.6 0.7 0.7 0.7 0.7 1.6"/>\
|
||||||
</style>\
|
<rect class="st0" x="24.192" y="22.691" width="1.1519" height="3.8396" stroke-width=".34905"/>\
|
||||||
<polygon points="18.3,0.7 1.6,0.7 0.7,0.7 0.7,1.6 0.7,18.3 0.7,19.1 1.6,19.1 18.3,19.1 19.1,19.1 19.1,18.3 19.1,1.6 19.1,0.7 "/>\
|
<rect class="st0" x="22.83" y="24.052" width="3.8396" height="1.1519" stroke-width=".34905"/>\
|
||||||
<rect x="8.3" y="4" class="st0" width="3.3" height="11"/>\
|
<polygon class="st1" transform="matrix(.34905 0 0 .34905 21.294 21.294)" points="18.3 19.1 19.1 19.1 19.1 18.3 19.1 1.6 19.1 0.7 18.3 0.7 1.6 0.7 0.7 0.7 0.7 1.6 0.7 18.3 0.7 19.1 1.6 19.1"/>\
|
||||||
<rect x="4.4" y="7.9" class="st0" width="11" height="3.3"/>\
|
</svg>'
|
||||||
<polygon class="st1" points="0.7,1.6 0.7,18.3 0.7,19.1 1.6,19.1 18.3,19.1 19.1,19.1 19.1,18.3 19.1,1.6 19.1,0.7 18.3,0.7 1.6,0.7 0.7,0.7 "/>\
|
)
|
||||||
</svg>'
|
|
||||||
).getroot()
|
def white():
|
||||||
|
return st.fromstring(
|
||||||
|
'<svg width="49.5mm" height="49.5mm" version="1.1" viewBox="0 0 49.5 49.5" xmlns="http://www.w3.org/2000/svg">\
|
||||||
|
<rect x="0" y="0" width="49.5" height="49.5" fill="#fff"/>\
|
||||||
|
</svg>')
|
||||||
|
|
66
qrr.py
66
qrr.py
|
@ -5,6 +5,10 @@ import qrcode
|
||||||
import qrcode.image.svg
|
import qrcode.image.svg
|
||||||
from svgutils import transform as st
|
from svgutils import transform as st
|
||||||
from ch_kreuz import swisscross as get_swisscross
|
from ch_kreuz import swisscross as get_swisscross
|
||||||
|
from ch_kreuz import white as get_white
|
||||||
|
from svgutils.compose import Figure
|
||||||
|
from cairosvg import (svg2pdf, svg2png)
|
||||||
|
|
||||||
|
|
||||||
class qr_rechnung():
|
class qr_rechnung():
|
||||||
data = ''
|
data = ''
|
||||||
|
@ -26,7 +30,6 @@ class qr_rechnung():
|
||||||
mode = 'w' if force else 'x'
|
mode = 'w' if force else 'x'
|
||||||
try:
|
try:
|
||||||
assert force or not os.path.isfile(filepath)
|
assert force or not os.path.isfile(filepath)
|
||||||
factory = qrcode.image.svg.SvgPathImage
|
|
||||||
img = qrcode.make(
|
img = qrcode.make(
|
||||||
self.data,
|
self.data,
|
||||||
error_correction=qrcode.constants.ERROR_CORRECT_M,
|
error_correction=qrcode.constants.ERROR_CORRECT_M,
|
||||||
|
@ -38,28 +41,29 @@ class qr_rechnung():
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
qrcode = st.fromfile(filepath)
|
qrcode = st.fromfile(filepath)
|
||||||
offset = self.calc_move_offset(qrcode.get_size()[0])
|
try:
|
||||||
swisscross = get_swisscross()
|
assert qrcode.width[-2:] == 'mm'
|
||||||
swisscross.moveto(
|
qr_scale = 49.5/float(qrcode.width[:-2])
|
||||||
x=offset['offset'],
|
except AssertionError as e:
|
||||||
y=offset['offset'],
|
print(f"ERROR: Ein unerwarteter Fall in der Skallierung.")
|
||||||
scale_x=offset['scale'],
|
print(e)
|
||||||
scale_y=offset['scale']
|
return 1
|
||||||
)
|
|
||||||
qrcode.append(swisscross)
|
|
||||||
qrcode.save(filepath)
|
|
||||||
|
|
||||||
def calc_move_offset(self, size):
|
qrr = Figure(
|
||||||
org = float(size[:-2])
|
'49.5mm', '49.5mm',
|
||||||
return {
|
get_white().getroot(),
|
||||||
'offset': org*0.427935156,
|
qrcode.getroot().scale(qr_scale),
|
||||||
'scale': org/137.364857143
|
get_swisscross().getroot()
|
||||||
}
|
)
|
||||||
|
qrr.save(filepath)
|
||||||
|
|
||||||
|
|
||||||
def help(args):
|
def help(args):
|
||||||
return '{0}: Ungültige Eingabe\nAufruf: \
|
return '\n'.join([
|
||||||
{0} TEXTDATEI [SVG-ZIELDATEI]'.format(args[0])
|
'{0}: Ungültige Eingabe',
|
||||||
|
'Aufruf: {0} TEXTDATEI [SVG-ZIELDATEI]',
|
||||||
|
'Alternativ kann die ZIELDATEI auch mit .pdf oder .png enden.'
|
||||||
|
]).format(args[0])
|
||||||
|
|
||||||
|
|
||||||
def main(args):
|
def main(args):
|
||||||
|
@ -69,7 +73,19 @@ def main(args):
|
||||||
print(help(args))
|
print(help(args))
|
||||||
return 1
|
return 1
|
||||||
try:
|
try:
|
||||||
|
output_format = 'svg'
|
||||||
svgfile = args[2]
|
svgfile = args[2]
|
||||||
|
if svgfile[-4:] == '.svg':
|
||||||
|
pass
|
||||||
|
elif svgfile[-4:] == '.png':
|
||||||
|
svgfile = svgfile[:-4]+'.svg'
|
||||||
|
output_format = 'png'
|
||||||
|
|
||||||
|
elif svgfile[-4:] == '.pdf':
|
||||||
|
svgfile = svgfile[:-4]+'.svg'
|
||||||
|
output_format = 'pdf'
|
||||||
|
else:
|
||||||
|
svgfile += '.svg'
|
||||||
except IndexError:
|
except IndexError:
|
||||||
try:
|
try:
|
||||||
assert textfile[-4:] == '.txt'
|
assert textfile[-4:] == '.txt'
|
||||||
|
@ -83,7 +99,17 @@ def main(args):
|
||||||
except (PermissionError, FileNotFoundError) as e:
|
except (PermissionError, FileNotFoundError) as e:
|
||||||
print(e)
|
print(e)
|
||||||
return 1
|
return 1
|
||||||
return 0
|
if output_format == 'svg':
|
||||||
|
return 0
|
||||||
|
elif output_format == 'png':
|
||||||
|
svg2png(url=svgfile, write_to=svgfile[:-4]+'.png', dpi=600)
|
||||||
|
return 0
|
||||||
|
elif output_format == 'pdf':
|
||||||
|
svg2pdf(url=svgfile, write_to=svgfile[:-4]+'.pdf')
|
||||||
|
return 0
|
||||||
|
else:
|
||||||
|
print(f"ERROR: Unbekanntes Output_format: {output_format}")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
Loading…
Reference in a new issue