Skip to main content

Zebra label printer plugin for InvenTree

Project description

License: MIT

inventree-zebra-plugin

This is a label printing plugin for InvenTree, which provides support for Zebra Label printers. It allows two modes of operation:

  • Use the ZPL library to convert the png data provided by InvenTree to Zebra's bitmap format and send this to the printer.
  • Write a ZPL template and let the printer do the rendering.

It can output the print data either to a local printer connected to the computer via USB or to a network printer with an IP address. The output can be configured in the InvenTree plugin user interface. A preview using the labalary API is also possible. The plugin allows to print the same label multiple times e.g. to put in on the front and back side of a box. Just increase the Number of labels parameter in the print form. This feature just adds a ^PQ command to the ZPL code. The maximum value is 99.

Installation

The latest release of the plugin is on pypi. Install this plugin using pip withr the following command:

pip install inventree-zebra-plugin

Configuration Options

Printer Interface

Here you can chose between local printer, network printer or the labelary.com API. The last one is useful for preview of labels, especially when ZPL templates are used. Default value is a local printer.

IP address

In case you use an IP printer set the IPv4 address here. This can be overwritten by the template. See below.

Port

In case you use an IP printer set the port number here. The default port number is 9100.

Local Device

In case of a local printer set the device here. The plugin actually puts the data directly to the device /dev/usb/lp0. No printer spooler is involved so far.

Threshold

The image from pillow comes in greyscale. The plugin converts it ti pure BW because this gives a much better print result. The threshold between black and white can be adjusted here.

Darkness

This is a value that influences the darkness of the print. Allowed values are 0 (white) to 30 (black). It is directly converted to a SD command in ZPL. If your black areas tend to blur out reduce the darkness. This can be overwritten by the template.

Dots per mm

This sets the resolution of the printer. You can choose between 8, 12 and 24 dpmm depending on your printer model.

Printer init

This string added to the printer output. It can be used to set special commands e.g. label rotation, mirror or white on black. Please refer to the ZPL manual for more information.

Zebra printers store settings after printing. So if a rotated label has been printed all following label will be rotated unless you change it. The default sets the printer to settings that have been useful for me. You might want to change it according to your requirements. Please keep in mind that this string is passed directly to the printer without any checks. So be careful when editing here.

Get Printer info

Turn this switch on to display a collection of all IP printers below on this page.

Label Template

The label needs a template described in html and css. The template should start with a page definition that defines the label size as shown below:

    @page {
        {% localize off %}
        height: {{ height }}mm;
        width: {{ width }}mm;
        {% endlocalize %}
        padding: 0mm;
        margin: 0px 0px 0px 0px;
        background-color: white;
    }

The height and width parameters are defined in the InvenTree admin panel in the label section. These values have to fit the label size that is in the printer. See the example templates for details on template definition.

Multi printer usage

We have the requirement to print labels in different sizes. As we do not want to change the reel for each print we set up a second printer loaded with a different label size. The plugin allows to add multiple printers controlled by the label template. Just define a key with an IP address in the label meta data:

{"ip_address":"xxx.yyy.zzz.eee"}
{"darkness":xx}
{"dpmm":xx}

If the printer driver finds that key, the IP address from the printer settings is overwritten with the address from the meta data. So the print will end up in another printer.

Only the IP address, darkness and dpmm can be overwritten so far. All other settings remain.

Quality matters

The InvenTree printer system uses a graphical representation of the label. The label is described in HTML, converted to a pixel graphic and printed. The advantage is independency from printer models and systems. Disadvantage is larger data and quality problems with darkness and scaling. Let's have a look at the following printout:

QRcodes

Both codes have been printed with the same printer on the same reel. The left one is hardly readable using my mobile. The right one reads easily even as it is smaller.

Secret 1, Scale

The printer resolution is 8 dots per mm resulting in a dot size of 0.125mm. The QR code pixel and the printer pixel size should be integrally divisible. The code in the picture has 21 pixels plus one in the frame, so 23 pixel. The frame is set in the HTML description.

{% qrcode qr_data border=1 %}

I selected two dots per pixel. So 23 * 2 * 0.125 = 6.125mm. If the size is something different scaling takes place and the result might be worse. If you like a larger printout select more dots per pixel. From a certain size upwards the value does not matter any more because the code gets large enough to be readable in any quality.

Secret 2: Darkness

Zebra printers allow to set the darkness of the print in values between 0 (white) and 30 (max) The left code was printed with a value of 30. The black dots tend to blur out a bit resulting in smaller white areas. The right code was printed with a value of 25 resulting in larger white pixels. The darkness values are just examples. Your values will differ based on printer model, media type and printer age. The printer head tends to wear out and the darkness value might need an adjustment from time to time.

