CUPS rastertoql filter  1.0.4
Filter for the Brother QL family of label printers
CUPS filter for Brother QL series label printers

The Brother QL series of label printers are easy to use printers. You can use pre-cut labels or create your own with continuous lenght labels.

This CUPS filter implementation will add a bi-colour print capability for the QL8xx series printers in conjunction with the special DK2215 roll.

Happy printing!

Supported printer models

Printer Cutter 300 DPI bi-colour > 62mm tested
QL500 manual X X
QL550 auto X
QL560 auto X
QL570 auto X
QL580 auto X
QL600 auto X
QL600TD auto X
QL700 auto X
QL710W auto X
QL710NW auto X
QL800 auto X X X
QL810W auto X X
QL820NWB auto X X
QL1050 auto X X
QL1060N auto X X
Note
For QL models with an auto cutter, it is possible to print multipage documents and each page gets cut by default. For QL models with a manual cutter multipage documents are printed at once and at the end the user can manually cut the whole page sequence.
Reading the printer's datasheets is confusing regarding their print data compression capabilitites. Most datasheets state, compression isn't supported or (at least) with some restrictions (limited to the "serial interface" for example). But printer data records from different drivers still show they use the RLE compression method. On the other hand, data compression on a full speed USB link doesn't makes sense for this small amount of data. Thus, this filter doesn't use compression at all.
Various printers listed above can print vertically at 600 DPI. But the driver doesn't support it, yet.
Attention
The filter pdftopdf tends to apply unexpected rotations to your document. If your document is oriented in landscape and would fit to a continuous length label, pdftopdf will rotate your document, because the continuous length label looks like a portrait oriented label to it. Using the pdfAutoRotate=off print parameter solves this issue.
The filter pdftoraster tends to ignore the PageSize printing parameter and creates an inappropriate CUPS raster instead.
An example: your document is a 62 mm x 29 mm landscape oriented label and you want to print it on a continuous length label like the DK2251 roll is. This is a regular use case and works perfectly.
But in this case pdftoraster prefers the DK1209 portrait label roll instead (with its size 29 mm x 62 mm). And creates the CUPS raster for it, which isn't what you expect. There is no workaround available yet. Refer Annoying and important Warnings.

How to build the filter

Preparations

You need some header files and their corresponding libraries. On my system, the following packages need to be installed:

  • libcups2
  • libcups2-dev
  • cups-filters-core-drivers
  • libcupsfilters1 (on demand for the tool cupsfilter)

Especially the filters pdftopdf and pdftoraster should be in place, in order to get the required filter chain to print on QL printers.

Building

configure && make && sudo make install

The filter rastertoql should now be installed to a directory like /usr/lib/cups/filter next to the other filters like pdftopdf and pdftoraster and the PPD files to a directory like /usr/share/cups/model.

How to use the filter

You should now be able to create a new printer and register its corresponding PPD file. CUPS will create a so called filter chain to convert your document into the required printer data format.

Manual Testing

For testing purposes you can build this chain manually like:

$ PPD=ql800.ppd cat <mypdf> | pdftopdf 1 x x 1 "PageSize=DK2251 ColorModel=RGB" |
   pdftoraster 1 x x 1 "PageSize=DK2251 ColorModel=RGB" |
   rastertoql 1 x x 1 "PageSize=DK2251 ColorModel=RGB" > /dev/usb/lp0
Note
In this example the full path to the filters is omitted. You need to add it, if you try it this way.
For all filters in this chain, the PageSize and ColorModel parameter must be the same.
The values of the first four parameters for each filter are not important in this example.

What does it mean? pdftopdf, pdftoraster and rastertoql are so called filters: they accept individual data formats and convert them into a different one.

  • the filter pdftopdf rotates your labels on demand to fit the used DK roll label orientation
  • the filter pdftoraster converts a PDF input format to the CUPS raster output format
  • the filter rastertoql converts the CUPS raster input format to the QL printer data output format

