Skip to content

Instantly share code, notes, and snippets.

@waylan
Created October 19, 2021 12:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save waylan/29f4b7d97c02da4d10336fba8bbe2e43 to your computer and use it in GitHub Desktop.
Save waylan/29f4b7d97c02da4d10336fba8bbe2e43 to your computer and use it in GitHub Desktop.
Print labels directly to Brother QL label printer using brother_ql lib.
from PIL import Image, ImageDraw, ImageFont
from brother_ql.devicedependent import label_type_specs
from brother_ql import BrotherQLRaster, create_label
from brother_ql.backends.helpers import send
PRINTER = {
'model': 'QL-800',
'address': 'usb://0x04f9:0x209b'
}
def get_font(text, size, margin, fontname, draw, start=100):
' Return font after calculating largest size which fits in box of given size.'
fontsize = start
while True:
font = ImageFont.truetype(fontname, fontsize)
txtsize = draw.multiline_textsize(text, font=font)
if txtsize[0] >= size[0] - (margin * 2) or txtsize[1] >= size[1] - (margin * 2):
# reduce font size and try again
fontsize -= 2
else:
# print(f'Using fontsize {fontsize}')
return font
def draw_address_label(body, memo, size):
img = Image.new('L', size, 'white')
draw = ImageDraw.Draw(img)
margin = 0
font = get_font(body, size, margin, 'times.ttf', draw, 60)
# Center text horizontally and vertically in image.
# Set anchor point to the middle (half width and half height of image size)
# and anchor alignment to middle/middle (mm) of text.
draw.multiline_text((size[0]/2, size[1]/2), body, fill='black', font=font, anchor='mm', align='center')
smallfont = ImageFont.truetype('times.ttf', 20)
# And memo to bottom left corner
draw.text((margin, size[1] - margin), memo, fill='black', font=smallfont, anchor='ld', align='left')
# Outline with rounded rect for debuging
# draw.rounded_rectangle([(0, 0), (size[0] - 1, size[1] - 1)], radius=10, outline='black', width=1)
return img
def draw_file_label(body, memo, size):
img = Image.new('L', size, 'white')
draw = ImageDraw.Draw(img)
margin = 0
font = get_font(body, size, margin, 'times.ttf', draw, 50)
# Add body to top left
draw.multiline_text((margin, margin + 50), body, fill='black', font=font, anchor='la', align='left')
# And memo to top right corner
draw.text((size[0] - margin, margin), memo, fill='black', font=font, anchor='ra', align='right')
# Outline with rounded rect for debuging
# draw.rounded_rectangle([(0, 0), (size[0] - 1, size[1] - 1)], radius=10, outline='black', width=1)
return img
def print_label(style, label_type, body, memo=None, cut=True, printer=PRINTER):
'''
Print a label directly to printer.
style: The style (layout) of the label. One of `address` or `file`.
label_type: The type (size) of label in the printer. Valid values include
any `name` listed in the output of `brother_ql info labels`.
body: The main body of the label.
memo: Optional secondary content printed to the label.
cut: Instruct the printer to cut after printing the label. Default: `True`.
printer: A dict specifying the printer `model` and `address` to send the print job to.
'''
memo = memo or ''
# Width and height are switched so we can draw with horizontal text. Image will then be rotated.
size = (
label_type_specs[label_type]['dots_printable'][1],
label_type_specs[label_type]['dots_printable'][0]
)
if style == 'address':
img = draw_address_label(body, memo, size)
elif style == 'file':
img = draw_file_label(body, memo, size)
else:
raise ValueError(f"'style' must be one of 'address' or 'file'. Got '{style}' instead.")
qlr = BrotherQLRaster(printer['model'])
create_label(qlr, img, label_type, cut=cut, rotate=90, dpi_600=False)
send(qlr.data, printer['address'])
if __name__ == '__main__':
img1 = draw_address_label('Firstname Somelongname\nSome Building\n123 Any Street Apt C-3\nAnytown PA, 12345', 'No. A.D. 123 of 2021', (991, 306))
img1.save('address_label.png')
img2 = draw_file_label('Somelongname, Firstname\nSomelongname, Othername & Another, Name', '123-2021', (991, 306))
img2.save('file_label.png')
# To print one of the above generated images, run the following command:
# brother_ql -b pyusb -m QL-800 -p usb://0x04f9:0x209b print -l 29x90 address_label.png
# To print a label directly from Python, do this:
print_label('address', '29x90', 'Firstname Somelongname\nSome Building\n123 Any Street Apt C-3\nAnytown PA, 12345', 'No. A.D. 123 of 2021')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment