Skip to content
Tres Finocchiaro edited this page Jan 1, 2024 · 33 revisions

Compatibility

  • ✅ 2.2 | ✅ 2.1 | ✅ 2.0* | ⛔ 1.9 | ...

Contents

The following code can be used for raw printing only. If you are unsure what raw printing is, please refer to What is Raw Printing?

Driver Support

  • Dual Mode Driver: Some Windows drivers, (e.g. Zebra's ZDesigner driver, Epson's TM-series driver) will support raw printing alongside pixel-based/PostScript printing. You may use those drivers if available.
  • Raw Only Driver: If your driver doesn't support raw, you must use a dedicated raw-generic/text-only driver to send raw commands, but the generic driver will not be able to print images/PDF/HTML.
  • Bypass Driver: If your driver DOES NOT support raw mode, you may use { forceRaw: true } to bypass the printer driver and send content raw to the device. Prior to 2.2, this was called { altPrinting: true }.

Prerequisites

Languages

Language Aliases

For compatibility with popular languages, often printer manufacturer run language emulation for compatibility with other applications. Below is a comparison chart of language emulations and their respective names. If a direct/raw printing language is not listed, contact us.

Manufacturer ➡️
Language ⬇️
Zebra Epson Datamax
(Honeywell)
Intermec Boca Godex OKI Data TSC Avery / Monarch Citizen SATO Toshiba
Zebra Printing Language ZPL - PL-Z ZSim - EZPL/GZPL ZEBRA ZPL TSPL-EZ MLI - SZPL Z-MODE
Comtec Printer Control Language ✅ CPCL - PL-C/CPCL CSim - - - CPCL - - - -
Eltron Printing Language EPL - PL-E - - GEPL - TSPL-EZ - - SEPL -
Epson Standard Code/POS Edition - ESCPOS ESCP - - - OKI POS ESC-POS - - - -
Datamax Printing Language - - DPL DSim - - - - CLP SDPL -
Intermec Printing Language - - PL-I ✅ IPL - - - - - - SIPL -
Friendly Ghosting Language - - PL-B - ✅ FGL - - - - - - -
IBM Proprinter Command Set - - PL-B - - - OKI Microline - - - - -
SATO Barcode Printer Language - - - - - - - - - - SBPL -
Toshiba TEC Printronix - - - - - - - - - - STCL ✅ TEC

✅ = Official language vendor/name.

Techniques

Advanced

Plain

Generic

Boilerplate code to send raw commands to any printer. See also ZPL, EPL, ESC/POS for specific examples. If your raw language is missing, please contact support.

Note: Reminder to supply <meta content="text/html;charset=utf-8" http-equiv="Content-Type"> if printing Unicode.

Plain Shorthand
var config = qz.configs.create("Printer Name");

var data = [
   'Raw Data\n',
   'More Raw Data\n',
   'Even More Raw Data\n'
   ];

qz.print(config, data).catch(function(e) { console.error(e); });
Plain
var config = qz.configs.create("Printer Name");

var data = [{
     type: 'raw',
     format: 'command',
     flavor: 'plain',
     data: [
        'Raw Data\n',
        'More Raw Data\n',
        'Even More Raw Data\n'
     ]
}];

qz.print(config, data).catch(function(e) { console.error(e); });

Note: The raw commands provided may not work with your printer. Please reference your printer's programming guide for more information.

  • Albeit obvious, each example needs a trigger, such as a button, .e.g.
<input type="button" onclick="printStuff()" value="Print"></input>

ZPL

Example for sending raw ZPL commands to a printer

Note: language: "foo" is only required if providing a raw image type in the data stream. Note: Labels are too small? Try this experimental code to force a 203dpi label to 300dpi.

var config = qz.configs.create("Printer Name");

var data = [
   '^XA\n',
   '^FO50,50^ADN,36,20^FDPRINTED USING QZ TRAY PLUGIN\n',
   { 
    type: 'raw', format: 'image', flavor: 'file', data: 'assets/img/image_sample_bw.png', 
    options: { language: "ZPL" }
   }, 
   '^FS\n',
   '^XZ\n'
   ];

qz.print(config, data).catch(function(e) { console.error(e); });

EPL

Example for sending EPL commands to a printer.

Note: language: "foo" is only required if providing a raw image type in the data stream.

var config = qz.configs.create("Printer Name");
   
var data = [
   '\nN\n',
   { 
    type: 'raw', format: 'image', flavor: 'file', data: 'assets/img/image_sample_bw.png', 
    options: { language: "EPL", x: 20, y: 0 } 
   },
   '\nP1,1\n'
   ];

qz.print(config, data).catch(function(e) { console.error(e); });

ESC/POS

var config = qz.configs.create("Printer Name");

var data = [
   { type: 'raw', format: 'image', flavor: 'file', data: 'assets/img/image_sample_bw.png', options: { language: "ESCPOS", dotDensity: 'double' } },
   '\x1B' + '\x40',          // init
   '\x1B' + '\x61' + '\x31', // center align
   'Canastota, NY  13032' + '\x0A',
   '\x0A',                   // line break
   'http://qz.io' + '\x0A',     // text and line break
   '\x0A',                   // line break
   '\x0A',                   // line break
   'May 18, 2016 10:30 AM' + '\x0A',
   '\x0A',                   // line break
   '\x0A',                   // line break    
   '\x0A',
   'Transaction # 123456 Register: 3' + '\x0A',
   '\x0A',
   '\x0A',
   '\x0A',
   '\x1B' + '\x61' + '\x30', // left align
   'Baklava (Qty 4)       9.00' + '\x1B' + '\x74' + '\x13' + '\xAA', //print special char symbol after numeric
   '\x0A',
   'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' + '\x0A',       
   '\x1B' + '\x45' + '\x0D', // bold on
   'Here\'s some bold text!',
   '\x1B' + '\x45' + '\x0A', // bold off
   '\x0A' + '\x0A',
   '\x1B' + '\x61' + '\x32', // right align
   '\x1B' + '\x21' + '\x30', // em mode on
   'DRINK ME',
   '\x1B' + '\x21' + '\x0A' + '\x1B' + '\x45' + '\x0A', // em mode off
   '\x0A' + '\x0A',
   '\x1B' + '\x61' + '\x30', // left align
   '------------------------------------------' + '\x0A',
   '\x1B' + '\x4D' + '\x31', // small text
   'EAT ME' + '\x0A',
   '\x1B' + '\x4D' + '\x30', // normal text
   '------------------------------------------' + '\x0A',
   'normal text',
   '\x1B' + '\x61' + '\x30', // left align
   '\x0A' + '\x0A' + '\x0A' + '\x0A' + '\x0A' + '\x0A' + '\x0A',
   '\x1B' + '\x69',          // cut paper (old syntax)
// '\x1D' + '\x56'  + '\x00' // full cut (new syntax)
// '\x1D' + '\x56'  + '\x30' // full cut (new syntax)
// '\x1D' + '\x56'  + '\x01' // partial cut (new syntax)
// '\x1D' + '\x56'  + '\x31' // partial cut (new syntax)
   '\x10' + '\x14' + '\x01' + '\x00' + '\x05',  // Generate Pulse to kick-out cash drawer**
                                                // **for legacy drawer cable CD-005A.  Research before using.
// Star TSP100-series kick-out ONLY
// '\x1B' + '\x70' + '\x00' /* drawer 1 */ + '\xC8' + '\xC8' + '\x1B' + '\x1F' + '\x70' + '\x03' + '\x00',
// '\x1B' + '\x70' + '\x01' /* drawer 2 */ + '\xC8' + '\xC8' + '\x1B' + '\x1F' + '\x70' + '\x03' + '\x00',
   ];

qz.print(config, data).catch(function(e) { console.error(e); });

ESC/POS Barcode

//barcode data
var code = '12345';

//convenience method
var chr = function(n) { return String.fromCharCode(n); };

var barcode = '\x1D' + 'h' + chr(80) +   //barcode height
    '\x1D' + 'f' + chr(0) +              //font for printed number
    '\x1D' + 'k' + chr(69) + chr(code.length) + code + chr(0); //code39

qz.websocket.connect().then(function() {
   var config = qz.configs.create("Epson TM88V");
   return qz.print(config, ['\n\n\n\n\n' + barcode + '\n\n\n\n\n']);
}).catch(function(err) { alert(err); });

ESC/POS QR Code

⚠️ Important: The default UTF8 encoding can corrupt QR codes, 'ISO-8859-1' is recommended instead. See #484, #155 for details. Also, if using macOS or Linux, { altPrinting : true } may be required, see #415 for details.

var config = qz.configs.create("Epson TM88V", { encoding: 'ISO-8859-1' });

// The QR data
var qr = 'https://qz.io';

// The dot size of the QR code
var dots = '\x09';

// Some proprietary size calculation
var qrLength = qr.length + 3;
var size1 =  String.fromCharCode(qrLength % 256);
var size0 = String.fromCharCode(Math.floor(qrLength / 256));
        
var data = [ 
   '\x1B' + '\x40' + 'John Doe' +'\x0A' + '\x0A' + '\x0A' + '\x0A' + '\x0A' + '\x0A', // Some text and a few line feeds to make sure the initiation and first line are coming through

   // <!-- BEGIN QR DATA -->
   '\x1D' + '\x28' + '\x6B' + '\x04' + '\x00' + '\x31' + '\x41' + '\x32' + '\x00',    // <Function 165> select the model (model 2 is widely supported)
   '\x1D' + '\x28' + '\x6B' + '\x03' + '\x00' + '\x31' + '\x43' + dots,               // <Function 167> set the size of the module
   '\x1D' + '\x28' + '\x6B' + '\x03' + '\x00' + '\x31' + '\x45' + '\x30',             // <Function 169> select level of error correction (48,49,50,51) printer-dependent
   '\x1D' + '\x28' + '\x6B' + size1 + size0 + '\x31' + '\x50' + '\x30' + qr,          // <Function 080> send your data (testing 123) to the image storage area in the printer
   '\x1D' + '\x28' + '\x6B' + '\x03' + '\x00' + '\x31' + '\x51' +'\x30',              // <Function 081> print the symbol data in the symbol storage area
   '\x1D' + '\x28' + '\x6B' + '\x03' + '\x00' + '\x31' + '\x52' +'\x30',              // <Function 082> Transmit the size information of the symbol data in the symbol storage area
   // <!-- END QR DATA -->

   'New York, NY' + '\x0A' + '\x0A' + '\x0A' + '\x0A' + '\x0A' + '\x0A'               // more line feeds and text to see if we messed up the QR Code syntax      
   ];

qz.print(config, data).catch(function(e) { console.error(e); });

ESC/P

This language is slightly different from ESC/POS, and intended for label printers like the Brother QL 820NWB or dot matrix printers like the Epson LX300

var config = qz.configs.create("Printer Name");

var data = [
    '\x1B' + '\x69' + '\x61' + '\x00' + '\x1B' + '\x40', // set printer to ESC/P mode and clear memory buffer
    '\x1B' + '\x69' + '\x4C' + '\x01', // set landscape mode
    '\x1B' + '\x55' + '\x02', '\x1B' + '\x33' + '\x0F', // set margin (02) and line feed (0F) values
    '\x1B' + '\x6B' + '\x0B' + '\x1B' + '\x58' + '\x00' + '\x3A' + '\x00', // set font and font size 
    'Printed by ', // "Printed by "
    'QZ-Tray', // "QZ-Tray"
    '\x0A' +'\x0A',// line feed 2 times
    '\x1B' + '\x69' + '\x74' + '\x30', // set to code39 barcode
    '\x72' + '\x31', // characters below barcode
    '\x65' + '\x30' + '\x68' + '\x65' + '\x00' + '\x77' +'\x34' + '\x7A' + '\x32', // parentheses y/n, height, width of barcode, 2:1 ratio wide to narrow bars
    '\x42' + '1234567890' + '\x5C', // begin barcode data, data, end barcode data
    '\x0A' + '\x0A', // line feed 2x
    '\x0C' // <--- Tells the printer to print 
    ];

qz.print(config, data).catch(function(e) { console.error(e); });

Evolis

Evolis Image

Example for sending 648 x 1016 pixels of graphic data to an Evolis printer. Take special note of precision: 128, which is 128 color precision (the highest) and overlay: true which will use the clear overlay film after printing as a light protective coating.

This technique can be combined with magnetic encoding and text printing.

var config = qz.configs.create('Evolis');

var data = [
   '\x1BPps;0\x0D',   // Enable raw/disable driver printer parameter supervision
   '\x1BPwr;0\x0D',   // Landscape (zero degree) orientation
   '\x1BWcb;k;0\x0D', // Clear card memory
   '\x1BSs\x0D',      // Start of sequence
   {
      type: 'raw', format: 'image', flavor: 'file', data: 'assets/img/fade-test.png',
      options: { language: "EVOLIS", precision: 128, overlay: true }
   }
   '\x1BSe\x0D'       // End of sequence
   ];

qz.print(config, data).catch(function(err) { alert(err); });

Evolis Overlay

If available, the overlay is a light protective coating that is applied by clear film of the print ribbon. In special cases, such as dual-sided printing, the overlay may need to be finely controlled (e.g. avoiding the magnetic stripe on the back side of the card). Take special note of overlay: overlay in code example.

Overlay can be the path to an image (black pixels will print as overlay) or can be a series of coordinates.

var config = qz.configs.create('Evolis');

// Technique 1 - Use rectangles to draw overlay

// Supplied rectangle will print as overlay
// Typical mag-stripe provided as example
var overlay = [
   [0, 0, 439, 1016],
   [588, 0, 648, 1016]
   // or if rotated 180 degrees
   // [0, 0, 60, 1016],
   // [209, 0, 648, 1016]
   ];

// Technique 2 - Use black pixels in 648 x 1016 image to draw overlay

// Black pixels will print as overlay
// var overlay = 'path/to/overlay.png';

var data = [
   '\x1BPps;0\x0D',   // Enable raw/disable driver printer parameter supervision
   '\x1BPwr;0\x0D',   // Landscape (zero degree) orientation
   '\x1BWcb;k;0\x0D', // Clear card memory
   '\x1BSs\x0D',      // Start of sequence

   // Overlay provided with image command
   {
      type: 'raw', format: 'image', flavor: 'file', data: 'assets/img/fade-test.png',
      options: { language: "EVOLIS", precision: 128, overlay: overlay }
    },
   '\x1BSe\x0D'       // End of sequence
   ];

qz.print(config, data).catch(function(err) { alert(err); });

Evolis Text

Draws the given monochrome text at the specified coordinates and font style.

Note: If combining with image printing, this should generally come after the image commands.

var config = qz.configs.create('Evolis');

var data = [
   // Wt = Monochrome text in bitmap
   // 50 = X Position
   // 60 = Y Position
   // 0  = Font Type.  0 = Arial Normal 100 dots, 1 = Arial Bold 100 dots
   // <text>
   '\x1B' + 'Wt;50;60;0;30;Printed using QZ Tray' + '\x0D',
   '\x1BSe\x0D'       // End of sequence
   ];

qz.print(config, data).catch(function(err) { alert(err); });

Evolis Magnetic Stripe

Magnetic stripe encoding is available through the Ss and Dm;<track>;<data> commands. This technique can be combined with image printing and text printing

var config = qz.configs.create('Evolis');

// Magnetic Encoding example
var data = [
   '\x1BPps;0\x0D',                    // Enable raw/disable driver printer parameter supervision
   '\x1BWcb;k;0\x0D',                  // Clear card memory
   '\x1BSs\x0D',                       // Start of sequence

    // Download magnetic track data using ISO 7811
   '\x1B' + 'Pps;0' + '\x0D',          // Enable raw/disable driver printer parameter supervision
// '\x1B' + 'Pmc;h' + '\x0D',          // Enable high coercivity
// '\x1B' + 'Pmc;l' + '\x0D',          // Enable low coercivity
   '\x1B' + 'Ss' + '\x0D'              // Start recording and clear the current magnetic buffer
   '\x1B' + 'Dm;1;foo' + '\x0D',       // Track 1 = Alpha (ASCII Range 20 - 95) Len: 79 (including start/stop/lrc)
   '\x1B' + 'Dm;2;12345' + '\x0D',     // Track 2 = Numeric, Len 40 (including start/stop/lrc)
   '\x1B' + 'Dm;3;67890' + '\x0D',     // Track 3 = Numeric, Len 107 (including start/stop/lrc)
   '\x1B' + 'Smw' + '\x0D'             // Write the magnetic data aka "Sequence write magnetic track"

   '\x1BSe\x0D'                        // End of sequence
   ];

qz.print(config, data).catch(function(err) { alert(err); });

Evolis Manual Flip

Manual card flipping is done by telling the printer where to insert and where to output the card using Pcim and Pcem commands respectively. Remember when printing overlay ribbon to a magnetic strip or chip area to use the evolis overlay mask area.

var config = qz.configs.create('Evolis');

// Manual flip example
var data = [

   // Front side
   '\x1BPcim;F\x0D'   // F Position: Feeder insertion
   '\x1BPcem;M\x0D'   // M Position: Manual ejection
   '\x1BSs\x0D',      // Start of sequence
// ... etc
   '\x1BSe\x0D'       // End of sequence

   // Back side
   '\x1BPcim;M\x0D',  // M Position: Manual insertion
   '\x1BPcem;D\x0D',  // D Position: Default ejection(output hopper)
   '\x1BSs\x0D',      // Start of sequence
// ... etc
   '\x1BSe\x0D'       // End of sequence

   ];

qz.print(config, data).catch(function(err) { alert(err); });

DPL

DPL Text

var config = qz.configs.create("Printer Name");

var data = [
    '\x02L\n', // Important DPL/CLP must begin with STX (x02) on
    'D11\n',
    'H14\n',
    '121100000300015TEST 1 2 3 4 5 6 7 8 9 10\n',
    'Q0001\n',
    'E\n'
    ];
qz.print(config, data).catch(function(e) { console.error(e); });

DPL Barcode

//barcode data
var code = '1234567890';

var text = 'Hello world';

//convenience method
var chr = function(n) { return String.fromCharCode(n); };

var data = [
   chr(02) + 'n\n',
   ' M0500\n',
   ' KcLW0422;\n',
   ' O0220\n',
   ' d\n',
   ' L\n',
   'D11\n',
   'ySPM\n',
   'A2\n',
   '1911A1200650118' + text +'\n',
   '1eA505401290091C' + code + '\n',
   '1911A1201090155'+ code + '\n',
   'Q0001\n',
   'E\n'
   ];

qz.websocket.connect().then(function() {
   var config = qz.configs.create("I-Class Mark II");
   return qz.print(config, data);
}).catch(function(err) { alert(err); });

SBPL

Example for sending raw SBPL (SATO Barcode Printer Language) commands to a SBPL-compatible printer.

var config = qz.configs.create("Printer Name");

var data = [
   '\x1B' + 'AA1V0250H0340',
   '\x1B' + 'H0020V0015P02RDB@0,026,025,PRINTED USING QZ TRAY',
   '\x1B' + 'H0050V0050',
   { 
      type: 'raw', format: 'image', flavor: 'file', data: 'assets/img/image_sample_bw.png', 
      options: { language: "SBPL" }
   },
   '\x1B' + 'H0030V00195P02RDB@0,026,025,AND SATO SBPL CODE',
   '\x1B' + 'Q1',
   '\x1B' + 'Z'
   ];
qz.print(config, data).catch(function(e) { console.error(e); });

PGL

Example for sending raw PGL (Printronix Graphics Language) commands to a compatible printer (e.g.: T-series Printronix)

var config = qz.configs.create("T8204");

var data = [
    '~CREATE;DATAMATRIX;288',
    'SCALE;DOT;300;300',
    'ALPHA',
    'POINT;50;100;16;9;*Printed using QZ Tray*',
    'STOP',
    'BARCODE',
    'DATAMATRIX;XD16;C20;R20;ECC200;ID5;150;150',
    '*https://qz.io*',
    'STOP',
    'END',
    '~EXECUTE;DATAMATRIX;1',

    '~NORMAL',
    ];
qz.print(config, data).catch(function(e) { console.error(e); });

FGL

Example for sending raw FGL (BOCA Friendly Ghost Language) commands to a FGL-compatible printer.

var config = qz.configs.create("Lemur");

var data = [
    "<n><DA><RL><RC300,20><F12>BOCA <F6><RC100,40>",
    "<NR><RC290,110><RL><F6><HW1,1>PROM=",
    "<RC300,160><RL><HW1,1><VA7><RC370,740><RU>GHOSTWRITER",
    "<RC48,880><RR><F2>FRIENDLY GHOST LANGUAGE",
    "<RC52,862>PLACE LETTERS ANYWHERE",
    "<RC80,1170><F6><RR>VOID",
    "<RC15,1100><F3>TEST TICKET ONLY",
    "<RC8,1010><X2><NXL10>*GHOST 123*<RR>",
    "<RC78,915>  CODE 39",
    "<RU><RC320,740><BS17,30>TICKET & LABEL PRINTER",
    "<NR><F3><RC0,300>EXCELLENT PRINT QUALITY",
    "<NR><RC30,300> Print any bar code",
    "<RC70,300><X2><OL6>^CODE 128^",
    "<RC90,250><RR>CODE 128",
    "<RC96,340><X3><NXP10>*MONKEY*",
    "<RC206,340><X2><NP6>*MONKEY*",
    "<F2><HW1,1><NR><F1><SP180,640><LO1>",
    "<RC371,385><F2><NR>SW1=          SW2=          SW3=<RC371,824>LEFT = 1  RIGHT = 0",
    "<RC385,150><F11>Script printing is now standard.",
    "<RC430,150><F9>High density printing is clear and readable",
    "<RC450,150><F2>High density printing is clear and readable",
    "<RC470,150><F1>Legal size printing",
    "<RC0,100><LT4><VX1200>",
    "<p>"
];

