CUPS rastertoql filter  1.0.4
Filter for the Brother QL family of label printers
Data Structures | Macros | Enumerations | Functions
qldriver.h File Reference

Data Structures

struct  line_command
 
struct  qlrgb
 
struct  qlhsv
 
struct  halftone_converter
 
struct  ql_trim
 
struct  qldriver
 
struct  dk_roll_types
 
struct  ql_simple_command
 

Macros

#define COLOUR_VAL_DARK   0x00
 
#define COLOUR_VAL_BRIGHT   0xff
 
#define PRINT_DOT_VAL   0x00
 
#define DEFAULT_QL_LINE_SIZE   90
 
#define PRE_CUT_LABEL_MARGIN_SKIP_LOW_RES   35
 
#define PRE_CUT_LABEL_MARGIN_SKIP_HIGH_RES   70
 

Enumerations

enum  printer_type {
  BROTHER_QL_UNKNOWN = 0, BROTHER_QL_500 = 500, BROTHER_QL_550 = 550, BROTHER_QL_560 = 560,
  BROTHER_QL_570 = 570, BROTHER_QL_580 = 580, BROTHER_QL_600 = 600, BROTHER_QL_650 = 650,
  BROTHER_QL_700 = 700, BROTHER_QL_710 = 710, BROTHER_QL_720 = 720, BROTHER_QL_800 = 800,
  BROTHER_QL_810 = 810, BROTHER_QL_820 = 820, BROTHER_QL_1050 = 1050, BROTHER_QL_1060 = 1060
}
 
enum  half_tone { HT_ERROR_DIFFUSION = 1, HT_ORDERED = 2, HT_NONE = 3 }
 
enum  dk_caps { DK_CAP_UNKNOWN = 0, DK_CAP_CONTINUOUS = 1, DK_CAP_DIE_CUT = 2, DK_CAP_RED = 4 }
 

Functions

void sliding_halftone_get (struct halftone_converter *cnv)
 
void sliding_halftone_put (struct halftone_converter *cnv)
 
void halftone_line_no_dither (struct halftone_converter *cnv)
 
void halftone_line_ordered (struct halftone_converter *cnv)
 
void halftone_line_with_error_diffusion (struct halftone_converter *cnv)
 
void move_in_next_line (struct halftone_converter *cnv, const unsigned char raw[cnv->pixel_count])
 
void move_in_empty_line (struct halftone_converter *cnv, signed short val)
 
int cups_ql_driver_init (struct qldriver *ql)
 
int ql_dk_information_get (struct dk_roll_types *medium, const char *name)
 
int cups_ql_job_print (struct qldriver *ql)
 
int cups_ql_colour_page_print (struct qldriver *ql, int first_time)
 
int cups_ql_monochome_page_print (struct qldriver *ql, int first_time)
 
int cups_ql_raster_header_read (struct qldriver *ql)
 
int cups_ql_next_line_read (struct qldriver *ql, size_t sz, unsigned char buf[sz])
 
int ql_printer_data_send (struct qldriver *ql, const void *data, size_t count, int flush)
 
void transform_to_monochrome (size_t input_cnt, const signed short input[input_cnt], unsigned char *data)
 
int ql_reset (struct qldriver *ql)
 
int ql_auto_powerdown (struct qldriver *ql, unsigned short time_out)
 
int ql_auto_powerup (struct qldriver *ql, unsigned short mode)
 
int ql_input_raster_crop (struct qldriver *ql)
 
int ql_raster_limits_get (struct qldriver *ql)
 
int ql_page_header_generate (struct qldriver *ql, int first_time)
 
int ql_job_footer_generate (struct qldriver *ql)
 
int ql_job_header_generate (struct qldriver *ql)
 

Macro Definition Documentation

◆ COLOUR_VAL_BRIGHT

#define COLOUR_VAL_BRIGHT   0xff

Value of white. The maximal value of a byte (regarding the CUPS raster)

◆ COLOUR_VAL_DARK

#define COLOUR_VAL_DARK   0x00

Value of black. The minimal value of a byte (regarding the CUPS raster)

◆ DEFAULT_QL_LINE_SIZE

#define DEFAULT_QL_LINE_SIZE   90

The generic count of bytes of one line of these QL printers

Note
This is valid only for a couple types of these printers. It should be set in the PPD instead.

◆ PRE_CUT_LABEL_MARGIN_SKIP_HIGH_RES

#define PRE_CUT_LABEL_MARGIN_SKIP_HIGH_RES   70

Amount of raster lines to skip at the top and bottom of a pre-cut label. This is a printer device requirement. It more or less defines a margin of 3 mm.
70 lines are valid for 600 DPI