You can refer Trouble shooting as well for a detailed description how to use these filters for testing or debugging purposes.

How to define labels

Continuous Labels

Continuous labels are simple to create: Just create a label with the exact size of your continuous roll paper. E.g. with its exact width.

Attention
The length of your label must be shorter than some hard limits the printer has. All I know yet is, you should not exceed a length of 1000 mm per single label (or: between cuts).
There is also a minimal limit for the length of your label: it is about 13 mm or 25 mm (depending on the QL model. Read the manual of your printer!).

The margin at the left and right borders you should not print to, are about 0.5 mm. There are no margin requirements at the top and bottom borders.

Attention
The printer will always add 3 mm at the top and bottom to your label. Then it will cut the roll.

Example:

You are using a DK2113 roll. It provides a medium width of 62 mm. You define a label with 62 mm width and 100 mm length.

Some label defined on a continuous medium

Your printable area on this label is 61 mm wide and has a length of 100 mm.

The size of this label after the printer has spit it out is 62 mm wide and has a length of 106 mm.

Pre-cut Labels

Pre-cut labels are a bit more complicated. The printers have some annoying behaviours, which we must honor to get an expected result.

First we must create a label of the exact size of the pre-cut labels of our DK roll. Since the printer adds some margins by itself, we now need to define exact margins. We need to know, the printer will always add 3 mm at the top and the bottom of each label. So it depends on the orientation of our label, where we need to honor these margins.

If we use a pre-cut label DK roll oriented in portrait, the 3 mm margins are at the short edges. For DK rolls oriented in landscape, the 3mm margins are at their long edges.

Some kind of labels in portrait orientation (left) and landscape orientation (right)