qz.print(config, data).catch(function(e) { console.error(e); });

Base64

With this function, you can send base64 encoded characters/raw commands to qz using "base64". This will automatically convert provided base64 encoded text into text/ascii/bytes, etc.

var config = qz.configs.create("Printer Name");

var data = [
   {
      type: 'raw', format: 'command', flavor: 'base64',
      data: 'Ck4KcTYwOQpRMjAzLDI2CkI1LDI2LDAsMUEsMyw3LDE1MixCLCIxMjM0IgpBMzEwLDI2LDAsMywx' +
         'LDEsTiwiU0tVIDAwMDAwIE1GRyAwMDAwIgpBMzEwLDU2LDAsMywxLDEsTiwiUVogUFJJTlQgQVBQ' +
         'TEVUIgpBMzEwLDg2LDAsMywxLDEsTiwiVEVTVCBQUklOVCBTVUNDRVNTRlVMIgpBMzEwLDExNiww'
   }
];

qz.print(config, data).catch(function(e) { console.error(e); });

Base64 Images

With this function, you can send a base64 encoded image as a portion of a raw command. This will automatically convert provided base64 encoded text into raster graphics appropriate for the specified language, etc.

var config = qz.configs.create("Printer Name");
var data = [
   '^XA\n',
   '^FO50,50^ADN,36,20^FDPRINTED USING QZ TRAY PLUGIN\n',
   {
      type: 'raw', format: 'image', flavor: 'base64',
      data: 'iVBORw0KGgoAAAANSUhEUgAAAH[...]==', 
      options: { language: "ZPL" },
   }
   '^FS\n',
   '^XZ\n'
];

qz.print(config, data).catch(function(e) { console.error(e); });

PDF Printing

Print a PDF directly to a raw printer

EPL
var config = qz.configs.create("Printer Name", { size: { width: 4, height: 6 } } );
var data = [
   '\nN\n',
   'q609\n',
   {
      type: 'raw', format: 'pdf', flavor: 'file',
      data: 'path/to/pdf_sample.pdf',
      options: { language: "EPL" } // , "pageWidth":..., "pageHeight":... },
   }
   '\nP1,1\n'
];

qz.print(config, data).catch(function(e) { console.error(e); });
ZPL
var config = qz.configs.create("Printer Name", { size: { width: 4, height: 6 } } );
var data = [
   '^XA\n',
   {
      type: 'raw', format: 'pdf', flavor: 'file',
      data: 'path/to/pdf_sample.pdf',
      options: { language: "ZPL" } // , "pageWidth":..., "pageHeight":... },
   }
   '^XZ\n'
];

qz.print(config, data).catch(function(e) { console.error(e); });
ESCPOS
var config = qz.configs.create("Printer Name");
var data = [
   {
      type: 'raw', format: 'pdf', flavor: 'file',
      data: 'path/to/pdf_sample.pdf',
      options: { language: "ESCPOS" } //, "pageWidth":..., "pageHeight":... },
   }
];

qz.print(config, data).catch(function(e) { console.error(e); });

HTML Printing

Print HTML content directly to a raw printer

EPL
var config = qz.configs.create("Printer Name", { size: { width: 4, height: 6 } } );
var data = [
   '\nN\n',
   'q609\n',
   {
      type: 'raw', format: 'html', flavor: 'file',
      data: 'path/to/sample.html',
      options: { language: "EPL" } // , "pageWidth": ...  "pageHeight": ... },
   }
   '\nP1,1\n'
];

qz.print(config, data).catch(function(e) { console.error(e); });
ZPL
var config = qz.configs.create("Printer Name", { size: { width: 4, height: 6 } } );
var data = [
   '^XA\n',
   {
      type: 'raw', format: 'html', flavor: 'file',
      data: 'path/to/sample.html',
      options: { language: "ZPL" } //, "pageWidth":..., "pageHeight":... },
   }
   '^XZ\n'
];