◆ PRE_CUT_LABEL_MARGIN_SKIP_LOW_RES

#define PRE_CUT_LABEL_MARGIN_SKIP_LOW_RES   35

Amount of raster lines to skip at the top and bottom of a pre-cut label. This is a printer device requirement. It more or less defines a margin of 3 mm.
35 lines are valid for 300 DPI

◆ PRINT_DOT_VAL

#define PRINT_DOT_VAL   0x00

The value of a to be printed dot (regarding the internal processing)

Enumeration Type Documentation

◆ dk_caps

enum dk_caps

Capabilities of a DK roll

Enumerator
DK_CAP_UNKNOWN 
DK_CAP_CONTINUOUS 

Continuous length label

DK_CAP_DIE_CUT 

Pre-cut label

DK_CAP_RED 

Bi-colour possible (black/red on white)

◆ half_tone

enum half_tone

Selected half-tone algorithm

Enumerator
HT_ERROR_DIFFUSION 

Floyd-Steinberg error diffusion

HT_ORDERED 

Ordered dithering matrix

HT_NONE 

Just quantize the raster

◆ printer_type

Keep the numbers here in sync with the PPD "cupsModelNumber" entry

Enumerator
BROTHER_QL_UNKNOWN 
BROTHER_QL_500 
BROTHER_QL_550 
BROTHER_QL_560 
BROTHER_QL_570 
BROTHER_QL_580 
BROTHER_QL_600 
BROTHER_QL_650 
BROTHER_QL_700 
BROTHER_QL_710 
BROTHER_QL_720 
BROTHER_QL_800 
BROTHER_QL_810 
BROTHER_QL_820 
BROTHER_QL_1050 
BROTHER_QL_1060 

Function Documentation

◆ cups_ql_colour_page_print()

int cups_ql_colour_page_print ( struct qldriver ql,
int  first_time 
)

Convert the current page into the printer's wire data format

Parameters
[in]qlFull job description
[in]first_time'1' if called the first time of this job, '0' else
Return values
0On success
-EINVALUnsupported raster input format
-ECANCELEDTermination request from outerspace

The routine loops through all or the remaining lines of the current page and converts them into the printer's colour wire format

Precondition
The format was already checked, e.g. it fits into the printer's media.

◆ cups_ql_driver_init()

int cups_ql_driver_init ( struct qldriver ql)

Init required information about the printer device

Parameters
[in]qlFull job description
Return values
0On success (currently always)

◆ cups_ql_job_print()

int cups_ql_job_print ( struct qldriver ql)

CUPS specific document print routine

Parameters
[in]qlFull job description
Return values
0On success
-EINVALUnsupported raster input format

This function prepares the print. E.g. configure the printer according to the given CUPS raster format.

We need to check the raster header in order to have an idea, what has to be printed (monochrome versus bi-colour). We can check the medium size versus the raster size here to be able to print something.

The routine loops through all pages inside the CUPS raster file and calls the corresponding encoding routine to do the job.

Note
On a termination request we rely on the specific encoding function (cups_ql_colour_page_print() or cups_ql_monochome_page_print()) to return with -ECANCELED, because the routine itself knows how to terminate the print at the printer's side as well
Precondition
All pages in the raster file use the same colour format (e.g. no RGB/grey mix)

◆ cups_ql_monochome_page_print()

int cups_ql_monochome_page_print ( struct qldriver ql,
int  first_time 
)

Convert the current page into the printer's wire data format

Parameters
[in]qlFull job description
[in]first_time'1' if called the first time in this job, '0' else
Return values
0On success
-EINVALUnsupported raster input format
-ECANCELEDTermination request from outerspace

The routine loops through all or the remaining lines of the current page and converts them into the printer's monchrome wire format

Note
The ql_trim::top_keep amount of lines of the input raster is printed.
In case of an error or a termination request, the print job gets terminated at the printer's side as well.
Precondition
The format was already checked, e.g. it fits into the printer's media.

◆ cups_ql_next_line_read()

int cups_ql_next_line_read ( struct qldriver ql,
size_t  sz,
unsigned char  buf[sz] 
)

Read in the next line from the CUPS raster

Parameters
[in,out]qlFull job description
[in]szSize of bytes buf points to
[out]bufWhere to store the raster data
Return values
0On success
-ENODATAMature end of CUPS raster input data

◆ cups_ql_raster_header_read()

int cups_ql_raster_header_read ( struct qldriver ql)

Read in the next header from the CUPS raster file

Parameters
[in,out]qlFull job description
Return values
numberHeader bytes read
0on EOF, negative value on failure, 'errno' is valid in this case