The margins at the other edges are about 0.5 mm (drop me a note, if this isn't always true). But refer Assumptions about the Print Head for more details.

With this rule it should be easy to define the correct margins, independently of your label's orientation.

You may also read the How the Filter deals with margins.

Example:

You are using a DK1201 roll. It provides pre-cut labels of the size 29 mm by 90 mm. Orientation on the roll is portrait. Thus, you need the 3 mm margins at the 29 mm edge.

Landscape label, but printed in portrait orientation

You can create a label in landscape (29 mm height, 90 mm width), with 3 mm margins at its left and right edge and 0.5 mm at its top and bottom edge. But regarding the top and bottom margins also refer Assumptions about the Print Head for more details.

Wrong Size for a pre-cut Label

What happens, if you create a larger label than the pre-cut label is? The printer won't be able to cut inbetween labels! It will cut inside the next label instead.

Wrong cut due to wrong vertical size

After that is happen, you must manually remove this remaining label, else the printer can no longer feed it correctly.
Solution: Pull out the DK roll from the printer and manually cut the tape at the intended position, and insert it into the printer again.

Where are the margins?

Here a more specific description how to setup the margins if you want to use labels in landscape orientation, but the DK roll provides only portrait orientation.

Landscape label margins on clockwise or counter clockwise rotation
Note
The words Plus90 and Minus90 can be found in the PPD. They are used by the filter pdftopdf to know how to rotate the PDF if the defined orientation doesn't fit the print orientation. By defining this hint, you can rely on it, when defining your label and its margins.

Bi-coloured print

With the QL8xx printer models and the special DK roll DK2251 a nice feature came in - bi-colour print: black and red dots on white paper.

A friend's comment :-)

In order to print in this mode you need:

  • one of the QL8xx printer models
  • the DK2251 62 mm continous label roll
  • documents which makes use of the red and black colours (refer What's red?)
  • switching to the RGB colour space when printing (monochrome is the default else)
  • don't use the 600 DPI print resolution (doesn't work in conjunction with bi-colour)

Limitations in bi-colour print

Bi-colour print mode ins't perfect. See what you can expect.

First how it looks like with black-only capable label. This image shows a DK1201 roll print:

Black on DK1201

The bi-colour DK2251 roll turns to red when the print head applies a low energy to it and still turns to black with high energy.

Since two temperatures (low and high energy) are used to create dots on this special medium, there are some interferences: using high energy (or high temperature) will cool down around the location the high energy was applied to. As a result, the area around a black dot turns to red as well: around all black areas will be some kind of red shadows.

This image shows a DK2251 bi-colour roll with a black area:

Black on DK2251

Vice versa: applying low energy seems not perfect and results in red areas with some black noise in it.

This image shows a DK2251 bi-colour roll with a red area:

Red on DK2251

If you can live with these imperfections, the DK2251 roll is a nice "add-on" for label printing.

What's red?

In order to print bi-coloured, the printer filter needs to separate black and red areas in your document. And it isn't as such easy to detect a red as it seems at first.

Red from the printer filter's point of view, has in the HSV colour model (https://en.wikipedia.org/wiki/HSL_and_HSV) a:

  • hue below 30 ° or above 350 °
  • saturation above 32
  • value above 32
Note
All these thresholds you can change in the PPD belonging to your printer (if it is one of the QL8xx models).

The corresponding settings in the PPD are:

  *qlprinter lower_red_angle: "30"
  *qlprinter higher_red_angle: "350"
  *qlprinter lower_red_saturation: "32"
  *qlprinter lower_red_value: "32"

If you change them, they will be used on the next run of the filter.

Power Saving

At least the QL8 series of printers have some kind of power save features.

Todo:
Please drop me a note, if you know other QL printers which provide this feature as well.

Auto Power Off

When the printer is idle for a while, it switches itself off and disappears from your host's USB.

It is a little bit annoying, since this is called a power save feature. While it is correct (it really saves power!), the printer is silently gone from your host system. You cannot print anymore until you manually switch it on again through its power button.

You can change/adapt this behaviour via a selection from the PPD's Power Off Timeout menu.

You can select a time between 10 minutes and up to 60 minutes (in steps of 10 minutes) in idle after it powers off. And it is possible to disable this feature entirely here as well.

Note
Once set, the printer persists this setting and thus, there is no further need to set it again and again. But: to change the setting you need to print a job.

Auto Power On

Powering the device can lead to an active printer device or a still disabled printer device. Active means, the printer is visible at your host's USB immediately. Still disabled means, it is invisible at the USB and requires an additionally and manually triggered power-on by its local power button.

You can change/adapt this behaviour via a selection from the PPD's Power Connect Behaviour menu.

You can select Default (e.g. don't change), Go online (e.g. active) or Keep offline (e.g. disabled).

Note
Once set, the printer persists this setting and thus, there is no further need to set it again and again. But: to change the setting you need to print a job.

Trouble Shooting

Converter Chains

This section should help to isolate the source of trouble. Trouble here means the printing result isn't the expected one.

CUPS uses a chain of filters to convert a to be printed document into the data the printer device requires. In order to print a portable document format (PDF) the following filter chain could be used:

or

Each filter touches the document somehow. So, if the print result isn't the expected one, we need to examine what happens to the document at which filter.

List the used converter chain

The used filters are a result of some configurations and availability of filter programs. To see, what will be used to print a PDF one can run the cupsfilter tool:

Generic call:

$ cupsfilter -p <some ppd file> -o <some printing params> -m printer/foo -e --list-filters <pdf file>
Note
The cupsfilter tool is part of the cups package
In the following examples the file test/DK1209.pdf is used, which is part of the package.
The DK1209 roll provides portrait orientation pre-cut labels of the size 29 mm x 62 mm. And the same document would perfectly fit in landscape orientation to a DK2251 roll with an endless label of a width of 62 mm. But see below what happens...

Example:

$ cupsfilter -p ql800.ppd -m printer/foo --list-filters -e  ~/example.pdf
pdftopdf
pdftoraster
rastertoql

Selection of filters

Why these filters are used or how they are selected?

The document to print has a MIME type of:

$ file --mime-type --brief test/DK1209.pdf
application/pdf

Now we can take a look into the configuration files in /usr/share/cups/mime and into the used PPD file. In the PPD file we can find the data MIME type, the printer converter expects. In our rastertoql it is application/vnd.cups-raster. If we grep for this string in /usr/share/cups/mime it lists (at least on my host) the filters mupdftoraster, gstoraster and pdftoraster capable to produce this MIME type.
On the other hand all of these filters accept the MIME type application/vnd.cups-pdf as their input. Since they all do the same job, the cost value selects one of these (the lowest cost wins) - in my case pdftoraster.
But there is still a missing link from the input document's type application/pdf to the required MIME type application/vnd.cups-pdf. If we now grep for application/pdf we find pdftopdf for exact this conversion. So, now the chain is complete:

A real example

Lets print a so called small adress label of the size 62 mm x 29 mm. We can find the corresponding PDF in test/DK1209.pdf. We can print it on various DK rolls:

  • DK1209: 29 mm x 62 mm portrait oriented pre-cut labels
  • DK11209: 62 mm x 29 mm landscale oriented pre-cut labels
  • DK2211: 29 mm endless label
  • DK2606: 62 mm endless label
  • DK2251: 62 mm endless label, bi-colour

In the following example, I tried it with the DK2251 roll.

With the tool cupsfilter we can now use the full chain to get the printer data, or we can stop earlier to get the data of each single filter to examine it. pdfinfo is a nice tool to examine one of the conversion results (in this case the PDF related MIMEs):

$ pdfinfo test/DK1209.pdf
Creator:        Writer
Producer:       LibreOffice 7.0
CreationDate:   Tue Nov  2 08:37:14 2021 CET
Tagged:         no
UserProperties: no
Suspects:       no
Form:           none
JavaScript:     no
Pages:          1
Encrypted:      no
Page size:      175.748 x 82.2047 pts
Page rot:       0
File size:      13630 bytes
Optimized:      no
PDF version:    1.6

The important information for us here are the "Page size" and "Page rot" lines.

To get the result of the pdftopdf filter we stop at the application/vnd.cups-pdf MIME type:

$ cupsfilter -p ql800.ppd -o "PageSize=DK2251" -m application/vnd.cups-pdf test/DK1209.pdf > processed.pdf
$ pdfinfo processed.pdf
[…]
Page size:      175.748 x 82.2047 pts
Page rot:       90
[…]

As we can see, "Page rot" is now 90 ° which means pdftopdf has rotated this landscape document into portrait mode. This for example is wrong, since the document fits perfectly onto the DK2251 label roll.

Note
pdftopdf uses the format of the specified roll to guess its orientation. And an endless label always seems like a portrait orientation for this filter. That's why it rotates our test document.

Lets have a look to the next filter stage. This time we stop at the application/vnd.cups-raster MIME type:

$ cupsfilter -p ql800.ppd -o "PageSize=DK2251" -m application/vnd.cups-raster test/DK1209.pdf > raster.raw

In this case the simple file tool gives us the information we need.

$ file raster.raw
raster.raw: Cups Raster version 3, Little Endian, 300x300 dpi, 343x732 pixels 8 bits/color 8 bits/pixel ColorOrder=Chunky ColorSpace=gray

Here we can see, the raster has a size of 343x732 pixels and thus, is in portrait orientation.

And with the full filter chain, rastertoql provides the remaining information about the raster.

$ cupsfilter -p ql800.ppd -o "PageSize=DK2251" -m printer/foo -e test/DK1209.pdf > printer.data
[…]
DEBUG: Page size requested: DK2251
DEBUG: Use settings from roll 'DK2251'
DEBUG: (cups-rastertoql:ql_dk_information_get:286) Inherit settings from roll 'full_size_large_margin'
DEBUG: Continuous length label medium detected.
DEBUG: Bi-colour capable medium detected.
DEBUG: Left hardware margin: 2.0 mm.
DEBUG: mediaBox = [ 0.000000 0.000000 175.748031 82.204724 ]; rotate = 90
DEBUG: size = DK1209
WARNING: 'pdftoraster' has guessed a bad page format. Your print will fail somehow
WARNING: requested print page is: 'DK2251', but the CUPS raster is made for: 'DK1209'
DEBUG: cupsInteger0 (1684302196) value ignored, yet
DEBUG: Intended print size: 28.9 mm (82 pts) x 62.1 mm (176 pts)
DEBUG: Monochrome raster detected
DEBUG: PPD reported page size is: 175.7 points x 2834.6 points
DEBUG: (cups-rastertoql:ql_input_raster_crop:386) Raster width: 343 dots, raster height: 732 dots
DEBUG: (cups-rastertoql:ql_input_raster_crop:387) Media width: 732 dots, media height: 11811 dots
DEBUG: (cups-rastertoql:ql_input_raster_crop:429) Left skip: 0 dots, left_keep: 343 dots
DEBUG: (cups-rastertoql:ql_input_raster_crop:430) Top skip: 0 dots, top_keep: 732 dots
DEBUG2: (cups-rastertoql:cups_ql_monochome_page_print:208) Entering monochrome page print
INFO: pdftoraster (PID 187309) exited with no errors.
DEBUG2: (cups-rastertoql:cups_ql_monochome_page_print:274) Monochrome page print done
[…]

We can see here, we requested for DK2251 roll, but the filter stage for application/vnd.cups-raster generation decided to change it. The print will fail or at least we get a result we don't expect (which also means it has failed).

Some suggestions:

  • the printing parameter pdfAutoRotate=off prevents pdftopdf doing annoying rotations.
  • deteting the currently not used roll definitions from the PPD file prevents pdftoraster from accidently guessing a different roll and adapting the print to it
  • if you don't want to touch the PPD but print on endless labels, avoid label formats which are also available as pre-cut labels.
  • define a different pre-cut roll type of the same size as a printing parameter when printing on endless labels. Use one, which has the same orientation. In our landscape oriented example test/DK1209.pdf to print in landscape orientation use the DK11209 instead of the really loaded DK2251 for example (the latter one will not work, if you want to print in bi-colour mode, since only the DK2251 roll has this feature and the rastertoql filter will check for it to switch to a different data format on request).

Messages

Error Message

Here a list:

  • Internal failure: unsupported bi-colour/device setup detected
  • Internal failure: unsupported bi-colour/medium setup detected
  • Internal failure: unsupported bi-colour/resolution setup detected
  • Failed to read next line of data from the CUPS raster file
  • Internal failure. Roll '<some name>' points to non existing roll '<some other name>'
  • Unkown half tone type: <some number>. Cannot continue.

Internal failures, should not happen, but could, due to programming errors.

  • Input raster expected as 8 bit grey format, but it is: <some number> bit. Cannot continue
  • Printer cannot print in bi-colour mode
  • Request to print in bi-colour mode, but the medium isn't capable doing so.
  • Unsupported raster colour format detected. Check your printer's setup.
  • *'Halftone' with invalid setting found: '<some string>'. Fix your PPD*
  • Missing 'cupsModelNumber' attribute in PPD, e.g. undefined printer model number. Cannot continue.
  • String number exceeds the expected length
  • *Numerical value expected - but found illegal value: '<some string>'
  • *Invalid '<some string>' number found
  • Out of signed integer range number '<some string>' found

Should not happen if the PPD is correct. Did you manually modify it?

  • ERROR: PPD file not defined. Cannot continue

The PPD environment variable isn't defined. This variable contains the filename of the to be used PPD file. Should not happen, except you run the filter manually (for test purposes) and leave this variable undefined.

  • The PPD file '<some PPD filename>' could not be opened

Sorry, don't know the reason. CUPS doesn't return it. Maybe the file does not exists? Missing permissions?

  • Failed to open raster input data file: <some error reason>

The filter tried to open a given file (7th command line parameter) for reading and failed.

  • Failed to open raster input data

It seems the input into the filter isn't in CUPS raster format.

  • Out of memory while allocating the sliding line buffers

No hope!

  • smul overflow with (<number> x <number>)
  • sadd overflow with (<number> x <number>)

Should really not happen. Drop me a note, if it happens at your side.

Real Warnings

  • Crop input raster to fit to <some words>

Your label's width does not fit to the printers capability. The filter crops your input data to be able to print it.

  • Missing internal definition for roll type '<some name>'. Expect the print will fail somehow.

Your DK roll is yet unknown. It seems you modified the PPD manually, but forget to add this new DK roll and its definition to the filter as well. Refer rolls for the addition.

  • *'Halftone' setting not found in PPD. Fix it!*
  • Missing 'ColorDevice' attribute in PPD. Continue as monochrome device!
  • *Value for <some name>/<some name> isn't a valid numerical value: '<some string>'

Should not happen if the PPD is correct. Did you manually modify it?

Annoying Warnings

If you see one of these warnings (or all of them) please drop me a note, how you did print your label, e.g. what print parmeter settings are you used.

  • Raster lenght is undefined. Expect the print fails
  • Duplex flag ignored
  • Collate flag ignored
  • Jog (<some number>) flag ignored
  • ManualFeed flag ignored
  • MirrorPrint flag ignored
  • NegativePrint flag ignored
  • NumCopies (<some number>) ignored
  • Orientation (<some number>) flag ignored
  • OutputFaceUp flag ignored
  • Separations flag ignored
  • TraySwitch flag ignored
  • Tumble flag ignored
  • CutMedia (<some number>) flag ignored, yet
  • LeadingEdge (<some number>) flag ignored, yet
  • AdvanceDistance (<some number>) value ignored, yet
  • AdvanceMedia (<some number>) flag ignored, yet

Annoying and important Warnings

  • pdftoraster has guessed a bad page format. Your print will fail somehow
    requested print page is: '<some name>', but the CUPS raster is made for: '<some different name>'

In this case pdftoraster has decided to use a different page format than you request for. The filter will continue and tries it best. But don't be surprised about the printed result.

Assumptions about the Print Head

  • most models of the QL printers have a print head with exact 720 dots, some (two models?) have more
  • these printers print at 300 DPI in the horizontal direction (fixed)
  • 720 dots at 300 DPI results into a width of 60.96 mm
  • the widest DK roll contains a paper with a width of 62 mm
  • the widest DK roll's transport tape width is 66 mm
Note
The following image implies the print head is centered inside the medium guard area (which isn't perfectly the case).
Guessed Printer Mechanics for Labels with 62 mm in width

If these assumptions are corrent, this implies for pre-cut labels (29 x 90 mm in this example):

Guessed Printer Mechanics for Labels smaller than 62 mm

Result:

  • for continous labels and pre-cut labels with 62 mm width, the left margin is about 0.2 mm and the right margin is about 0.8 mm
  • for continous labels and pre-cut labels smaller than 62 mm width, the right margin is 1.0 mm and really no margin at the left edge
Attention
This difference is important, since the filter pdftopdf will rotate your PDF 90 ° clockwise on demand. Thus you need 1 mm margin at the top of your document and no margin at the bottom (for landscape label -> portrait print). Refer How to setup margins correctly for details.

How does it work?

The printer prints "face down". E.g. you can't see what it prints until it cuts the tape and the label drops out. It always prints from right to left, because all media are inserted right aligned. All DK rolls increase in size to the left. Keep this in mind, when you design your label. The important edge (where everything starts) is the right edge.

Birds view to a QL printer
Attention
Since the printer prints from right to left, the first dot the print head can print on the medium comes with bit 7 in the first byte of line data.