qz.print(config, data).catch(function(e) { console.error(e); });
ESCPOS
var config = qz.configs.create("Printer Name");
var data = [
   {
      type: 'raw', format: 'html', flavor: 'file',
      data: 'path/to/sample.html',
      options: { language: "ESCPOS" } //, "pageWidth": ..., "pageHeight": ... },
   }
];

qz.print(config, data).catch(function(e) { console.error(e); });

File

This feature allows a raw file to be spooled directly to the printer.

var config = qz.configs.create("Printer Name");

var data = [
   {
     type: 'raw', format: 'command', flavor: 'file', data: 'assets/raw-data.txt'
   }
];
  
qz.print(config, data).catch(function(e) { console.error(e); });

XML

The ability to read the contents of an XML file containing Base64 encoded commands and send these commands to the printer.

var config = qz.configs.create("Printer Name");

var data = [
   {
     type: 'raw', format: 'command', flavor: 'xml', data: 'assets/zpl_sample.xml', 
     options: { xmlTag: 'v7:Image' }
   }
];

qz.print(config, data).catch(function(e) { console.error(e); });

Host

URL

Print directly to a HTTP host/url (such as a CUPS shared printer, or to a print server device).

var config = qz.configs.create({ host: "192.168.254.254", port: 9100 }); // or http://<cups-server>/printers/<my-printer>

var data = [
   'Raw Data\n',
   'More Raw Data\n',
   'Even More Raw Data\n'
];

qz.print(config, data).catch(function(e) { console.error(e); });

Filesystem

Print to local filesystem

var config = qz.configs.create({ file: "/path/to/output.txt" }); // or "C:\\path\\to\\output.text", etc

var data = [
   'Raw Data\n',
   'More Raw Data\n',
   'Even More Raw Data\n'
];

qz.print(config, data).catch(function(e) { console.error(e); });

Print to Win32 UNC Path

var config = qz.configs.create({ file: "\\\\server\\printer" });

var data = [
   'Raw Data\n',
   'More Raw Data\n',
   'Even More Raw Data\n'
];

qz.print(config, data).catch(function(e) { console.error(e); });

Print to Win32 Device Namespace

Leverage printing API for writing to a Win32 Device Namespace physical device such as a Bematech/Logic Controls Pole Display mapped as \\.\LCLD9

var config = qz.configs.create({ file: "\\\\.\\LCLD9\\dummy" });

var data = [
   '"\r\nMMM... COFFEE! :)\r\n"'
];

qz.print(config, data).catch(function(e) { console.error(e); });

Advanced Print Spooling

Spools jobs between specified end parameter. Useful for avoiding buffer overflows on unusually large quantity print jobs by spooling each raw job individually. Defaults to 1 job per spool, but can be overridden using size option.