◆ halftone_line_no_dither()

void halftone_line_no_dither ( struct halftone_converter cnv)

Quantize the top line without any half tone algorithm

Parameters
[in,out]cnvThe converter structure to use
Returns
The quantized line in halftone_converter::sliding_lines[0]

http://www.visgraf.impa.br/Courses/ip00/proj/Dithering1/average_dithering.html

◆ halftone_line_ordered()

void halftone_line_ordered ( struct halftone_converter cnv)

Quantize the top line according to an "ordered dithering matrix"

Parameters
[in,out]cnvThe converter structure to use
Returns
The quantized line in halftone_converter::sliding_lines[0]

This is a simple algorithm with a 2x2 "ordered dithering matrix":

   | 1/10  3/10 | <-- cnv->sliding_lines[0]
   | 4/10  2/10 | <-- cnv->sliding_lines[1]

http://www.visgraf.impa.br/Courses/ip00/proj/Dithering1/ordered_dithering.html

Precondition
halftone_converter::sliding_lines[0] and halftone_converter::sliding_lines[1] must be valid

◆ halftone_line_with_error_diffusion()

void halftone_line_with_error_diffusion ( struct halftone_converter cnv)

Quantize the top line according to the "Floyd-Steinberg error diffusion" and distribute the error around

Parameters
[in,out]cnvThe converter structure to use
Returns
The quantized line in halftone_converter::sliding_lines[0]

From: http://www.visgraf.impa.br/Courses/ip00/proj/Dithering1/floyd_steinberg_dithering.html

   |  N     *   7/16 | <-- cnv->sliding_lines[0]
   | 3/16  5/16 1/16 | <-- cnv->sliding_lines[1]

N previous pixel, * current pixel to process (e.g. X/Y position)

Precondition
halftone_converter::sliding_lines[0] and halftone_converter::sliding_lines[1] must be valid
At least three pixels must be in the lines

◆ move_in_empty_line()

void move_in_empty_line ( struct halftone_converter cnv,
signed short  val 
)

Move in an empty line into the process

Parameters
[in,out]cnvThe converter structure to use
[in]val'Empty' value (0…255)

'Empty' means val must have a value which should not print anything. For example COLOUR_VAL_BRIGHT.

◆ move_in_next_line()

void move_in_next_line ( struct halftone_converter cnv,
const unsigned char  raw[cnv->pixel_count] 
)

Move in the next line with raw raster data into the process

Parameters
[in,out]cnvThe converter structure to destroy
[in]rawBuffer with raw pixel data (grey scale) in bytes

Throw away the content of the current top line, move all lines below one line up and fill the bottom line with new content from the given raw line.

Currently there are only two lines in the calculation buffer, so "moving" means "swapping" instead.

The byte based pixel data is copied into the sliding half tone structure and gets converted to signed short to be able run the half tone algorithm afterwards.

Note
In order to be able to calculate the bottom line of the image, you need to input an empty line instead. Empty means: it must contain a value, which isn't printed. Refer move_in_empty_line() for details
Precondition
raw must point to a buffer with halftone_converter::pixel_count bytes.

◆ ql_auto_powerdown()

int ql_auto_powerdown ( struct qldriver ql,
unsigned short  time_out 
)

Set the printer's auto power down behaviour if it is idle

Parameters
[in]qlFull job description
[in]time_outTime out when idle to enter power down mode

time_out can be:

  • 0x0000: disable auto power off
  • 0x0001: auto power off after 10 minutes
  • 0x0002: auto power off after 20 minutes
  • 0x0003: auto power off after 30 minutes
  • 0x0004: auto power off after 40 minutes
  • 0x0005: auto power off after 50 minutes
  • 0x0006: auto power off after 60 minutes

If the printer enters the power down mode, it disconnects itself from the USB and can be re-enabled manually only with its local power button. This is a really bad idea for remote printers.

Note
This command is reverse-engineered, it isn't listed in the programming manual
The big endian format for the subcommand's data (here time_val) is guessed only. All other printer commands use little endian for multibyte parameter. So, the command's data might have a different format/content than listed here

◆ ql_auto_powerup()

int ql_auto_powerup ( struct qldriver ql,
unsigned short  mode 
)

Set the printer's power up behaviour when connecting to external power

Parameters
[in]qlFull job description
[in]modePower On mode

mode can be:

  • 0x0000 Keep offline when connecting to external power
  • 0x0001 Go online when connecting to external power
Note
This command is reverse-engineered, it isn't listed in the programming manual
The big endian format for the subcommand's data (here mode) is guessed only. All other commands use little endian for multibyte parameter. So, the command's data might have a different format/content than listed here

