From 8b487418166c03eb00991c989f4bf201447fd551 Mon Sep 17 00:00:00 2001 From: Dirk Jahnke Date: Fri, 1 Apr 2022 10:19:41 +0200 Subject: [PATCH] Label creation and print --- .../container/container_print_label.html | 24 ++++- container/views.py | 87 ++++++++++++++++--- labelprinter/labels.py | 57 +++++++++--- 3 files changed, 138 insertions(+), 30 deletions(-) diff --git a/container/templates/container/container_print_label.html b/container/templates/container/container_print_label.html index d3c29eb..5b7fd7c 100644 --- a/container/templates/container/container_print_label.html +++ b/container/templates/container/container_print_label.html @@ -4,17 +4,33 @@ {% block title %}Container: {{ container.named_id }}{% endblock %} {% block content %} -===== Print Label Content ===== - +

Print Container Label

- Label created for container {{ container.named_id }} of type {{ container.container_type.named_id }} + Label created for container {{ container.named_id }} of type {{ container.container_type.named_id }}:
- +
+
+ {% csrf_token %} + + +
+
+
+ +
diff --git a/container/views.py b/container/views.py index 28fdc16..300933c 100644 --- a/container/views.py +++ b/container/views.py @@ -1,6 +1,8 @@ from django.views import generic from .models import Container, ContainerType -from labelprinter.labels import container_label +import logging, json + +logger = logging.getLogger(__name__) class ContainerListView(generic.ListView): @@ -62,22 +64,81 @@ class ContainerPrintLabelView(generic.DetailView): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - from labelprinter.labels import container_label + num_copies = int(self.request.GET['num_copies']) if 'num_copies' in self.request.GET else 0 + context['num_copies'] = num_copies + context['logs'] = ['creating label for container ' + self.object.named_id] + from labelprinter.labels import container_label, pil_to_html_imgdata container_description = self.object.container_type.named_id if len(self.object.container_type.description) > 0: container_description += ': ' + self.object.container_type.description if len(self.object.description) > 0: - container_description += ' / ' + self.object.description - context['barcode_img'] = container_label(self.object.named_id, description=container_description, writer_options={'background': 'white', - 'font_size': 10, - 'foreground': 'black', - 'module_height': 10.0, - 'module_width': 0.2, - 'quiet_zone': 2.5, - 'text': 'This is the text', - 'text_distance': 3.0, - 'write_text': True - }) + container_description_line2 = self.object.description + label_image = container_label( + self.object.named_id, + fmt='image', + description=container_description, + description_line2=container_description_line2, + writer_options={'font_size': 14, + 'module_height': 10.0, + 'quiet_zone': 4.5, + 'text': 'This is the text', + 'text_distance': 1.0 + }) + context['barcode_img'] = pil_to_html_imgdata(label_image, fmt='PNG') + context['logs'].append('Image created') + if num_copies > 0: + #from brother_ql.devicedependent import models, label_type_specs, label_sizes + #from brother_ql.devicedependent import ENDLESS_LABEL, DIE_CUT_LABEL, ROUND_DIE_CUT_LABEL + from brother_ql import BrotherQLRaster, create_label + from brother_ql.backends import backend_factory, guess_backend + + try: + with open('config.json', encoding='utf-8') as fh: + config = json.load(fh) + except FileNotFoundError as e: + with open('config.example.json', encoding='utf-8') as fh: + config = json.load(fh) + + # LABEL_SIZES = [(name, label_type_specs[name]['name']) for name in label_sizes] + + ''' + 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' + red = False + if 'red' in context['label_size']: + red = True + ''' + + qlr = BrotherQLRaster(config['PRINTER']['MODEL']) + context['logs'].append('Connected to printer') + create_label(qlr, image=label_image, label_size='62', red=False, threshold=1, + cut=True, rotate='auto') + context['logs'].append('Created raster information') + + try: + selected_backend = guess_backend(config['PRINTER']['PRINTER']) + except ValueError: + context['messages'].append( + "Could't guess the backend to use from the printer string descriptor (config PRINTER.PRINTER)") + context['logs'].append('Backend found: ' + selected_backend) + try: + be_class = backend_factory(selected_backend)['backend_class'] + be = be_class(config['PRINTER']['PRINTER']) + context['logs'].append('Got backend driver') + for i in range(1,num_copies): + be.write(qlr.data) + + context['logs'].append('Data sent to printer') + be.dispose() + del be + except Exception as e: + context['logs'].append('Exception: ' + str(e)) + logger.warning('Exception happened: %s', e) + + context['logs'].append('Finished printing label') + return context diff --git a/labelprinter/labels.py b/labelprinter/labels.py index 685bdf8..24650f1 100644 --- a/labelprinter/labels.py +++ b/labelprinter/labels.py @@ -6,8 +6,11 @@ from io import BytesIO import datetime import textwrap from math import floor + +import PIL.Image import barcode as python_barcode from PIL import Image, ImageDraw, ImageFont +import labelprinter def now(fmt="%Y-%m-%d %H:%M"): @@ -43,7 +46,8 @@ def wrap(text, col_width): return "\n".join(textwrap.wrap(text, col_width)) -def container_label(data, barcode_class='code128', fmt='png', logo_file='./static/images/djlogo256.png',owner_name='Dirk Jahnke', description='', **writer_options): +def container_label(data, barcode_class='code128', fmt='png', logo_file='./static/images/djlogo256.png', + owner_name='Dirk Jahnke', description='', description_line2='', **options): """Return a barcode's image data. Powered by the Python library ``python-barcode``. See this library's documentation for more details. @@ -60,6 +64,10 @@ def container_label(data, barcode_class='code128', fmt='png', logo_file='./stati svg -> embeddable code for html img tag logo_file File path to logo file to be included + owner_name + Name of owner printed underneath the logo + description + Text to be printed on bottom of the label writer_options Various options for the writer to tune the appearance of the barcode (see python-barcode documentation). @@ -86,8 +94,10 @@ def container_label(data, barcode_class='code128', fmt='png', logo_file='./stati """ with Image.open(logo_file) as logo_img: - font_size = 16 - logo_img = logo_img.resize((128,128)) + font_size = 22 + font_size_small = 16 + owner_name_font_size = 26 + logo_img = logo_img.resize((128, 128)) logo_img = logo_img.convert('L') threshold = 20 logo_img = logo_img.point(lambda p: 255 if p < threshold else 0) @@ -96,26 +106,47 @@ def container_label(data, barcode_class='code128', fmt='png', logo_file='./stati data = str(data).zfill(constructor.digits) writer = { 'svg': python_barcode.writer.ImageWriter, - 'png': python_barcode.writer.ImageWriter + 'png': python_barcode.writer.ImageWriter, + 'image': python_barcode.writer.ImageWriter }[fmt] barcode_img = constructor(data, writer=writer()) - img = barcode_img.render(writer_options=writer_options) + img = barcode_img.render(writer_options=options['writer_options']) barcode_xsize, barcode_ysize = img.size logo_xsize, logo_ysize = logo_img.size - result_img = Image.new('1', (696, barcode_ysize+20), 1) - result_img.paste(logo_img, (0, floor(barcode_ysize/3)-floor(logo_ysize/2))) + label_xsize = 696 + label_ysize = barcode_ysize + font_size if description_line2 == '' else barcode_ysize + 2 * font_size + result_img = Image.new('1', (label_xsize, label_ysize), 1) + result_img.paste(logo_img, (owner_name_font_size + 10, floor(barcode_ysize / 2) - 20 - floor(logo_ysize / 2))) start_x_for_barcode = logo_xsize + 10 max_x_for_barcode = 696 - start_x_for_barcode - result_img.paste(img, (start_x_for_barcode + floor((max_x_for_barcode-barcode_xsize)/2), 5)) - # fnt = ImageFont.truetype("Pillow/Tests/fonts/FreeMono.ttf", 40) + result_img.paste(img, (start_x_for_barcode + floor((max_x_for_barcode - barcode_xsize) / 2), 5)) fnt = ImageFont.truetype("./static/fonts/DejaVuSerif.ttf", font_size) - d = ImageDraw.Draw(result_img) - d.text((20,logo_ysize+40), owner_name, font=fnt) - d.text((30+floor((660-fnt.getlength(description))/2),barcode_ysize), description, font=fnt) + owner_name_fnt = ImageFont.truetype("./static/fonts/DejaVuSerif.ttf", owner_name_font_size) + owner_text_img = Image.new('1', (floor(owner_name_fnt.getlength(owner_name)+1), owner_name_font_size+5), 1) + d = ImageDraw.Draw(owner_text_img) + d.text((0,0), owner_name, font=owner_name_fnt) + owner_text_img = owner_text_img.transpose(PIL.Image.ROTATE_90) + result_img.paste(owner_text_img, (0, 10)) - if fmt == 'png': + d = ImageDraw.Draw(result_img) + #d.text((20, logo_ysize), owner_name, font=fnt) + if fnt.getlength(description) > 660: + fnt_small = ImageFont.truetype("./static/fonts/DejaVuSerif.ttf", font_size_small) + d.text((0, barcode_ysize), description, font=fnt_small) + if description_line2 != '': + d.text((0, barcode_ysize + font_size), description_line2, font=fnt_small) + else: + #d.text((30 + floor((660 - fnt.getlength(description)) / 2), barcode_ysize), description, font=fnt) + d.text((0, barcode_ysize), description, font=fnt) + if description_line2 != '': + d.text((0, barcode_ysize + font_size), description_line2, font=fnt) + + if fmt == 'image': + return result_img + elif fmt == 'png': return pil_to_html_imgdata(result_img, fmt='PNG') else: prefix = "data:image/svg+xml;charset=utf-8;base64," return prefix + base64.b64encode(result_img).decode() +