// Change end to '^XZ' for ZPL, 'P1\n' for EPL, etc
var config = qz.configs.create("Printer Name", { spool: { end: '\n',  size: 1 } }`);
var data = [
   'First\n',
   'Second\n',
   'Third\n'
];

qz.print(config, data).catch(function(e) { console.error(e); });
}

Note: Prior to qz-tray.js 2.1.3, this was { endOfDoc : '\n', perSpool: 1 } however the API will handle downgrading this to the old syntax automatically.

Special Characters

Hex

var config = qz.configs.create("Printer Name");

var data = [
   //defaults to 'type: raw' and 'format: command'
   { 
    flavor: 'hex', data: 'x1Bx00', // or data: '1B00'
    options: { language: "ZPL" } //or other languages
   }
];

qz.print(config, data).catch(function(e) { console.error(e); });

Decimal

var config = qz.configs.create("Printer Name");

var data = [
   String.fromCharCode(27) + String.fromCharCode(0) // e.g. CHR(27) CHR(0) or Hex x1Bx00
];

qz.print(config, data).catch(function(e) { console.error(e); });
}

Uint8Array

QZ Tray can automatically convert Uint8Array data to BASE64 or HEX formats:

Uint8Array with fetch
// Uint8Array support available since 2.2.3
var config = qz.configs.create("Printer Name");

fetch("https://demo.qz.io/assets/pdf_sample.pdf").then((response) => {
      if (!response.ok) {
        throw new Error(`HTTP error, status = ${response.status}`);
      }
      return response.arrayBuffer();
}).then(buffer => {
    var config = qz.configs.create("PDF");

    var data = [{
      type: 'pixel',
      format: 'pdf',
      flavor: 'base64',
      data: new Uint8Array(buffer)
    }];

    return qz.print(config, data);
});
Uint8Array with Thermal-Printer-Encoder with Node.js
// Uint8Array support available since 2.2.3
let tpe = require('thermal-printer-encoder');
let ws = require('ws');
let qz = require('qz-tray');

let encoder = new tpe({
    language: 'esc-pos'
});

let result = encoder
    .initialize()
    .text('The quick brown fox jumps over the lazy dog')
    .newline()
    .qrcode('https://nielsleenheer.com')
    .encode();

let config = qz.configs.create("Epson TM-T88VI");
let data = [{
    type: 'raw',
    format: 'command',
    flavor: 'hex',
    data: result
}];

qz.api.setWebSocketType(ws);

qz.websocket.connect().then(() => {
    return qz.print(config, data);
}).catch((err) => {
    console.error(err);
});

Code Page

Force Java to use a specific code-page and Raw-Encoding for options.

var config = qz.configs.create("Printer Name", { encoding: 'CP1253' }); // MS-DOS Greek

var data = [
   "Σ β θ"
];

qz.print(config, data).catch(function(e) { console.error(e); });

Combining Techniques

var config = qz.configs.create("Printer Name");

// Example only, not valid ESCPOS
var data = [
   "My Raw Commands",
   String.fromCharCode(27) + String.fromCharCode(0),
   { flavor: 'hex', data: 'x1Bx00' },
   { type: 'raw', format: 'image', flavor: 'file', data: 'assets/img/image_sample_bw.png', options: { language: 'ESCPOS', dotDensity: 'double' } }, 
];

qz.print(config, data).catch(function(e) { console.error(e); });

Copies

A config parameter copies can be provided to send the specified raw commands multiple times. This is a convenience function as most raw languages already have an internal copies command.

var config = qz.configs.create("Printer Name", { copies: 4 });

var data = [
   'Raw Data\n',
   'More Raw Data\n',
   'Even More Raw Data\n'
];

qz.print(config, data).catch(function(e) { console.error(e); });

Custom Job Name

A config parameter jobName can be provided to change the name listed in the print queue.

var config = qz.configs.create("Printer Name", { jobName: "Receipt #123456" });

var data = [
   'Raw Data\n',
   'More Raw Data\n',
   'Even More Raw Data\n'
];

qz.print(config, data).catch(function(e) { console.error(e); });

Force Raw

Alternate Printing

When using CUPS (Linux/Unix/Mac), the printer driver can be bypassed completely by executing a command-line option

⚠️ WARNING: This feature currently has no effect in a Windows environment.

lpr -o raw my-raw-file.txt

This may be useful when troubleshooting issues with non-raw printer drivers. QZ Tray can substitute the standard printing behavior with this technique by adding a config parameter forceRaw. This parameter has no effect in a Windows environment.

var config = qz.configs.create("Printer Name", { forceRaw: true }); // Since 2.2;  2.1 use: { altPrinting: true } instead

var data = [
   'Raw Data\n',
   'More Raw Data\n',
   'Even More Raw Data\n'
];

qz.print(config, data).catch(function(e) { console.error(e); });

Chaining Requests

Print requests can be chained together to print several raw items at once, or to print to several different printers.

var config = qz.configs.create();
var data = [{ type: 'raw', data: null, }];
   
data.data = 'Some Raw Data #1';                    ////// First raw item
config.setPrinter('First Printer');                ////// First printer
qz.print(config, data)
.then(function() {
   data.data = 'Some Raw Data #2';                 ////// Second raw item
   config.setPrinter('Second Printer');            ////// Second printer
   return qz.print(config, data);
})
.then(function() {
   data.data = 'Some Raw Data #3';                 ////// Third raw item
   config.setPrinter('Third Printer');             ////// Third printer
   return qz.print(config, data);
})
.catch(function(e) {
   console.error(e);                // Exceptions throw all the way up the stack
});

Promise Loop

Looping multiple configs and multiple data objects is now built-in to the 2.1 API. More information here.

Filter Printers

As of 2.1, the sift library can be leveraged using qz.printers.details(); to filter the available printer listings. This can be used to exclude types of printers (virtual, raw, etc).

In this example, only raw printers attached to the system will be returned

qz.printers.details().then(function(data) {
  data = sift.keep( data, { type: 'raw' });
  console.log(data);
});

Go to the sift repository for more examples on how the sift library can be utilized.

Clone this wiki locally