Create label image for container
This commit is contained in:
parent
7013301fbd
commit
f507481491
|
@ -20,7 +20,7 @@
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<a class="btn btn-primary" href="{% url 'container:edit' container.id %}" role="button">Edit</a>
|
<a class="btn btn-primary" href="{% url 'container:update' container.id %}" role="button">Edit</a>
|
||||||
<a class="btn btn-primary" href="{% url 'container:delete' container.id %}" role="button">Delete</a>
|
<a class="btn btn-primary" href="{% url 'container:delete' container.id %}" role="button">Delete</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,11 @@
|
||||||
<td><div>{{ container.color }}</div></td>
|
<td><div>{{ container.color }}</div></td>
|
||||||
<td><div>{{ container.description }}</div></td>
|
<td><div>{{ container.description }}</div></td>
|
||||||
<td><div>{{ container.changed_ts | date:'H:i:s d.m.Y' }}</div></td>
|
<td><div>{{ container.changed_ts | date:'H:i:s d.m.Y' }}</div></td>
|
||||||
<td><a class="btn btn-outline-primary btn-sm" href="{% url 'container:delete' container.id %}" role="button">Delete</a></td>
|
<td>
|
||||||
|
<a class="btn btn-outline-primary btn-sm" href="{% url 'container:delete' container.id %}" role="button">Delete</a>
|
||||||
|
<a class="btn btn-outline-primary btn-sm" href="{% url 'container:detail' container.id %}" role="button">View</a>
|
||||||
|
<a class="btn btn-outline-primary btn-sm" href="{% url 'container:print_label' container.id %}" role="button">Label</a>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
|
{% block title %}Container: {{ container.named_id }}{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
===== Print Label Content =====
|
||||||
|
|
||||||
|
<!-- Action buttons -->
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<div class="col-sm-12">
|
||||||
|
Label created for container {{ container.named_id }} of type {{ container.container_type.named_id }}
|
||||||
|
<br />
|
||||||
|
<img class="img-fluid shadow p-3 mb-5 bg-body rounded" src="{{ barcode_img }}">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<!-- End Action buttons -->
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{% endblock content %}
|
|
@ -1,13 +1,15 @@
|
||||||
from django.urls import path
|
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
|
from container.views import ContainerTypeListView, ContainerTypeDetailView, ContainerTypeCreateView, ContainerTypeUpdateView, ContainerTypeDeleteView
|
||||||
|
|
||||||
app_name = 'container'
|
app_name = 'container'
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('', ContainerListView.as_view(), name='list'),
|
path('', ContainerListView.as_view(), name='list'),
|
||||||
|
path('<int:pk>/', ContainerDetailView.as_view(), name='detail'),
|
||||||
path('add/', ContainerCreateView.as_view(), name='add'),
|
path('add/', ContainerCreateView.as_view(), name='add'),
|
||||||
path('edit/<int:pk>/', ContainerUpdateView.as_view(), name='update'),
|
path('edit/<int:pk>/', ContainerUpdateView.as_view(), name='update'),
|
||||||
|
path('label/<int:pk>/', ContainerPrintLabelView.as_view(), name='print_label'),
|
||||||
path('delete/<int:pk>/', ContainerDeleteView.as_view(), name='delete'),
|
path('delete/<int:pk>/', ContainerDeleteView.as_view(), name='delete'),
|
||||||
path('type/', ContainerTypeListView.as_view(), name='container_type_list'),
|
path('type/', ContainerTypeListView.as_view(), name='container_type_list'),
|
||||||
path('type/<int:pk>/', ContainerTypeDetailView.as_view(), name='container_type_detail'),
|
path('type/<int:pk>/', ContainerTypeDetailView.as_view(), name='container_type_detail'),
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
from django.views import generic
|
from django.views import generic
|
||||||
from .models import Container, ContainerType
|
from .models import Container, ContainerType
|
||||||
from blabel import LabelWriter
|
from labelprinter.labels import container_label
|
||||||
|
|
||||||
|
|
||||||
class ContainerListView(generic.ListView):
|
class ContainerListView(generic.ListView):
|
||||||
model = Container
|
model = Container
|
||||||
|
@ -48,13 +49,36 @@ class ContainerPrintLabelView(generic.DetailView):
|
||||||
model = Container
|
model = Container
|
||||||
template_name = 'container/container_print_label.html'
|
template_name = 'container/container_print_label.html'
|
||||||
|
|
||||||
def get(self, **kwargs):
|
def get(self, request, **kwargs):
|
||||||
super().get(kwargs)
|
context = super().get(request, **kwargs)
|
||||||
|
'''
|
||||||
label_writer = LabelWriter(
|
label_writer = LabelWriter(
|
||||||
'templates/label/container_label.html',
|
"container/templates/label/container_label.html",
|
||||||
default_stylesheets=("templates/label/label_style.css",)
|
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):
|
class ContainerTypeListView(generic.ListView):
|
||||||
|
@ -101,4 +125,3 @@ class ContainerTypeUpdateView(generic.UpdateView):
|
||||||
|
|
||||||
class ContainerTypeDeleteView(generic.DetailView):
|
class ContainerTypeDeleteView(generic.DetailView):
|
||||||
model = ContainerType
|
model = ContainerType
|
||||||
|
|
||||||
|
|
|
@ -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 ``<img/>`` tag.
|
||||||
|
Examples:
|
||||||
|
---------
|
||||||
|
>>> data = pil_to_html_imgdata(my_pil_img)
|
||||||
|
>>> html_data = '<img src="%s"/>' % 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 ``<img/>`` tag.
|
||||||
|
Examples:
|
||||||
|
---------
|
||||||
|
>>> data = barcode('EGF12134', barcode_class='code128')
|
||||||
|
>>> html_data = '<img src="%s"/>' % 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()
|
Loading…
Reference in New Issue