mirror of
https://github.com/hackathi/brother_ql_web.git
synced 2026-02-03 23:33:22 +00:00
Grocy Label printing API
This commit is contained in:
parent
9e20b6dc3f
commit
ac488f927c
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"python.pythonPath": "/Users/katharina/.local/share/virtualenvs/brother_ql_web-SwH3dpgY/bin/python"
|
||||
}
|
||||
15
Pipfile
Normal file
15
Pipfile
Normal file
@ -0,0 +1,15 @@
|
||||
[[source]]
|
||||
url = "https://pypi.org/simple"
|
||||
verify_ssl = true
|
||||
name = "pypi"
|
||||
|
||||
[packages]
|
||||
brother-ql = "*"
|
||||
bottle = "*"
|
||||
Jinja2 = "*"
|
||||
pylibdmtx = "*"
|
||||
|
||||
[dev-packages]
|
||||
|
||||
[requires]
|
||||
python_version = "3.9"
|
||||
170
Pipfile.lock
generated
Normal file
170
Pipfile.lock
generated
Normal file
@ -0,0 +1,170 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "da7a1334691b7adf61fae33efd94321812b4a0180e56621a5ba349a940004db0"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
"python_version": "3.9"
|
||||
},
|
||||
"sources": [
|
||||
{
|
||||
"name": "pypi",
|
||||
"url": "https://pypi.org/simple",
|
||||
"verify_ssl": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"default": {
|
||||
"attrs": {
|
||||
"hashes": [
|
||||
"sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1",
|
||||
"sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==21.2.0"
|
||||
},
|
||||
"bottle": {
|
||||
"hashes": [
|
||||
"sha256:a9d73ffcbc6a1345ca2d7949638db46349f5b2b77dac65d6494d45c23628da2c",
|
||||
"sha256:f6b8a34fe9aa406f9813c02990db72ca69ce6a158b5b156d2c41f345016a723d"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.12.19"
|
||||
},
|
||||
"brother-ql": {
|
||||
"hashes": [
|
||||
"sha256:1a7a3faa56924c4e7670da82016486fc310af339acb2ffb98bd863a2667ab2c2",
|
||||
"sha256:1f5c57a039f012c9c204397f470001f76ebb7483421ebde985d0cb3c614e8660"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.9.4"
|
||||
},
|
||||
"click": {
|
||||
"hashes": [
|
||||
"sha256:8c04c11192119b1ef78ea049e0a6f0463e4c48ef00a30160c704337586f3ad7a",
|
||||
"sha256:fba402a4a47334742d782209a7c79bc448911afe1149d07bdabdf480b3e2f4b6"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==8.0.1"
|
||||
},
|
||||
"future": {
|
||||
"hashes": [
|
||||
"sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"
|
||||
],
|
||||
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==0.18.2"
|
||||
},
|
||||
"jinja2": {
|
||||
"hashes": [
|
||||
"sha256:1f06f2da51e7b56b8f238affdd6b4e2c61e39598a378cc49345bc1bd42a978a4",
|
||||
"sha256:703f484b47a6af502e743c9122595cc812b0271f661722403114f71a79d0f5a4"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.0.1"
|
||||
},
|
||||
"markupsafe": {
|
||||
"hashes": [
|
||||
"sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298",
|
||||
"sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64",
|
||||
"sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b",
|
||||
"sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567",
|
||||
"sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff",
|
||||
"sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74",
|
||||
"sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35",
|
||||
"sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26",
|
||||
"sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7",
|
||||
"sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75",
|
||||
"sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f",
|
||||
"sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135",
|
||||
"sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8",
|
||||
"sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a",
|
||||
"sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914",
|
||||
"sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18",
|
||||
"sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8",
|
||||
"sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2",
|
||||
"sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d",
|
||||
"sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b",
|
||||
"sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f",
|
||||
"sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb",
|
||||
"sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833",
|
||||
"sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415",
|
||||
"sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902",
|
||||
"sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9",
|
||||
"sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d",
|
||||
"sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066",
|
||||
"sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f",
|
||||
"sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5",
|
||||
"sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94",
|
||||
"sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509",
|
||||
"sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51",
|
||||
"sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==2.0.1"
|
||||
},
|
||||
"packbits": {
|
||||
"hashes": [
|
||||
"sha256:bc6b370bb34e04ac8cfa835e06c0484380affc6d593adb8009dd6c0f7bfff034"
|
||||
],
|
||||
"version": "==0.6"
|
||||
},
|
||||
"pillow": {
|
||||
"hashes": [
|
||||
"sha256:01425106e4e8cee195a411f729cff2a7d61813b0b11737c12bd5991f5f14bcd5",
|
||||
"sha256:031a6c88c77d08aab84fecc05c3cde8414cd6f8406f4d2b16fed1e97634cc8a4",
|
||||
"sha256:083781abd261bdabf090ad07bb69f8f5599943ddb539d64497ed021b2a67e5a9",
|
||||
"sha256:0d19d70ee7c2ba97631bae1e7d4725cdb2ecf238178096e8c82ee481e189168a",
|
||||
"sha256:0e04d61f0064b545b989126197930807c86bcbd4534d39168f4aa5fda39bb8f9",
|
||||
"sha256:12e5e7471f9b637762453da74e390e56cc43e486a88289995c1f4c1dc0bfe727",
|
||||
"sha256:22fd0f42ad15dfdde6c581347eaa4adb9a6fc4b865f90b23378aa7914895e120",
|
||||
"sha256:238c197fc275b475e87c1453b05b467d2d02c2915fdfdd4af126145ff2e4610c",
|
||||
"sha256:3b570f84a6161cf8865c4e08adf629441f56e32f180f7aa4ccbd2e0a5a02cba2",
|
||||
"sha256:463822e2f0d81459e113372a168f2ff59723e78528f91f0bd25680ac185cf797",
|
||||
"sha256:4d98abdd6b1e3bf1a1cbb14c3895226816e666749ac040c4e2554231068c639b",
|
||||
"sha256:5afe6b237a0b81bd54b53f835a153770802f164c5570bab5e005aad693dab87f",
|
||||
"sha256:5b70110acb39f3aff6b74cf09bb4169b167e2660dabc304c1e25b6555fa781ef",
|
||||
"sha256:5cbf3e3b1014dddc45496e8cf38b9f099c95a326275885199f427825c6522232",
|
||||
"sha256:624b977355cde8b065f6d51b98497d6cd5fbdd4f36405f7a8790e3376125e2bb",
|
||||
"sha256:63728564c1410d99e6d1ae8e3b810fe012bc440952168af0a2877e8ff5ab96b9",
|
||||
"sha256:66cc56579fd91f517290ab02c51e3a80f581aba45fd924fcdee01fa06e635812",
|
||||
"sha256:6c32cc3145928c4305d142ebec682419a6c0a8ce9e33db900027ddca1ec39178",
|
||||
"sha256:8b56553c0345ad6dcb2e9b433ae47d67f95fc23fe28a0bde15a120f25257e291",
|
||||
"sha256:8bb1e155a74e1bfbacd84555ea62fa21c58e0b4e7e6b20e4447b8d07990ac78b",
|
||||
"sha256:95d5ef984eff897850f3a83883363da64aae1000e79cb3c321915468e8c6add5",
|
||||
"sha256:a013cbe25d20c2e0c4e85a9daf438f85121a4d0344ddc76e33fd7e3965d9af4b",
|
||||
"sha256:a787ab10d7bb5494e5f76536ac460741788f1fbce851068d73a87ca7c35fc3e1",
|
||||
"sha256:a7d5e9fad90eff8f6f6106d3b98b553a88b6f976e51fce287192a5d2d5363713",
|
||||
"sha256:aac00e4bc94d1b7813fe882c28990c1bc2f9d0e1aa765a5f2b516e8a6a16a9e4",
|
||||
"sha256:b91c36492a4bbb1ee855b7d16fe51379e5f96b85692dc8210831fbb24c43e484",
|
||||
"sha256:c03c07ed32c5324939b19e36ae5f75c660c81461e312a41aea30acdd46f93a7c",
|
||||
"sha256:c5236606e8570542ed424849f7852a0ff0bce2c4c8d0ba05cc202a5a9c97dee9",
|
||||
"sha256:c6b39294464b03457f9064e98c124e09008b35a62e3189d3513e5148611c9388",
|
||||
"sha256:cb7a09e173903541fa888ba010c345893cd9fc1b5891aaf060f6ca77b6a3722d",
|
||||
"sha256:d68cb92c408261f806b15923834203f024110a2e2872ecb0bd2a110f89d3c602",
|
||||
"sha256:dc38f57d8f20f06dd7c3161c59ca2c86893632623f33a42d592f097b00f720a9",
|
||||
"sha256:e98eca29a05913e82177b3ba3d198b1728e164869c613d76d0de4bde6768a50e",
|
||||
"sha256:f217c3954ce5fd88303fc0c317af55d5e0204106d86dea17eb8205700d47dec2"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==8.2.0"
|
||||
},
|
||||
"pylibdmtx": {
|
||||
"hashes": [
|
||||
"sha256:267d6e75b5a62c177697f35e154249d24baa33cb8a331079fbeeffd7858cb848",
|
||||
"sha256:6c75c4c9463e3872b3ab10e0b2fd8d906a9cede6f865e924a4f2d9ec766f0a2d",
|
||||
"sha256:709f80fafa1f79bf02c9393a8931fd1e7c1e04f8bf3ca9112fa2229751682bed"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.1.9"
|
||||
},
|
||||
"pyusb": {
|
||||
"hashes": [
|
||||
"sha256:7d449ad916ce58aff60b89aae0b65ac130f289c24d6a5b7b317742eccffafc38",
|
||||
"sha256:f18eb813d3a1439918071234589162c2f209a19adbeffeb1377ce078a4aebc70"
|
||||
],
|
||||
"version": "==1.1.1"
|
||||
}
|
||||
},
|
||||
"develop": {}
|
||||
}
|
||||
@ -70,6 +70,9 @@ def get_label_context(request):
|
||||
'margin_bottom': float(d.get('margin_bottom', 45))/100.,
|
||||
'margin_left': float(d.get('margin_left', 35))/100.,
|
||||
'margin_right': float(d.get('margin_right', 35))/100.,
|
||||
'grocycode': d.get('grocycode', None),
|
||||
'product': d.get('product', None),
|
||||
'duedate': d.get('duedate', None)
|
||||
}
|
||||
context['margin_top'] = int(context['font_size']*context['margin_top'])
|
||||
context['margin_bottom'] = int(context['font_size']*context['margin_bottom'])
|
||||
@ -145,6 +148,63 @@ def create_label_im(text, **kwargs):
|
||||
draw.multiline_text(offset, text, kwargs['fill_color'], font=im_font, align=kwargs['align'])
|
||||
return im
|
||||
|
||||
def create_label_grocy(text, **kwargs):
|
||||
product = kwargs['product']
|
||||
duedate = kwargs['duedate']
|
||||
grocycode = kwargs['grocycode']
|
||||
|
||||
|
||||
# prepare grocycode datamatrix
|
||||
from pylibdmtx.pylibdmtx import encode
|
||||
encoded = encode(grocycode.encode('utf8'), size="SquareAuto") # adjusted for 300x300 dpi - results in DM code roughly 5x5mm
|
||||
datamatrix = Image.frombytes('RGB', (encoded.width, encoded.height), encoded.pixels)
|
||||
datamatrix.save('/tmp/dmtx.png')
|
||||
|
||||
product_font = ImageFont.truetype(kwargs['font_path'], 100)
|
||||
duedate_font = ImageFont.truetype(kwargs['font_path'], 60)
|
||||
width = kwargs['width']
|
||||
height = 200
|
||||
if kwargs['orientation'] == 'rotated':
|
||||
tw = width
|
||||
width = height
|
||||
height = tw
|
||||
|
||||
im = Image.new('RGB', (width, height), 'white')
|
||||
draw = ImageDraw.Draw(im)
|
||||
if kwargs['orientation'] == 'standard':
|
||||
vertical_offset = kwargs['margin_top']
|
||||
horizontal_offset = kwargs['margin_left']
|
||||
elif kwargs['orientation'] == 'rotated':
|
||||
vertical_offset = kwargs['margin_top']
|
||||
horizontal_offset = kwargs['margin_left']
|
||||
datamatrix.transpose(Image.ROTATE_270)
|
||||
|
||||
im.paste(datamatrix, (horizontal_offset, vertical_offset, horizontal_offset + encoded.width, vertical_offset + encoded.height))
|
||||
|
||||
if kwargs['orientation'] == 'standard':
|
||||
vertical_offset += -10
|
||||
horizontal_offset = encoded.width + 40
|
||||
elif kwargs['orientation'] == 'rotated':
|
||||
vertical_offset += encoded.width + 40
|
||||
horizontal_offset += -10
|
||||
|
||||
textoffset = horizontal_offset, vertical_offset
|
||||
|
||||
draw.text(textoffset, product, kwargs['fill_color'], font=product_font)
|
||||
|
||||
if duedate is not None:
|
||||
if kwargs['orientation'] == 'standard':
|
||||
vertical_offset += 110
|
||||
horizontal_offset = kwargs['margin_left']
|
||||
elif kwargs['orientation'] == 'rotated':
|
||||
vertical_offset = kwargs['margin_left']
|
||||
horizontal_offset += 110
|
||||
textoffset = horizontal_offset, vertical_offset
|
||||
|
||||
draw.text(textoffset, duedate, kwargs['fill_color'], font=duedate_font)
|
||||
|
||||
return im
|
||||
|
||||
@get('/api/preview/text')
|
||||
@post('/api/preview/text')
|
||||
def get_preview_image():
|
||||
@ -165,6 +225,56 @@ def image_to_png_bytes(im):
|
||||
image_buffer.seek(0)
|
||||
return image_buffer.read()
|
||||
|
||||
@post('/api/print/grocy')
|
||||
@get('/api/print/grocy')
|
||||
def print_grocy():
|
||||
"""
|
||||
API endpoint to consume the grocy label webhook.
|
||||
|
||||
returns; JSON
|
||||
"""
|
||||
|
||||
return_dict = {'success' : False }
|
||||
|
||||
try:
|
||||
context = get_label_context(request)
|
||||
except LookupError as e:
|
||||
return_dict['error'] = e.msg
|
||||
return return_dict
|
||||
|
||||
if context['product'] is None:
|
||||
return_dict['error'] = 'Please provide the product for the label'
|
||||
return return_dict
|
||||
|
||||
im = create_label_grocy(**context)
|
||||
if DEBUG: im.save('sample-out.png')
|
||||
|
||||
if context['kind'] == ENDLESS_LABEL:
|
||||
rotate = 0 if context['orientation'] == 'standard' else 90
|
||||
elif context['kind'] in (ROUND_DIE_CUT_LABEL, DIE_CUT_LABEL):
|
||||
rotate = 'auto'
|
||||
|
||||
qlr = BrotherQLRaster(CONFIG['PRINTER']['MODEL'])
|
||||
red = False
|
||||
if 'red' in context['label_size']:
|
||||
red = True
|
||||
create_label(qlr, im, context['label_size'], red=red, threshold=context['threshold'], cut=True, rotate=rotate)
|
||||
|
||||
if not DEBUG:
|
||||
try:
|
||||
be = BACKEND_CLASS(CONFIG['PRINTER']['PRINTER'])
|
||||
be.write(qlr.data)
|
||||
be.dispose()
|
||||
del be
|
||||
except Exception as e:
|
||||
return_dict['message'] = str(e)
|
||||
logger.warning('Exception happened: %s', e)
|
||||
return return_dict
|
||||
|
||||
return_dict['success'] = True
|
||||
if DEBUG: return_dict['data'] = str(qlr.data)
|
||||
return return_dict
|
||||
|
||||
@post('/api/print/text')
|
||||
@get('/api/print/text')
|
||||
def print_text():
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user