Verified Commit 65b60848 authored by Robin Sonnabend's avatar Robin Sonnabend
Browse files

Port to python3

parent c3878fec
...@@ -38,7 +38,9 @@ savegames ...@@ -38,7 +38,9 @@ savegames
config.py config.py
schilder.wsgi schilder.wsgi
*.png.* *.png_*
*.schild.* *.schild_*
venv/ venv/
data/cache/
data/pdf/
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- encoding: utf8 -*-
from flask import Flask, flash, session, redirect, url_for, escape, request, Response, Markup from flask import Flask, flash, session, redirect, url_for, escape, request, Response, Markup, render_template
from jinja2 import Environment, PackageLoader
import sys import sys
import os import os
import os.path import os.path
import glob import glob
import werkzeug import werkzeug
# genshi expects old location, fix
werkzeug.cached_property = werkzeug.utils.cached_property
from genshi.template import TemplateLoader
from genshi.template.text import NewTextTemplate
from flaskext.genshi import Genshi, render_response
from werkzeug.utils import secure_filename from werkzeug.utils import secure_filename
from collections import defaultdict from collections import defaultdict
from docutils.core import publish_parts from docutils.core import publish_parts
from PIL import Image
from pdf2image import convert_from_path
import warnings import warnings
import shutil import shutil
import subprocess import subprocess as sp
from subprocess import CalledProcessError, STDOUT
import PythonMagick
import json import json
import tempfile import tempfile
import config import config
...@@ -31,43 +26,7 @@ app.config.update( ...@@ -31,43 +26,7 @@ app.config.update(
MAX_CONTENT_LENGTH = 8388608 MAX_CONTENT_LENGTH = 8388608
) )
app.secret_key = config.app_secret app.secret_key = config.app_secret
genshi = Genshi(app)
genshi.extensions['html'] = 'html5'
def check_output(*popenargs, **kwargs):
# Copied from py2.7s subprocess module
r"""Run command with arguments and return its output as a byte string.
If the exit code was non-zero it raises a CalledProcessError. The
CalledProcessError object will have the return code in the returncode
attribute and output in the output attribute.
The arguments are the same as for the Popen constructor. Example:
>>> check_output(["ls", "-l", "/dev/null"])
'crw-rw-rw- 1 root root 1, 3 Oct 18 2007 /dev/null\n'
The stdout argument is not allowed as it is used internally.
To capture standard error in the result, use stderr=STDOUT.
>>> check_output(["/bin/sh", "-c",
... "ls -l non_existent_file ; exit 0"],
... stderr=STDOUT)
'ls: non_existent_file: No such file or directory\n'
"""
if 'stdout' in kwargs:
raise ValueError('stdout argument not allowed, it will be overridden.')
process = subprocess.Popen(stdout=subprocess.PIPE, *popenargs, **kwargs)
output, unused_err = process.communicate()
retcode = process.poll()
if retcode != 0:
cmd = kwargs.get("args")
if cmd is None:
cmd = popenargs[0]
raise CalledProcessError(retcode, cmd, output=output)
#raise Exception(output)
return output
def allowed_file(filename): def allowed_file(filename):
return '.' in filename and filename.rsplit('.', 1)[1] in config.allowed_extensions return '.' in filename and filename.rsplit('.', 1)[1] in config.allowed_extensions
...@@ -87,11 +46,14 @@ def save_data(formdata, outfilename): ...@@ -87,11 +46,14 @@ def save_data(formdata, outfilename):
def run_pdflatex(context, outputfilename, overwrite=True): def run_pdflatex(context, outputfilename, overwrite=True):
if 'textemplate' not in context: if 'textemplate' not in context:
context['textemplate'] = "text-image-quer.tex" context['textemplate'] = "text-image-quer.tex"
genshitex = TemplateLoader([config.textemplatedir]) texenv = Environment(loader=PackageLoader("schilder", config.textemplatedir))
template = genshitex.load( texenv.variable_start_string = "${"
context['textemplate'], cls=NewTextTemplate, encoding='utf8') texenv.variable_end_string = "}"
if not overwrite and os.path.isfile(outputfilename) and os.path.getmtime(template.filepath) < os.path.getmtime(outputfilename): texenv.block_start_string = "${{{{{"
return texenv.block_end_string = "}}}}}"
template = texenv.get_template(context['textemplate'])
#if not overwrite and os.path.isfile(outputfilename) and os.path.getmtime(template.filepath) < os.path.getmtime(outputfilename):
# return
if context['markup'] == 'rst': if context['markup'] == 'rst':
context['text'] = publish_parts(context['text'], writer_name='latex')['body'] context['text'] = publish_parts(context['text'], writer_name='latex')['body']
#context['headline'] = publish_parts(context['headline'], writer_name='latex')['body'] #context['headline'] = publish_parts(context['headline'], writer_name='latex')['body']
...@@ -108,22 +70,17 @@ def run_pdflatex(context, outputfilename, overwrite=True): ...@@ -108,22 +70,17 @@ def run_pdflatex(context, outputfilename, overwrite=True):
tmptexfile = os.path.join(tmpdir, 'output.tex') tmptexfile = os.path.join(tmpdir, 'output.tex')
tmppdffile = os.path.join(tmpdir, 'output.pdf') tmppdffile = os.path.join(tmpdir, 'output.pdf')
with open(tmptexfile, 'w') as texfile: with open(tmptexfile, 'w') as texfile:
texfile.write(template.generate(form=context).render(encoding='utf8')) texfile.write(template.render(form=context))
cwd = os.getcwd()
os.chdir(tmpdir)
os.symlink(config.texsupportdir, os.path.join(tmpdir, 'support')) os.symlink(config.texsupportdir, os.path.join(tmpdir, 'support'))
try: try:
texlog = check_output( texlog = sp.check_output(['pdflatex', '--halt-on-error', tmptexfile], stderr=sp.STDOUT, cwd=tmpdir, universal_newlines=True)
['pdflatex', '--halt-on-error', tmptexfile], stderr=STDOUT) except sp.CalledProcessError as e:
except CalledProcessError as e:
if overwrite: if overwrite:
try: try:
flash(Markup("<p>PDFLaTeX Output:</p><pre>%s</pre>" % e.output), 'log') flash(Markup("<p>PDFLaTeX Output:</p><pre>%s</pre>" % e.output), 'log')
except: except:
print((e.output)) print((e.output))
raise SyntaxWarning("PDFLaTeX bailed out") raise SyntaxWarning("PDFLaTeX bailed out")
finally:
os.chdir(cwd)
if overwrite: if overwrite:
try: try:
flash(Markup("<p>PDFLaTeX Output:</p><pre>%s</pre>" % texlog), 'log') flash(Markup("<p>PDFLaTeX Output:</p><pre>%s</pre>" % texlog), 'log')
...@@ -141,22 +98,21 @@ def save_and_convert_image_upload(inputname): ...@@ -141,22 +98,21 @@ def save_and_convert_image_upload(inputname):
filename = os.path.join( filename = os.path.join(
config.uploaddir, secure_filename(imgfile.filename)) config.uploaddir, secure_filename(imgfile.filename))
imgfile.save(filename) imgfile.save(filename)
img = PythonMagick.Image(filename) img = Image.open(filename)
imgname = os.path.splitext(secure_filename(imgfile.filename))[ imgname = os.path.splitext(secure_filename(imgfile.filename))[
0].replace('.', '_') + '.png' 0].replace('.', '_') + '.png'
savedfilename = os.path.join(config.imagedir, imgname) savedfilename = os.path.join(config.imagedir, imgname)
img.write(savedfilename) img.save(savedfilename)
os.remove(filename) os.remove(filename)
return imgname return imgname
return None return None
def make_thumb(filename, maxgeometry): def make_thumb(filename, maxgeometry):
thumbpath = filename + '.' + str(maxgeometry) thumbpath = (filename.replace(config.imagedir, config.cachedir) + '_' + str(maxgeometry)).replace(".", "_") + ".png"
if not os.path.exists(thumbpath) or os.path.getmtime(filename) > os.path.getmtime(thumbpath): if not os.path.exists(thumbpath) or os.path.getmtime(filename) > os.path.getmtime(thumbpath):
img = PythonMagick.Image(str(filename)) img = Image.open(str(filename))
img.transform("%sx%s" % (maxgeometry, maxgeometry)) img = img.resize((maxgeometry, maxgeometry))
img.quality(90) img.save(thumbpath)
img.write(str("png:%s" % thumbpath))
return thumbpath return thumbpath
...@@ -167,7 +123,7 @@ def index(**kwargs): ...@@ -167,7 +123,7 @@ def index(**kwargs):
data.update(**kwargs) data.update(**kwargs)
filelist = glob.glob(config.datadir + '/*.schild') filelist = glob.glob(config.datadir + '/*.schild')
data['files'] = [str(os.path.basename(f)) for f in sorted(filelist)] data['files'] = [str(os.path.basename(f)) for f in sorted(filelist)]
return render_response('index.html', data) return render_template('index.html', **data)
@app.route('/edit') @app.route('/edit')
...@@ -180,7 +136,7 @@ def edit(**kwargs): ...@@ -180,7 +136,7 @@ def edit(**kwargs):
data['templates'] = [str(os.path.basename(f)) data['templates'] = [str(os.path.basename(f))
for f in sorted(templatelist)] for f in sorted(templatelist)]
data['imageextensions'] = config.allowed_extensions data['imageextensions'] = config.allowed_extensions
return render_response('edit.html', data) return render_template('edit.html', **data)
@app.route('/edit/<filename>') @app.route('/edit/<filename>')
...@@ -239,7 +195,7 @@ def create(): ...@@ -239,7 +195,7 @@ def create():
@app.route('/schild/<filename>') @app.route('/schild/<filename>')
def schild(filename): def schild(filename):
return render_response('schild.html', {'filename': filename, 'printer': [str(f) for f in sorted(config.printers.keys())]}) return render_template('schild.html', filename=filename, printer=[str(f) for f in sorted(config.printers.keys())])
@app.route('/printout', methods=['POST']) @app.route('/printout', methods=['POST'])
...@@ -250,10 +206,10 @@ def printout(): ...@@ -250,10 +206,10 @@ def printout():
copies = int(request.form['copies']) or 0 copies = int(request.form['copies']) or 0
if copies > 0 and copies <= 6: if copies > 0 and copies <= 6:
try: try:
lprout = check_output(['lpr', '-H', str(config.printserver), '-P', str( lprout = sp.check_output(['lpr', '-H', str(config.printserver), '-P', str(
printer), '-#', str(copies)] + config.lproptions + [filename], stderr=STDOUT) printer), '-#', str(copies)] + config.lproptions + [filename], stderr=sp.STDOUT)
flash('Schild wurde zum Drucker geschickt!') flash('Schild wurde zum Drucker geschickt!')
except CalledProcessError as e: except sp.CalledProcessError as e:
flash(Markup("<p>Could not print:</p><pre>%s</pre>" % e.output), 'error') flash(Markup("<p>Could not print:</p><pre>%s</pre>" % e.output), 'error')
else: else:
flash('Ungültige Anzahl Kopien!') flash('Ungültige Anzahl Kopien!')
...@@ -286,7 +242,7 @@ def image(imgname): ...@@ -286,7 +242,7 @@ def image(imgname):
imgpath = os.path.join(config.imagedir, secure_filename(imgname)) imgpath = os.path.join(config.imagedir, secure_filename(imgname))
# print(imgpath) # print(imgpath)
if os.path.exists(imgpath): if os.path.exists(imgpath):
with open(imgpath, 'r') as imgfile: with open(imgpath, 'rb') as imgfile:
return Response(imgfile.read(), mimetype="image/png") return Response(imgfile.read(), mimetype="image/png")
else: else:
return "Meh" # redirect(url_for('index')) return "Meh" # redirect(url_for('index'))
...@@ -296,15 +252,18 @@ def image(imgname): ...@@ -296,15 +252,18 @@ def image(imgname):
def thumbnail(imgname, maxgeometry): def thumbnail(imgname, maxgeometry):
imgpath = os.path.join(config.imagedir, secure_filename(imgname)) imgpath = os.path.join(config.imagedir, secure_filename(imgname))
thumbpath = make_thumb(imgpath, maxgeometry) thumbpath = make_thumb(imgpath, maxgeometry)
with open(thumbpath, 'r') as imgfile: with open(thumbpath, 'rb') as imgfile:
return Response(imgfile.read(), mimetype="image/png") return Response(imgfile.read(), mimetype="image/png")
@app.route('/pdfthumb/<pdfname>/<int:maxgeometry>') @app.route('/pdfthumb/<pdfname>/<int:maxgeometry>')
def pdfthumbnail(pdfname, maxgeometry): def pdfthumbnail(pdfname, maxgeometry):
pdfpath = os.path.join(config.pdfdir, secure_filename(pdfname)) pdfpath = os.path.join(config.pdfdir, secure_filename(pdfname))
thumbpath = make_thumb(pdfpath, maxgeometry) pngpath = pdfpath.replace(".", "_") + ".png"
with open(thumbpath, 'r') as imgfile: img = convert_from_path(pdfpath)[0]
img.save(pngpath)
thumbpath = make_thumb(pngpath, maxgeometry)
with open(thumbpath, 'rb') as imgfile:
return Response(imgfile.read(), mimetype="image/png") return Response(imgfile.read(), mimetype="image/png")
...@@ -321,17 +280,21 @@ def tplthumbnail(tplname, maxgeometry): ...@@ -321,17 +280,21 @@ def tplthumbnail(tplname, maxgeometry):
}, pdfpath, overwrite=False }, pdfpath, overwrite=False
) )
except Exception as e: except Exception as e:
raise e
return str(e) return str(e)
else: else:
thumbpath = make_thumb(pdfpath, maxgeometry) pngpath = pdfpath.replace(".", "_") + ".png"
with open(thumbpath, 'r') as imgfile: img = convert_from_path(pdfpath)[0]
img.save(pngpath)
thumbpath = make_thumb(pngpath, maxgeometry)
with open(thumbpath, 'rb') as imgfile:
return Response(imgfile.read(), mimetype="image/png") return Response(imgfile.read(), mimetype="image/png")
@app.route('/pdfdownload/<pdfname>') @app.route('/pdfdownload/<pdfname>')
def pdfdownload(pdfname): def pdfdownload(pdfname):
pdfpath = os.path.join(config.pdfdir, secure_filename(pdfname)) pdfpath = os.path.join(config.pdfdir, secure_filename(pdfname))
with open(pdfpath, 'r') as pdffile: with open(pdfpath, 'rb') as pdffile:
return Response(pdffile.read(), mimetype="application/pdf") return Response(pdffile.read(), mimetype="application/pdf")
......
<!DOCTYPE html> <!DOCTYPE html>
<!-- <html xmlns="http://www.w3.org/1999/xhtml" > --> <html>
<html xmlns:py="http://genshi.edgewall.org/">
<head> <head>
<link rel='stylesheet' type='text/css' href="${ url_for('static', filename='main.css') }"/> <link rel='stylesheet' type='text/css' href="{{ url_for('static', filename='main.css') }}"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/> <meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Schildergenerator</title> <title>Schildergenerator</title>
</head> </head>
<body> <body>
<py:with vars="messages = get_flashed_messages(with_categories=True)"> {% with messages = get_flashed_messages(with_categories=True) %}
<ul class="flashes" py:if="messages"> {% if messages %}
<li class="${ category }" py:for="category,message in messages" tabindex="0">${ message }</li> <ul class="flashes">
</ul> {% for category, message in messages %}
</py:with> <li class="{{ category }}" tabindex="0">{{ message }}</li>
<a href="${ url_for('index') }">Liste der fertigen Schilder</a> {% endfor %}
</ul>
<form method="post" action="${ url_for('create') }" enctype="multipart/form-data"> {% endif %}
<div class="box"> {% endwith %}
<label for="form:template">Wähle eine TeX-Vorlage:</label> <a href="{{ url_for('index') }}">Liste der fertigen Schilder</a>
<ul py:attrs="{'class':'collapsed'} if defined('form') else {}">
<li py:for="textemplate in templates"> <form method="post" action="{{ url_for('create') }}" enctype="multipart/form-data">
<input type="radio" name="textemplate" id="tpl:${textemplate}" value="${textemplate}" py:attrs="{'checked':'checked', 'onfocus':'this.parentElement.parentElement.className=\'\';'} if defined('form') and textemplate == form.textemplate else {}"/> <div class="box">
<label for="tpl:${textemplate}"><img src="${ url_for('tplthumbnail', tplname=textemplate, maxgeometry=80) }" alt="${textemplate}" title="${textemplate}"/></label> <label for="form:template">Wähle eine TeX-Vorlage:</label>
</li> <ul class="{% if form %}collapsed{% endif %}">
<li class="onlywhencollapsed"> {% for textemplate in templates %}
<button onclick="this.parentElement.parentElement.className=''; return false;" >Auswahl anzeigen</button> <li>
</li> <input type="radio" name="textemplate" id="tpl:{{textemplate}}" value="{{textemplate}}" {% if form and textemplate == form.textemplate %} checked="checked" onfocus="this.parentElement.parentElement.className='';" {% endif %} />
</ul> <label for="tpl:{{textemplate}}"><img src="{{ url_for('tplthumbnail', tplname=textemplate, maxgeometry=80) }}" alt="{{textemplate}}" title="{{textemplate}}"/></label>
</div><br/> </li>
<div class="box"> <li class="onlywhencollapsed">
<label for="form:headline">Überschrift</label> <button onclick="this.parentElement.parentElement.className=''; return false;" >Auswahl anzeigen</button>
<textarea name="headline" id="form:headline" cols="35" rows="5"><py:if test="defined('form')">${form.headline}</py:if></textarea> </li>
</div> {% endfor %}
<div class="box"> </ul>
<label for="form:text">Text</label> </div><br/>
<select name="markup"> <div class="box">
<option value="latex" py:attrs="{'selected':'True'} if defined('form') and form.markup == 'latex' else {}">LaTeX</option> <label for="form:headline">Überschrift</label>
<option value="rst" py:attrs="{'selected':'True'} if not defined('form') or form.markup == 'rst' or form.markup == '' else {}">Wiki (reStructuredText)</option> <textarea name="headline" id="form:headline" cols="35" rows="5">{% if form %}{{form.headline}}{% endif %}</textarea>
</select> </div>
<textarea name="text" id="form:text" cols="35" rows="5"><py:if test="defined('form')">${form.text}</py:if></textarea> <div class="box">
</div><br/> <label for="form:text">Text</label>
<div class="box imageselect"> <select name="markup">
<label for="form:img">Wähle ein Bild (falls auf Vorlage anwendbar):</label> <option value="latex" {% if form and form.markup == "latex" %}selected{% endif %}>LaTeX</option>
<ul> <option value="rst" {% if form and (form.markup == "rst" or form.markup == "") %}selected{% endif %}>Wiki (reStructuredText)</option>
<li> </select>
<input type="radio" name="img" id="img--none" value="__none" py:attrs="{'checked':'checked'} if defined('form') and form.img == '__none' else {}"/> <textarea name="text" id="form:text" cols="35" rows="5">{% if form %}{{form.text}}{% endif %}</textarea>
<label for="img--none">Kein Bild</label> </div>
</li> <br/>
<li> <div class="box imageselect">
<input type="radio" name="img" id="img--upload" value="__upload"/> <label for="form:img">Wähle ein Bild (falls auf Vorlage anwendbar):</label>
<input type="file" name="imgupload"/> <ul>
<label for="img--upload">Bild hochladen (${', '.join(imageextensions)})</label> <li>
</li> <input type="radio" name="img" id="img--none" value="__none" {% if form and form.img == "__none" %}checked{% endif %}/>
</ul> <label for="img--none">Kein Bild</label>
<ul py:attrs="{'class':'collapsed'} if defined('form') else {}"> </li>
<li py:for="img in images"> <li>
<input type="radio" name="img" id="img:${img}" value="${img}" py:attrs="{'checked':'checked', 'onfocus':'this.parentElement.parentElement.className=\'\';'} if defined('form') and form.img == img else {}"/> <input type="radio" name="img" id="img--upload" value="__upload"/>
<label for="img:${img}"><img src="${ url_for('thumbnail', imgname=img, maxgeometry=100) }" alt="${img}" title="${img}"/></label> <input type="file" name="imgupload"/>
</li> <label for="img--upload">Bild hochladen ({{', '.join(imageextensions)}})</label>
<li class="onlywhencollapsed"> </li>
<button onclick="this.parentElement.parentElement.className=''; return false;" >Auswahl anzeigen</button> </ul>
</li> <ul {% if form %}class="collapsed"{% endif %}>
</ul> {% for img in images %}
</div> <li>
<input type="radio" name="img" id="img:{{img}}" value="{{img}}" {% if form and form.img == img %}checked="checked" onfocus="this.parentElement.parentElement.className='';"{% endif %} />
<label for="img:{{img}}">
<img src="{{ url_for('thumbnail', imgname=img, maxgeometry=100) }}" alt="{{img}}" title="{{img}}"/>
</label>
</li>
{% endfor %}
<li class="onlywhencollapsed">
<button onclick="this.parentElement.parentElement.className=''; return false;" >Auswahl anzeigen</button>
</li>
</ul>
</div>
<br/>
<div class="box">
{% if form and form.filename|length > 5 %}
<input type="hidden" name="filename" value="{{form.filename}}"/>
<input id="form:reusefilename" type="checkbox" name="reusefilename"/>
<label for="form:reusefilename">Überschreibe bisherige Version von {{form.filename}}.</label>
<br/> <br/>
<div class="box"> {% endif %}
<py:if test="defined('form') and len(form.filename) > 5"> <input type="submit" value="Schild erstellen"/>
<input type="hidden" name="filename" value="${form.filename}"/> </div>
<input id="form:reusefilename" type="checkbox" name="reusefilename"/> </form>
<label for="form:reusefilename">Überschreibe bisherige Version von ${form.filename}.</label>
<br/>
</py:if>
<input type="submit" value="Schild erstellen"/>
</div>
</form>
</body> </body>
</html> </html>
<!DOCTYPE html> <!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" <html>
xmlns:py="http://genshi.edgewall.org/">
<head> <head>
<link rel='stylesheet' type='text/css' href="${ url_for('static', filename='main.css') }"/> <link rel='stylesheet' type='text/css' href="{{ url_for('static', filename='main.css') }}"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/> <meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Schildergenerator</title> <title>Schildergenerator</title>
</head> </head>
<body> <body>
<py:with vars="messages = get_flashed_messages(with_categories=True)"> {% with messages = get_flashed_messages(with_categories=True) %}
<ul class="flashes" py:if="messages"> {% if messages %}
<li class="${ category }" py:for="category,message in messages" tabindex="0">${ message }</li> <ul class="flashes">
</ul> {% for category, message in messages %}
</py:with> <li class="{{ category }}" tabindex="0">{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
<a href="${ url_for('edit') }">Neues Schild</a> <a href="{{ url_for('edit') }}">Neues Schild</a>
<py:if test="defined('files')"> {% if files %}
<form method="POST" action="${ url_for('deletelist') }"> <form method="POST" action="{{ url_for('deletelist') }}">
<ul> <ul>
<li py:for="file in files"> {% for file in files %}
<input id="form:${file}" type="checkbox" name="filenames" value="${file}"/> <li>
<a href="${ url_for('schild', filename=file) }" title="${file}"> <input id="form:{{file}}" type="checkbox" name="filenames" value="{{file}}"/>
<img src="${ url_for('pdfthumbnail', pdfname=file+'.pdf', maxgeometry=150) }"/> <a href="{{ url_for('schild', filename=file) }}" title="{{file}}">
</a> <img src="{{ url_for('pdfthumbnail', pdfname=file+'.pdf', maxgeometry=150) }}"/>
</li> </a>
</ul> </li>
<input type="submit" value="Ausgewählte Schilder löschen"/> {% endfor %}
</form> </ul>
</py:if> <input type="submit" value="Ausgewählte Schilder löschen"/>
</form>
{% endif %}
</body> </body>
</html> </html>
<!DOCTYPE html> <!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" <html>
xmlns:py="http://genshi.edgewall.org/">
<head> <head>
<link rel='stylesheet' type='text/css' href="${ url_for('static', filename='main.css') }"/> <link rel='stylesheet' type='text/css' href="{{ url_for('static', filename='main.css') }}"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/> <meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Schildergenerator</title> <title>Schildergenerator</title>
</head> </head>
<body> <body>
<a href="${ url_for('index') }">Liste der Schilder</a> <a href="{{ url_for('index') }}">Liste der Schilder</a>
<a href="${ url_for('edit') }">Neues Schild</a> <a href="{{ url_for('edit') }}">Neues Schild</a>
<py:with vars="messages = get_flashed_messages(with_categories=True)"> {% with messages = get_flashed_messages(with_categories=True) %}
<ul class="flashes" py:if="messages"> {% if messages %}
<li class="${ category }" py:for="category,message in messages">${ message }</li> <ul class="flashes">
</ul> {% for category, message in messages %}
</py:with> <li class="{{ category }}">{{ message }}</li>
<img class="bigpreview" src="${ url_for('pdfthumbnail', pdfname=filename+'.pdf', maxgeometry=300) }"/> {% endfor %}
<form method="post" action="${ url_for('printout') }"> </ul>
<input type="hidden" name="filename" value="${filename + '.pdf'}" /> {% endif %}
{% endwith %}
<img class="bigpreview" src="{{ url_for('pdfthumbnail', pdfname=filename+'.pdf', maxgeometry=300) }}"/>
<form method="post" action="{{ url_for('printout') }}">
<input type="hidden" name="filename" value="{{filename + '.pdf'}}" />
<select name="copies"> <select name="copies">
<option py:for="x in range(1,11)" value="${x}" label="${x} Kopien">${x} Kopien</option>