In printer rendering

You can also bypass the InvenTree print engine and render the label inside the printer. The printer knows how to render the label for best quality. Inspired by the inventree-zpl-plugin a similar function was aded to the zebra printer driver. You can write a ZPL template and upload it to the InvenTree Label templates as usual. Add a command to the template's metadata:

{"zpl_template": "True"}

In that case the printer driver ignores the picture rendered by WeasyPrint. Instead it calls the render_to_string function of the template and sends the result to the printer. The result can look like:

Label Example

The upper label was created using this template:

{% autoescape off %}
^FT30,25^A0N,18,22^FDIPN^FS
^FT150,30^FB100,1,,C,,^A0N,24,32^FDACME^FS
^FT320,25^A0N,18,22^FD{{ item.pk }}^FS
^FT100,70^FB200,2,,C,,^A0N,18,22^FD{{ part.name }}^FS
^FT100,100^FB200,1,,C,,^A0N,18,22^FD{{ part.manufacturer_parts.first.manufacturer.name }}^FS
^FT30,150^FB340,1,,C,,^A0N,30,40^FD{{ part.IPN }}^FS
^FT20,210^FB360,3,,L,,^A0N,18,22^FD{{ part.description }}^FS
^FT15,110^BQ,2,3^FDQA,{{ part.IPN }}^FS
^FT310,130^BQ,2,3^FDQA,{{ qr_data }}^FS
{% endautoescape %}

Autoescape must be off. We do not need &quot and similar escapes here. Context variables can be used as usual. Start and stop commands ^XA and ^XZ are added by the driver and not allowed in the template. The printer init string as given in the settings is added as usual.

!!! warning "Limitation" ZPL commands starting with backslash like \& cannot be used so far.

Preview

The printer driver allows an output device called "preview". If this is selected the ZPL code is sent to the API of labelary.com. The API sends back pdf data which is displayed in a new browser window. This is helpful while writing ZPL templates but works with HTML templates too. Please be careful and do not send confidential information to the API.

In case you need to pass a proxy for the POST requests set the environment variables PROXY_CON and PROXY_URL on the server. The plugin does not have settings for this.

Getting printer info

With the multi printer feature it can happen that you have several printers in your setup. When the Get Printer Info switch is set ON, the driver calls each printer once a minute and collects some info about it. It calls the printer configured in the settings as well as all printers it finds in the label templates. In case a printer is unreachable, an error message is shown. If a printer is used in several templates it is listed only once.

The printer info feature works for local USB printers too.

Printer Info

This info is only visible in the classical user interface of InvenTree. For PUI the UI api as changed. The plugin does not support that so far.

Inventree 1.0

The UI features of the driver are minimal. There is only the printer status list in the settings. The function get_settings_content is replaced by get_admin_context. Some lines of javascript code in ./static and some table tweaks are needed. That's basically it. The printer logic remains the same and works fine with Inventree 1.0.

The machine interface is not used yet. We have no need for it. Our method to support several printers binds the template fix to a dedicated printer. No way to print a 50x30 label on a printer loaded with 20x12 labels. the only drawback is that the templates metadata field needs to be edited manually in the admin interface. But this is done seldom.

How it works

First import all the stuff you need. Here we use the translation mechanism from Django for multi language support. The import the InvenTree libs and everything you need for plugin. Here we have ZPL for the Zebra bitmaps and socket for the IP connection to the printer.

The next part is this:

class ZebraLabelPlugin(LabelPrintingMixin, SettingsMixin, IntegrationPluginBase):

    AUTHOR = "Michael Buchmann"
    DESCRIPTION = "Label printing plugin for Zebra printers"
    VERSION = ZEBRA_PLUGIN_VERSION
    NAME = "Zebra labels"
    SLUG = "zebra"
    TITLE = "Zebra Label Printer"

The name of the class can be freely chosen but should be different from SLUG. Otherwise it does not show up. You reference to it in the entry_points section of the setup.py file. The parameters need to be like in the example. Then there is the description block. The keywords are fixed and need to be like that. The values are found in the UI as shown in the picture below.

Config

Then we add the configuration parameters.

SETTINGS = {
        'CONNECTION': {
            'name': _('Printer Interface'),
            'description': _('Select local or network printer'),
            'choices': [('local','Local printer e.g. USB'),('network','Network printer with IP address')],
            'default': 'local',
        },
        'PORT': {
            'name': _('Port'),
            'description': _('Network port in case of network printer'),
            'default': '9100',
        },
    }

