Label creation and print
This commit is contained in:
		| @@ -4,17 +4,33 @@ | |||||||
| {% block title %}Container: {{ container.named_id }}{% endblock %} | {% block title %}Container: {{ container.named_id }}{% endblock %} | ||||||
|  |  | ||||||
| {% block content %} | {% block content %} | ||||||
| ===== Print Label Content ===== | <h1>Print Container Label</h1> | ||||||
|  |  | ||||||
| <!-- Action buttons --> | <!-- Action buttons --> | ||||||
| <div class="row"> | <div class="row"> | ||||||
|  |  | ||||||
|   <div class="col-sm-12"> |   <div class="col-sm-12"> | ||||||
|     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 }}: | ||||||
|     <br /> |     <br /> | ||||||
|     <img  class="img-fluid shadow p-3 mb-5 bg-body rounded" src="{{ barcode_img }}"> |     <img  class="img-fluid shadow p-3 mb-5 bg-body rounded" src="{{ barcode_img }}"> | ||||||
|   </div> |   </div> | ||||||
|  |   <div class="col-sm-12"> | ||||||
|  |     <form method="gest"> | ||||||
|  |       {% csrf_token %} | ||||||
|  |       <label for="num_copies">Number of copies:</label><input type="number" id="num_copies" size="2" min="1" max="8" name="num_copies" value="1"> | ||||||
|  |       <input type="submit" class="btn btn-primary" value="Print"> | ||||||
|  |     </form> | ||||||
|  |   </div> | ||||||
|  |   <div class="col-sm-12"> | ||||||
|  |     <!-- | ||||||
|  |     {% if logs %} | ||||||
|  |       {% for msg in logs %} | ||||||
|  |         {{ msg }}<br /> | ||||||
|  |       {% endfor %} | ||||||
|  |     {% else %} | ||||||
|  |       no messages | ||||||
|  |     {% endif %} | ||||||
|  |     --> | ||||||
|  |   </div> | ||||||
| </div> | </div> | ||||||
| <!-- End Action buttons --> | <!-- End Action buttons --> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,6 +1,8 @@ | |||||||
| from django.views import generic | from django.views import generic | ||||||
| from .models import Container, ContainerType | from .models import Container, ContainerType | ||||||
| from labelprinter.labels import container_label | import logging, json | ||||||
|  |  | ||||||
|  | logger = logging.getLogger(__name__) | ||||||
|  |  | ||||||
|  |  | ||||||
| class ContainerListView(generic.ListView): | class ContainerListView(generic.ListView): | ||||||
| @@ -62,22 +64,81 @@ class ContainerPrintLabelView(generic.DetailView): | |||||||
|  |  | ||||||
|     def get_context_data(self, **kwargs): |     def get_context_data(self, **kwargs): | ||||||
|         context = super().get_context_data(**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 |         container_description = self.object.container_type.named_id | ||||||
|         if len(self.object.container_type.description) > 0: |         if len(self.object.container_type.description) > 0: | ||||||
|             container_description += ': ' + self.object.container_type.description |             container_description += ': ' + self.object.container_type.description | ||||||
|         if len(self.object.description) > 0: |         if len(self.object.description) > 0: | ||||||
|             container_description += ' / ' + self.object.description |             container_description_line2 = self.object.description | ||||||
|         context['barcode_img'] = container_label(self.object.named_id, description=container_description, writer_options={'background': 'white', |         label_image = container_label( | ||||||
|                                                                                'font_size': 10, |             self.object.named_id, | ||||||
|                                                                                'foreground': 'black', |             fmt='image', | ||||||
|                                                                                'module_height': 10.0, |             description=container_description, | ||||||
|                                                                                'module_width': 0.2, |             description_line2=container_description_line2, | ||||||
|                                                                                'quiet_zone': 2.5, |             writer_options={'font_size': 14, | ||||||
|                                                                                'text': 'This is the text', |                             'module_height': 10.0, | ||||||
|                                                                                'text_distance': 3.0, |                             'quiet_zone': 4.5, | ||||||
|                                                                                'write_text': True |                             '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 |         return context | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -6,8 +6,11 @@ from io import BytesIO | |||||||
| import datetime | import datetime | ||||||
| import textwrap | import textwrap | ||||||
| from math import floor | from math import floor | ||||||
|  |  | ||||||
|  | import PIL.Image | ||||||
| import barcode as python_barcode | import barcode as python_barcode | ||||||
| from PIL import Image, ImageDraw, ImageFont | from PIL import Image, ImageDraw, ImageFont | ||||||
|  | import labelprinter | ||||||
|  |  | ||||||
|  |  | ||||||
| def now(fmt="%Y-%m-%d %H:%M"): | 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)) |     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. |     """Return a barcode's image data. | ||||||
|     Powered by the Python library ``python-barcode``. See this library's |     Powered by the Python library ``python-barcode``. See this library's | ||||||
|     documentation for more details. |     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 |         svg -> embeddable code for html img tag | ||||||
|     logo_file |     logo_file | ||||||
|         File path to logo file to be included |         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 |     writer_options | ||||||
|       Various options for the writer to tune the appearance of the barcode |       Various options for the writer to tune the appearance of the barcode | ||||||
|       (see python-barcode documentation). |       (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: |     with Image.open(logo_file) as logo_img: | ||||||
|         font_size = 16 |         font_size = 22 | ||||||
|         logo_img = logo_img.resize((128,128)) |         font_size_small = 16 | ||||||
|  |         owner_name_font_size = 26 | ||||||
|  |         logo_img = logo_img.resize((128, 128)) | ||||||
|         logo_img = logo_img.convert('L') |         logo_img = logo_img.convert('L') | ||||||
|         threshold = 20 |         threshold = 20 | ||||||
|         logo_img = logo_img.point(lambda p: 255 if p < threshold else 0) |         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) |         data = str(data).zfill(constructor.digits) | ||||||
|         writer = { |         writer = { | ||||||
|             'svg': python_barcode.writer.ImageWriter, |             'svg': python_barcode.writer.ImageWriter, | ||||||
|             'png': python_barcode.writer.ImageWriter |             'png': python_barcode.writer.ImageWriter, | ||||||
|  |             'image': python_barcode.writer.ImageWriter | ||||||
|         }[fmt] |         }[fmt] | ||||||
|         barcode_img = constructor(data, writer=writer()) |         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 |         barcode_xsize, barcode_ysize = img.size | ||||||
|         logo_xsize, logo_ysize = logo_img.size |         logo_xsize, logo_ysize = logo_img.size | ||||||
|         result_img = Image.new('1', (696, barcode_ysize+20), 1) |         label_xsize = 696 | ||||||
|         result_img.paste(logo_img, (0, floor(barcode_ysize/3)-floor(logo_ysize/2))) |         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 |         start_x_for_barcode = logo_xsize + 10 | ||||||
|         max_x_for_barcode = 696 - start_x_for_barcode |         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)) |         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) |         fnt = ImageFont.truetype("./static/fonts/DejaVuSerif.ttf", font_size) | ||||||
|  |  | ||||||
|         d = ImageDraw.Draw(result_img) |         owner_name_fnt = ImageFont.truetype("./static/fonts/DejaVuSerif.ttf", owner_name_font_size) | ||||||
|         d.text((20,logo_ysize+40), owner_name, font=fnt) |         owner_text_img = Image.new('1', (floor(owner_name_fnt.getlength(owner_name)+1), owner_name_font_size+5), 1) | ||||||
|         d.text((30+floor((660-fnt.getlength(description))/2),barcode_ysize), description, font=fnt) |         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') |             return pil_to_html_imgdata(result_img, fmt='PNG') | ||||||
|         else: |         else: | ||||||
|             prefix = "data:image/svg+xml;charset=utf-8;base64," |             prefix = "data:image/svg+xml;charset=utf-8;base64," | ||||||
|             return prefix + base64.b64encode(result_img).decode() |             return prefix + base64.b64encode(result_img).decode() | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user