◆ ql_dk_information_get()

int ql_dk_information_get ( struct dk_roll_types medium,
const char *  name 
)

Retrieve settings/information about a specific DK roll/cassette

Parameters
[out]mediumThe settings for the DK roll named by name
[in]nameThe DK roll name the settings should be retrieved for
Return values
0On success, *medium is valid
-EINVALRoll with the given name not found

DK rolls can inherit settings from other rolls. This routine walks through the table and uses the dk_roll_types::like member to re-use their settings.

◆ ql_input_raster_crop()

int ql_input_raster_crop ( struct qldriver ql)

Crop the input raster to meet the printer's expectations/requirements

Parameters
[in]qlFull job description

The printer device has some - hmm, lets it call - interesting requirements about the print data it accepts. Continuous labels are easy, but pre-cut labels aren't. In order to ensure the printer always cuts inbetween two pre-cut labels, we need to tweak the amount of lines to be print.

Read How the Filter deals with margins about details.

◆ ql_job_footer_generate()

int ql_job_footer_generate ( struct qldriver ql)

Send the footer commands after a print job

Parameters
[in]qlFull job description
Attention
Do not call in case of a procesing failure. These commands make sense only if the print job was successful.

Called once per print job at the end. But only:

  • if the whole job was successful
  • no termination request was received

◆ ql_job_header_generate()

int ql_job_header_generate ( struct qldriver ql)

Send the heading commands to setup the printer prior a print job

Parameters
[in]qlFull job description

Called once per print job at the beginning

◆ ql_page_header_generate()

int ql_page_header_generate ( struct qldriver ql,
int  first_time 
)
Parameters
[in]qlFull job description
[in]first_timeFlag if called the first time in a print job
Return values
0On success
-ENODEVDevice seems gone (e.g. channel to the next stage is gone)

Called once per page at the beginning

Note
In case of -ENODEV it makes no sense trying to send any further data or commands
Precondition
The qldriver::trim member must be up to data, e.g. its content matches the current raster page header
Todo:

Deal with QL_FAST_PRINT/QL_QUALITY_PRINT for monochrome use case

Do the QL_QUALITY_PRINT and QL_HIGH_RESOLUTION bits depend on each other?

Deal with auto cut setting and when to cut (and if the printer has a cutter). To make it simple: only "cut at end" and "cut each" should be supported

◆ ql_printer_data_send()

int ql_printer_data_send ( struct qldriver ql,
const void *  data,
size_t  count,
int  flush 
)

Send data to the printer's stream

Parameters
[in,out]qlFull job description
[in]dataPointer to the to be sent data
[in]countCount of bytes data points to
[in]flush'1' if the stream should be flushed
Return values
0On success
NegativeERRNO from fwrite() call

◆ ql_raster_limits_get()

int ql_raster_limits_get ( struct qldriver ql)
Precondition
The CUPS raster header info must be valid, e.g. cups_ql_raster_header_read() already called
Note
CUPS specific adaption

◆ ql_reset()

int ql_reset ( struct qldriver ql)

Initialize/reset the printer

Parameters
[in]qlFull job description
Return values
0On success
NegativeError code from the ql_printer_data_send() call

This command can also be used every time to terminate a current print

Note
To be sent once at the beginning of a print job (according to the manual)

◆ sliding_halftone_get()

void sliding_halftone_get ( struct halftone_converter cnv)

Prepare the sliding line buffers

Parameters
[in,out]cnvThe converter structure to initialiaize

In order to run some kind of half-tone processing we need signed values per pixel which must be larger than the incoming pixels data. Incoming pixels are of type 'unsigned char' with their grey values. Due to this conversion we do not need to honor any kind of saturation while calculating the dithered output.

Note
Does not return in case of memory failure
Precondition
halftone_converter::pixel_count must be already set and not '0'

◆ sliding_halftone_put()

void sliding_halftone_put ( struct halftone_converter cnv)

Clean up image processing via sliding line buffers

Parameters
[in,out]cnvThe converter structure to destroy

◆ transform_to_monochrome()

void transform_to_monochrome ( size_t  input_cnt,
const signed short  input[input_cnt],
unsigned char *  data 
)

Convert an array of signed shorts into a monochrome pattern (one signed short into one bit)

Parameters
[in]input_cntCount of pixel in input
[in]inputWhere to get the quantized input data
[out]dataWhere to store the converted output data
Note
Since the printer prints from right to left, each pattern gets mirrored(!) here. First pixel printed (at the right border) is the MSB of the first byte
Precondition
PRINT_DOT_VAL means: print a dot, everything else means: do not print a dot, e.g. the input data must already be quantized