180 lines
5.9 KiB
Python
180 lines
5.9 KiB
Python
import fpdf
|
|
from flask import Flask, render_template, request
|
|
import flask
|
|
import io
|
|
import zipfile
|
|
from werkzeug.datastructures import FileStorage
|
|
from PIL import Image
|
|
from pdf2image import convert_from_bytes
|
|
from PyPDF2 import PdfReader
|
|
|
|
VALID_KIND = ["all", "tc", "zc", "zip"]
|
|
ALLOWED_EXTENSIONS = ["png", "jpeg", "jpg", "pdf"]
|
|
|
|
# Function to get the dimensions of the source PDF page
|
|
|
|
|
|
def get_page_dimensions(pdfData, page_number=0):
|
|
reader = PdfReader(pdfData)
|
|
page = reader.pages[page_number]
|
|
width = float(page.mediabox.width)
|
|
height = float(page.mediabox.height)
|
|
width = width * (page.user_unit / 72) * 25.4
|
|
height = height * (page.user_unit / 72) * 25.4
|
|
return width, height
|
|
|
|
|
|
def generateTemplate(width: int, height: int, fondPerdu: int, zoneTranquille: int, marge: int, kind: str = "all", image: FileStorage = None, aFondPerdu: bool = False) -> fpdf.FPDF:
|
|
margeDuContenue = marge + fondPerdu
|
|
|
|
pdf = fpdf.FPDF("P", "mm", (width + margeDuContenue *
|
|
2, height + margeDuContenue * 2))
|
|
pdf.set_font("helvetica", "B", 16) # dummy font
|
|
pdf.set_margins(0, 0)
|
|
pdf.set_auto_page_break(False)
|
|
pdf.add_page()
|
|
|
|
xy, w, h = margeDuContenue, width, height
|
|
if (aFondPerdu == True):
|
|
xy = xy - fondPerdu
|
|
w = w + fondPerdu*2
|
|
h = h + fondPerdu*2
|
|
|
|
if (image and image.mimetype in ["image/jpeg", "image/png"]):
|
|
if 'inMemoryImage' not in flask.g:
|
|
flask.g.inMemoryImage = io.BytesIO()
|
|
image.save(flask.g.inMemoryImage)
|
|
|
|
if (image and image.mimetype in ["application/pdf", "application/x-pdf"]):
|
|
if 'inMemoryImage' not in flask.g:
|
|
pdfData = image.stream.read()
|
|
pdfW, pdfH = get_page_dimensions(io.BytesIO(pdfData))
|
|
scale = min(pdfW/w, pdfH/h)
|
|
imageFromPDF = convert_from_bytes(
|
|
pdfData, dpi=600, size=(w*scale, h*scale), single_file=True)
|
|
flask.g.inMemoryImage = imageFromPDF[0]
|
|
|
|
if ('inMemoryImage' in flask.g):
|
|
pdf.image(flask.g.inMemoryImage, xy, xy, w, h, keep_aspect_ratio=True)
|
|
|
|
if (kind in ["all", "zc"]):
|
|
pdf.set_draw_color(255, 0, 0) # red
|
|
pdf.rect(margeDuContenue, margeDuContenue, width, height)
|
|
|
|
pdf.set_draw_color(0, 0, 255) # blue
|
|
pdf.rect(
|
|
margeDuContenue - fondPerdu,
|
|
margeDuContenue - fondPerdu,
|
|
width + fondPerdu * 2,
|
|
height + fondPerdu * 2,
|
|
)
|
|
|
|
pdf.set_draw_color(0, 255, 0) # green
|
|
pdf.rect(
|
|
margeDuContenue + zoneTranquille,
|
|
margeDuContenue + zoneTranquille,
|
|
width - zoneTranquille * 2,
|
|
height - zoneTranquille * 2,
|
|
)
|
|
|
|
if (kind in ["all", "tc"]):
|
|
pdf.set_draw_color(0, 0, 0)
|
|
LINES = [
|
|
(margeDuContenue, 0, margeDuContenue, marge),
|
|
(margeDuContenue + width, 0, margeDuContenue + width, marge),
|
|
(
|
|
margeDuContenue,
|
|
height + margeDuContenue * 2,
|
|
margeDuContenue,
|
|
height + margeDuContenue * 2 - marge,
|
|
),
|
|
(
|
|
margeDuContenue + width,
|
|
height + margeDuContenue * 2,
|
|
margeDuContenue + width,
|
|
height + margeDuContenue * 2 - marge,
|
|
),
|
|
(0, margeDuContenue, marge, margeDuContenue),
|
|
(0, margeDuContenue + height, marge, margeDuContenue + height),
|
|
(
|
|
width + margeDuContenue * 2,
|
|
margeDuContenue,
|
|
width + margeDuContenue * 2 - marge,
|
|
margeDuContenue,
|
|
),
|
|
(
|
|
width + margeDuContenue * 2,
|
|
margeDuContenue + height,
|
|
width + margeDuContenue * 2 - marge,
|
|
margeDuContenue + height,
|
|
),
|
|
]
|
|
for line in LINES:
|
|
pdf.line(*line)
|
|
|
|
# pdf.set_author("template.ar2000.me")
|
|
pdf.set_creator("template.ar2000.me")
|
|
pdf.set_title(f'{width}x{height}_{kind}')
|
|
|
|
return pdf
|
|
|
|
|
|
def allowed_file(filename):
|
|
return '.' in filename and \
|
|
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
|
|
|
|
|
|
app = Flask(__name__)
|
|
|
|
|
|
@app.route("/")
|
|
def index():
|
|
return render_template("index.html")
|
|
|
|
|
|
@app.route("/generate", methods=['GET', 'POST'])
|
|
def generate():
|
|
try:
|
|
w = int(request.form.get("width", ""))
|
|
h = int(request.form.get("height", ""))
|
|
fp = int(request.form.get("fp", ""))
|
|
zt = int(request.form.get("zt", ""))
|
|
m = int(request.form.get("margin", ""))
|
|
k = request.form.get("kind", "all")
|
|
ffp = request.form.get("ffp", "off")
|
|
ffp = {"on": True, "off": False}[ffp]
|
|
if k not in VALID_KIND:
|
|
raise ValueError("kind is not valid")
|
|
image = None
|
|
if 'file' in request.files and allowed_file(request.files['file'].filename):
|
|
image = request.files['file']
|
|
|
|
except (KeyError, ValueError) as e:
|
|
flask.abort(400)
|
|
app.logger.info(
|
|
"w %d ; h %d ; fp %d ; zt %d ; m %d ; ffp %s", w, h, fp, zt, m, ffp)
|
|
if k != "zip":
|
|
pdf = generateTemplate(w, h, fp, zt, m, k, image, ffp).output()
|
|
return flask.send_file(
|
|
io.BytesIO(pdf),
|
|
mimetype="application/pdf",
|
|
download_name=f'{w}x{h}_{k}.pdf',
|
|
)
|
|
else:
|
|
zipBuffer = io.BytesIO()
|
|
zipHandle = zipfile.ZipFile(
|
|
zipBuffer, "a", zipfile.ZIP_DEFLATED, False, 9)
|
|
for kk in [x for x in VALID_KIND if x != "zip"]:
|
|
pdf = generateTemplate(w, h, fp, zt, m, kk, image, ffp).output()
|
|
zipHandle.writestr(f'{w}x{h}_{kk}.pdf', pdf)
|
|
zipHandle.close()
|
|
return flask.send_file(
|
|
io.BytesIO(zipBuffer.getvalue()),
|
|
mimetype="application/zip",
|
|
download_name=f'{w}x{h}.zip',
|
|
)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
app.run(host='0.0.0.0', port=8000)
|