We need to define a dict with the name SETTINGS. Please be aware the keys need to be in all CAPITAL letters like CONNECTION. Simple parameters are just text strings like the port. We can set a default. The name and description shows up in the UI. Instead of a simple text we can also use choices. The first string like "local" it the key you use in the code. The second one is the description in the UI. After that we need to define a function:

def print_label(self, **kwargs){

The kwargs is a dict with the following keys:

  • pdf_data
  • user
  • filename
  • label_instance
  • item_instance
  • width
  • height
  • png_file

The item_instance is the part to be printed. This allows direct access to all part data. The arguments width and height come from the settings of the label in the admin interface. NOT from the html template. For the Zebra printer we use the png_file. This is a PIL (python Pillow) object with the graphic of the label in PNG format. The PIL object is a greyscale image. Because the printer can just print pure BW we convert this to a BW picture.

fn = lambda x : 255 if x > Threshold else 0
label_image = label_image.convert('L').point(fn, mode='1')

The threshold can by modified by a plugin parameter. 200 is a good starting value. This trick gives much better prints. We can put the result of this directly into the ZPL library.

l = zpl.Label(Height, Width, dpmm)
li.set_darkness(darkness)
...
l.write_graphic(label_image, Width)
l.endorigin()

Width and Height define is the size of the label in millimeters as described above. The third parameter is the resolution of the printer in dots per mm. write_graphic converts the pillow data to ZPL.

The plugin was tested with a labels of various sizes defined using css and html. The DPI scaling can be chosen in the InvenTree settings. 800 is a good value because it gives high quality.

The rest of the code is just output to the printer on different interfaces.

ZPL deep dive

in Normal Mode (no ZPL templates) the plugin uses the ZPL library to convert the png data provided by InvenTree to Zebra's bitmap format. ZPL code needs to have a certain sequence of commands to properly work. Some ZPL commands are generated by the ZPL library, others can be included using the "Printer Init" parameter of tthe plugin. Here is a closer look at the ZPL code that the plugin generates. These commands are generated by the ZPL library and calculated based on the label size and darkness parameter:

Command Description
^XA Start of ZPL file
^PW400 Width of label in dots
^LL240 Length of label in dots
~SD22 Darkness
^LH0,0 Label home

The following commands are from the Printer Init parameter. These are just the defaults. The can be edited based on our personal setup.

Command Description
~TA000 tear off
~JSN back feed
^LT0 top offset
^MNW media tracking. This is for non continuous labels
^MTT media type. This is for thermo transfer. Adjust to your needs
^PMN no mirror print
^PON normal orientation
^PR2,2 2 Speed 2 inch per second
^LRN No reverse print (white on black)

Finally there are commands that are again inserted by the ZPL library:

Command Description
^FO0,0 Start field
^PQ1 Label count (one)
^GFA Graphics bit field
... Graphics data
^FS End of field
^XZ End of file

For more details on the commands refer to the ZPL programming guide. Happy printing.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

inventree_zebra_plugin-0.9.0.tar.gz (18.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

inventree_zebra_plugin-0.9.0-py3-none-any.whl (14.4 kB view details)

Uploaded Python 3

File details

Details for the file inventree_zebra_plugin-0.9.0.tar.gz.

File metadata

  • Download URL: inventree_zebra_plugin-0.9.0.tar.gz
  • Upload date:
  • Size: 18.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for inventree_zebra_plugin-0.9.0.tar.gz
Algorithm Hash digest
SHA256 6a56ad407353f5ff494d3f775a9456ef6bc908f990cd29821e4cd4f6439b6863
MD5 73ab310f7064ef3d938c2d213bf958ea
BLAKE2b-256 4bb1ea4a2c2bf758cd701e8d27ff0f64ed3c4c61adf407787c5eb829cfcbd1f4

See more details on using hashes here.

Provenance

The following attestation bundles were made for inventree_zebra_plugin-0.9.0.tar.gz:

Publisher: ci.yml on SergeoLacruz/inventree-zebra-plugin

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file inventree_zebra_plugin-0.9.0-py3-none-any.whl.

File metadata

File hashes

Hashes for inventree_zebra_plugin-0.9.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b8174f3144cbab712bffce46272b6b0a2c1b79983062543353a517973246f02d
MD5 e4f28f4e4a96740d38a8f582e9cf74d2
BLAKE2b-256 3403c017a7b2aca4672e6b38da859ba645d5a5c5b693ba53be6b6242f38d8541

See more details on using hashes here.

Provenance

The following attestation bundles were made for inventree_zebra_plugin-0.9.0-py3-none-any.whl:

Publisher: ci.yml on SergeoLacruz/inventree-zebra-plugin

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page