Fix planche generation issues
This commit is contained in:
parent
6a05e46946
commit
d706ae1645
@ -1,6 +1,6 @@
|
||||
FROM alpine
|
||||
FROM alpine:3.18
|
||||
|
||||
RUN apk --no-cache add python3 inkscape bash imagemagick ghostscript ttf-opensans
|
||||
RUN apk --no-cache add python3 inkscape bash imagemagick ghostscript font-droid
|
||||
RUN apk --no-cache add py3-pip && pip3 install --break-system-packages django tzdata gunicorn
|
||||
|
||||
ADD backend /zetikettes
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -23,7 +23,7 @@
|
||||
"model": "tikette.tisub",
|
||||
"pk": 4,
|
||||
"fields": {
|
||||
"name": "qty",
|
||||
"name": "q",
|
||||
"descritpion": "Poids net (g)",
|
||||
"default": "370",
|
||||
"type": "ST"
|
||||
@ -43,7 +43,7 @@
|
||||
"model": "tikette.tisub",
|
||||
"pk": 6,
|
||||
"fields": {
|
||||
"name": "fruit",
|
||||
"name": "f",
|
||||
"descritpion": "Quantité de fruits pour 100g (g)",
|
||||
"default": "60",
|
||||
"type": "ST"
|
||||
|
@ -50,7 +50,7 @@ class Tikette(models.Model):
|
||||
description = models.TextField()
|
||||
color = models.CharField(max_length=6)
|
||||
ab = models.CharField(max_length=7, choices=AbVisibility)
|
||||
# designation_fontsize is hardcoded to 42.6667
|
||||
# designation_fontsize is hardcoded to 42.6667 in planche/generate.py
|
||||
|
||||
def __str__(self):
|
||||
return self.title
|
||||
|
@ -1,24 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
viewBox="0 0 210 297"
|
||||
height="297mm"
|
||||
width="210mm">
|
||||
<g transform="translate(3, 4.5)">
|
||||
<g transform="translate(-42,144) rotate(-90,144,0)">
|
||||
<g transform="translate( 0,0)">$right0</g>
|
||||
<g transform="translate( 48,0)">$right1</g>
|
||||
<g transform="translate( 96,0)">$right2</g>
|
||||
<g transform="translate(144,0)">$right3</g>
|
||||
<g transform="translate(192,0)">$right4</g>
|
||||
<g transform="translate(240,0)">$right5</g>
|
||||
</g>
|
||||
<g transform="translate(-42,144) rotate(90,144,0)">
|
||||
<g transform="translate( 0,0)">$left0</g>
|
||||
<g transform="translate( 48,0)">$left1</g>
|
||||
<g transform="translate( 96,0)">$left2</g>
|
||||
<g transform="translate(144,0)">$left3</g>
|
||||
<g transform="translate(192,0)">$left4</g>
|
||||
<g transform="translate(240,0)">$left5</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 896 B |
0
backend/zetikettes/tikette/planche/__init__.py
Normal file
0
backend/zetikettes/tikette/planche/__init__.py
Normal file
@ -7,6 +7,8 @@ from .makeplanche import makeplanche
|
||||
|
||||
OUT_DIR = tempfile.gettempdir()
|
||||
DEFAULT_DPI = 300
|
||||
DESIGNATION_FONTSIZE = 42.6667
|
||||
|
||||
|
||||
def inkscapize(svg_in, pdf_out):
|
||||
png_out = tempfile.mktemp(suffix='.png')
|
||||
@ -22,31 +24,31 @@ def inkscapize(svg_in, pdf_out):
|
||||
os.unlink(png_out)
|
||||
|
||||
|
||||
def generate(request, out_dir):
|
||||
def generate(template, subs, out_dir, landscape=False):
|
||||
""" Generate a sticker sheet.
|
||||
|
||||
request: dict-like with the following fields:
|
||||
sticker: mandatory. filename for the sticker
|
||||
subs: mandatory. dict-like with key-value template subtitution fields
|
||||
landscape: optional. defaults to False
|
||||
|
||||
template: file name for the sticker template
|
||||
subs: dict-like with key-value template subtitution fields
|
||||
out_dir: you get it
|
||||
landscape: optional. defaults to False
|
||||
"""
|
||||
|
||||
# default designation font size
|
||||
subs['designation_fontsize'] = subs.get('designation_fontsize',
|
||||
DESIGNATION_FONTSIZE)
|
||||
|
||||
# fill in sticker details
|
||||
sticker_out = tempfile.mktemp(suffix='.svg')
|
||||
|
||||
try:
|
||||
with open(sticker_out, 'w') as stickout:
|
||||
landscape = request.get('landscape', False)
|
||||
makesticker(os.path.join(out_dir, request['sticker']), stickout,
|
||||
request['subs'], landscape=landscape)
|
||||
makesticker(os.path.join(out_dir, template), stickout, subs)
|
||||
|
||||
# make sticker sheet
|
||||
planche_out = tempfile.mktemp(suffix='.svg')
|
||||
with open(sticker_out, 'r') as stickin:
|
||||
with open(planche_out, 'w') as planchout:
|
||||
makeplanche(stickin, planchout)
|
||||
makeplanche(stickin, planchout, landscape=landscape)
|
||||
|
||||
# process to printable pdf
|
||||
pdf_out = tempfile.mktemp(dir=out_dir, suffix='.pdf')
|
@ -20,6 +20,9 @@ def parse_args():
|
||||
default=sys.stdout,
|
||||
type=argparse.FileType('w'),
|
||||
help='output path (default: stdout)')
|
||||
parser.add_argument('--landscape',
|
||||
action='store_true',
|
||||
help='input sticker is in landscape orientation')
|
||||
parser.add_argument('sticker',
|
||||
type=argparse.FileType('r'),
|
||||
default=sys.stdin,
|
||||
@ -29,7 +32,7 @@ def parse_args():
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def makeplanche(sticker, out, template=DEFAULT_SHEET_TEMPLATE):
|
||||
def makeplanche(sticker, out, template=DEFAULT_SHEET_TEMPLATE ,landscape=False):
|
||||
with open(template) as tpl:
|
||||
tpl_data = tpl.read()
|
||||
|
||||
@ -38,19 +41,11 @@ def makeplanche(sticker, out, template=DEFAULT_SHEET_TEMPLATE):
|
||||
lines = lines[1:]
|
||||
sticker_data = ''.join(lines)
|
||||
|
||||
rotate = "translate(102, 0) rotate(90)" if not landscape else ""
|
||||
|
||||
subs = {
|
||||
'left0': sticker_data,
|
||||
'left1': sticker_data,
|
||||
'left2': sticker_data,
|
||||
'left3': sticker_data,
|
||||
'left4': sticker_data,
|
||||
'left5': sticker_data,
|
||||
'right0': sticker_data,
|
||||
'right1': sticker_data,
|
||||
'right2': sticker_data,
|
||||
'right3': sticker_data,
|
||||
'right4': sticker_data,
|
||||
'right5': sticker_data,
|
||||
'sticker': sticker_data,
|
||||
'rotate': rotate,
|
||||
}
|
||||
|
||||
out.write(Template(tpl_data).substitute(subs))
|
@ -22,25 +22,18 @@ def parse_args():
|
||||
parser.add_argument('--teneur', '-t', required=False, help='Teneur en sucre')
|
||||
parser.add_argument('--fruit', '-f', required=False, help='Quantité de fruits')
|
||||
parser.add_argument('--size', '-s', required=False, help='Masse de produit')
|
||||
parser.add_argument('--landscape',
|
||||
action='store_true',
|
||||
help='input sticker is in landscape orientation')
|
||||
parser.add_argument('sticker', help='path to the sticker template')
|
||||
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def makesticker(sticker: str, out: typing.IO, subs: dict, landscape=False):
|
||||
def makesticker(sticker: str, out: typing.IO, subs: dict):
|
||||
with open(sticker) as fin:
|
||||
lines = fin.readlines()
|
||||
if lines[0].startswith('<?xml'):
|
||||
lines = lines[1:]
|
||||
sticker_data = ''.join(lines)
|
||||
|
||||
if landscape:
|
||||
# Rotate the sticker 90 degrees
|
||||
sticker_data = "<g transform=\"rotate(-90,0,0) translate(-102,0)\">{}</g>".format(sticker_data)
|
||||
|
||||
out.write(Template(sticker_data).substitute(subs))
|
||||
|
||||
|
||||
@ -50,8 +43,8 @@ if __name__ == "__main__":
|
||||
'dluo': args.pop('dluo'),
|
||||
'lot': args.pop('lot'),
|
||||
'teneur': args.pop('teneur'),
|
||||
'fruit': args.pop('fruit'),
|
||||
'qty': args.pop('quantite'),
|
||||
'f': args.pop('fruit'),
|
||||
'q': args.pop('quantite'),
|
||||
'size': args.pop('size'),
|
||||
}
|
||||
args['subs'] = subs
|
24
backend/zetikettes/tikette/planche/planche.svg.in
Normal file
24
backend/zetikettes/tikette/planche/planche.svg.in
Normal file
@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
viewBox="0 0 210 297"
|
||||
height="297mm"
|
||||
width="210mm">
|
||||
<g transform="translate(3, 4.5)">
|
||||
|
||||
<g transform="translate(0, 0) ${rotate} scale(0.26458)">${sticker}</g>
|
||||
<g transform="translate(0, 48) ${rotate} scale(0.26458)">${sticker}</g>
|
||||
<g transform="translate(0, 96) ${rotate} scale(0.26458)">${sticker}</g>
|
||||
<g transform="translate(0, 144) ${rotate} scale(0.26458)">${sticker}</g>
|
||||
<g transform="translate(0, 192) ${rotate} scale(0.26458)">${sticker}</g>
|
||||
<g transform="translate(0, 240) ${rotate} scale(0.26458)">${sticker}</g>
|
||||
|
||||
<g transform="rotate(180, 102, 144)">
|
||||
<g transform="translate(0, 0) ${rotate} scale(0.26458)">${sticker}</g>
|
||||
<g transform="translate(0, 48) ${rotate} scale(0.26458)">${sticker}</g>
|
||||
<g transform="translate(0, 96) ${rotate} scale(0.26458)">${sticker}</g>
|
||||
<g transform="translate(0, 144) ${rotate} scale(0.26458)">${sticker}</g>
|
||||
<g transform="translate(0, 192) ${rotate} scale(0.26458)">${sticker}</g>
|
||||
<g transform="translate(0, 240) ${rotate} scale(0.26458)">${sticker}</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
@ -5,18 +5,34 @@ from django.http import JsonResponse
|
||||
from django.shortcuts import render
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
|
||||
from . import generate as stickersheet
|
||||
from .planche import generate as stickersheet
|
||||
from .models import Tikette, Tikategory
|
||||
|
||||
CORS={'access-control-allow-origin': '*'}
|
||||
|
||||
|
||||
def quirk_bold_allergens(ingredients):
|
||||
out = []
|
||||
for ing in (x.strip() for x in ingredients.split(',')):
|
||||
if ing.startswith('*'):
|
||||
out.append(f'<tspan style="font-weight:bold">{ing[1:]}</tspan>')
|
||||
else:
|
||||
out.append(ing)
|
||||
return ", ".join(out)
|
||||
|
||||
|
||||
def get_list(request):
|
||||
tikettes = [{
|
||||
'id': x.id,
|
||||
'title': x.title,
|
||||
'category': x.category.name,
|
||||
'prototempalte': x.category.prototempalte.name,
|
||||
'landscape': x.category.landscape,
|
||||
'designation': x.designation,
|
||||
'ingredients': quirk_bold_allergens(x.ingredients),
|
||||
'description': x.description,
|
||||
'ab': x.ab,
|
||||
'color': x.color,
|
||||
'subs': {x.name: x.default for x in x.category.subs.all()},
|
||||
} for x in Tikette.objects.all()]
|
||||
return JsonResponse({'status': 'ok', 'tikettes': tikettes}, headers=CORS)
|
||||
@ -36,7 +52,14 @@ def generate(request):
|
||||
return JsonResponse({'status': 'notok', 'message': 'this isn\'t the way'})
|
||||
|
||||
payload = json.loads(request.body)
|
||||
pdfpath = stickersheet.generate(payload, out_dir=settings.TIKETTE_OUT_DIR)
|
||||
|
||||
subs = dict(payload['subs'])
|
||||
for key in ('designation', 'ingredients', 'description', 'color', 'AB'):
|
||||
subs[key] = payload[key]
|
||||
|
||||
pdfpath = stickersheet.generate(template=payload['template'], subs=subs,
|
||||
out_dir=settings.TIKETTE_OUT_DIR,
|
||||
landscape=payload['landscape'])
|
||||
|
||||
return JsonResponse({'status': 'ok', 'file': pdfpath}, headers=CORS)
|
||||
|
||||
|
@ -1,10 +1,9 @@
|
||||
const params = {
|
||||
'dluo': 'DLUO',
|
||||
'lot': 'Nº de lot',
|
||||
'qty': 'Poids net (g)',
|
||||
'vol': 'Volume net (cL)',
|
||||
'q': 'Poids net (g)',
|
||||
'teneur': 'Teneur en fruits (%)',
|
||||
'fruit': 'Quantité de fruits pour 100g (g)',
|
||||
'f': 'Quantité de fruits pour 100g (g)',
|
||||
}
|
||||
|
||||
var tikats;
|
||||
@ -26,7 +25,12 @@ function addProduct(tikette) {
|
||||
.toArray()
|
||||
.reduce((obj, el) => ({...obj, [el.name]: el.value}), {});
|
||||
const req = {
|
||||
sticker: zett.sticker,
|
||||
template: zett.prototempalte,
|
||||
designation: zett.designation,
|
||||
description: zett.description,
|
||||
ingredients: zett.ingredients,
|
||||
color: zett.color,
|
||||
AB: zett.ab, // mind the capitalization here
|
||||
subs,
|
||||
landscape: zett.landscape,
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user