diff --git a/container/templates/container/container_detail.html b/container/templates/container/container_detail.html index ce3ba4b..8f9c3e2 100644 --- a/container/templates/container/container_detail.html +++ b/container/templates/container/container_detail.html @@ -20,7 +20,7 @@
- Edit + Edit Delete
diff --git a/container/templates/container/container_list.html b/container/templates/container/container_list.html index d3f464d..cc0d397 100644 --- a/container/templates/container/container_list.html +++ b/container/templates/container/container_list.html @@ -29,7 +29,11 @@
{{ container.color }}
{{ container.description }}
{{ container.changed_ts | date:'H:i:s d.m.Y' }}
- Delete + + Delete + View + Label + {% endfor %} diff --git a/container/templates/container/container_print_label.html b/container/templates/container/container_print_label.html new file mode 100644 index 0000000..d3c29eb --- /dev/null +++ b/container/templates/container/container_print_label.html @@ -0,0 +1,22 @@ +{% extends "base.html" %} +{% load static %} + +{% block title %}Container: {{ container.named_id }}{% endblock %} + +{% block content %} +===== Print Label Content ===== + + +
+ +
+ Label created for container {{ container.named_id }} of type {{ container.container_type.named_id }} +
+ +
+ +
+ + +
+{% endblock content %} \ No newline at end of file diff --git a/container/urls.py b/container/urls.py index ef56232..b36ec76 100644 --- a/container/urls.py +++ b/container/urls.py @@ -1,13 +1,15 @@ from django.urls import path -from container.views import ContainerListView, ContainerUpdateView, ContainerCreateView, ContainerDetailView, ContainerDeleteView +from container.views import ContainerListView, ContainerUpdateView, ContainerCreateView, ContainerDetailView, ContainerDeleteView, ContainerPrintLabelView from container.views import ContainerTypeListView, ContainerTypeDetailView, ContainerTypeCreateView, ContainerTypeUpdateView, ContainerTypeDeleteView app_name = 'container' urlpatterns = [ path('', ContainerListView.as_view(), name='list'), + path('/', ContainerDetailView.as_view(), name='detail'), path('add/', ContainerCreateView.as_view(), name='add'), path('edit//', ContainerUpdateView.as_view(), name='update'), + path('label//', ContainerPrintLabelView.as_view(), name='print_label'), path('delete//', ContainerDeleteView.as_view(), name='delete'), path('type/', ContainerTypeListView.as_view(), name='container_type_list'), path('type//', ContainerTypeDetailView.as_view(), name='container_type_detail'), diff --git a/container/views.py b/container/views.py index 27c5b51..28fdc16 100644 --- a/container/views.py +++ b/container/views.py @@ -1,6 +1,7 @@ from django.views import generic from .models import Container, ContainerType -from blabel import LabelWriter +from labelprinter.labels import container_label + class ContainerListView(generic.ListView): model = Container @@ -48,13 +49,36 @@ class ContainerPrintLabelView(generic.DetailView): model = Container template_name = 'container/container_print_label.html' - def get(self, **kwargs): - super().get(kwargs) + def get(self, request, **kwargs): + context = super().get(request, **kwargs) + ''' label_writer = LabelWriter( - 'templates/label/container_label.html', - default_stylesheets=("templates/label/label_style.css",) + "container/templates/label/container_label.html", + default_stylesheets=("container/templates/label/label_style.css",) ) - label_writer.write_labels(kwargs['pk'], target="container_label.pdf") + label_writer.write_labels([dict(named_id=kwargs['pk'], id=kwargs['pk'])], target="container_label.pdf") + ''' + return context + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + from labelprinter.labels import container_label + 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 + }) + return context class ContainerTypeListView(generic.ListView): @@ -101,4 +125,3 @@ class ContainerTypeUpdateView(generic.UpdateView): class ContainerTypeDeleteView(generic.DetailView): model = ContainerType - diff --git a/labelprinter/__init__.py b/labelprinter/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/labelprinter/labels.py b/labelprinter/labels.py new file mode 100644 index 0000000..685bdf8 --- /dev/null +++ b/labelprinter/labels.py @@ -0,0 +1,121 @@ +"""Utilities for label generation. + stolen from: https://github.com/Edinburgh-Genome-Foundry/blabel +""" +import base64 +from io import BytesIO +import datetime +import textwrap +from math import floor +import barcode as python_barcode +from PIL import Image, ImageDraw, ImageFont + + +def now(fmt="%Y-%m-%d %H:%M"): + """Display the current time. + Default format is "year-month-day hour:minute" but another format can be + provided (see ``datetime`` docs for date formatting). + """ + now = datetime.datetime.now() + if fmt is not None: + now = now.strftime(fmt) + return now + + +def pil_to_html_imgdata(img, fmt='PNG'): + """Convert a PIL image into HTML-displayable data. + + The result is a string ``data:image/FMT;base64,xxxxxxxxx`` which you + can provide as a "src" parameter to a ```` tag. + Examples: + --------- + >>> data = pil_to_html_imgdata(my_pil_img) + >>> html_data = '' % data + """ + buffered = BytesIO() + img.save(buffered, format=fmt) + img_str = base64.b64encode(buffered.getvalue()) + prefix = 'data:image/%s;charset=utf-8;base64,' % fmt.lower() + return prefix + img_str.decode() + + +def wrap(text, col_width): + """Breaks the text into lines with at maximum 'col_width' characters.""" + 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): + """Return a barcode's image data. + Powered by the Python library ``python-barcode``. See this library's + documentation for more details. + Parameters + ---------- + data + Data to be encoded in the datamatrix. + barcode_class + Class/standard to use to encode the data. Different standards have + different constraints. + fmt + The format to be used when rendering the resulting image + png -> png image + svg -> embeddable code for html img tag + logo_file + File path to logo file to be included + writer_options + Various options for the writer to tune the appearance of the barcode + (see python-barcode documentation). + Returns + ------- + image_base64_data + A string ``data:image/png;base64,xxxxxxxxx`` which you can provide as a + "src" parameter to a ```` tag. + Examples: + --------- + >>> data = barcode('EGF12134', barcode_class='code128') + >>> html_data = '' % data + Examples of writer options: + >>> { 'background': 'white', + >>> 'font_size': 10, + >>> 'foreground': 'black', + >>> 'module_height': 15.0, + >>> 'module_width': 0.2, + >>> 'quiet_zone': 6.5, + >>> 'text': '', + >>> 'text_distance': 5.0, + >>> 'write_text': True + >>> } + """ + + with Image.open(logo_file) as logo_img: + font_size = 16 + 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) + logo_img = logo_img.convert('1') + constructor = python_barcode.get_barcode_class(barcode_class) + data = str(data).zfill(constructor.digits) + writer = { + 'svg': python_barcode.writer.ImageWriter, + 'png': python_barcode.writer.ImageWriter + }[fmt] + barcode_img = constructor(data, writer=writer()) + img = barcode_img.render(writer_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))) + 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) + 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) + + if 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()