"""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 PIL.Image import barcode as python_barcode from PIL import Image, ImageDraw, ImageFont import labelprinter 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='', description_line2='', **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 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). 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 = 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) 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, 'image': python_barcode.writer.ImageWriter }[fmt] barcode_img = constructor(data, writer=writer()) writer_options = { 'font_size': 24, 'module_width': 0.25, 'module_height': 10, 'quiet_zone': 3, 'text_distance': 1.0 } writer_options.update(options['writer_options']) img = barcode_img.render(writer_options=writer_options) barcode_xsize, barcode_ysize = img.size logo_xsize, logo_ysize = logo_img.size 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("./static/fonts/DejaVuSerif.ttf", font_size) 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)) 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()