Wiki - 2.0 Raw Printing

Compatibility

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?


Prerequisites

Languages

Techniques

Advanced

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.

function printStuff() {
   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); });
}

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

<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.

function printZPL() {
   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', 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.

function printEPL() {
   var config = qz.configs.create("Printer Name");
   
   var data = [
      '\nN\n',
      { type: 'raw', format: 'image', 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', data: 'assets/img/image_sample_bw.png', options: { language: "ESCPOS", dotDensity: 'double' } },
   '\x1B' + '\x40',          // init
   '\x1B' + '\x61' + '\x31', // center align
   'Beverly Hills, CA  90210' + '\x0A',
   '\x0A',                   // line break
   'www.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!',
   '\x0A',
   '\x1B' + '\x45' + '\x0A', // bold off
   '\x1D' + '\x21' + '\x11', // double font size
   'Here\'s large text!',
   '\x0A',
   '\x1D' + '\x21' + '\x00', // standard font size
   '\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
   '\x10' + '\x14' + '\x01' + '\x00' + '\x05',  // Generate Pulse to kick-out cash drawer**
                                                // **for legacy drawer cable CD-005A.  Research before using.
];

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); });

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.

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

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

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

Base64 Images

Since 2.0.3, you can send base64 encoded images to qz. This will automatically convert provided base64 encoded image data into a supported raw image type. Base64 image data must begin with data:image/png;base64,.

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

   var data = [
      {
         type: 'raw',
         format: 'image',
         data: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAJFBMVEX' +
               '///8kIiQAAADMzMyZmZlmZmb8/vxcXlz//8z//5lmzAAzZgBFSkm0AAAAVklEQVQYlYWPUQ6AMAhD' +
               'ATvZ5v3va6duYybG90P60gQQ+cBuZs47KVG4exA/BVXLbRZT1ZZle1YYQMM8UVBEgKWBRdR6UKRXg' +
               '5kCAx7QrkidK48/+7MnGPwCSdhQpuEAAAAASUVORK5CYII=',
         options: { language: "ESCPOS", dotDensity: 'double' }
      }
   ];

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

File

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

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

   var data = [
      {
         type: 'raw', 
         format: '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.

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

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

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

URL

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

function printToURL() {
   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

function printToFile() {
   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

function printToUNC() {
   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

function printToDevice() {
   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 endOfDoc delimiter. 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 perSpool option.

function advancedSpooling() {
   var config = qz.configs.create("Printer Name", { endOfDoc : '\n' });

   var data = [
      'First\n',
      'Second\n',
      'Third\n'
   ];

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

Special Characters

Hex

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

   var data = [
      { type: 'raw', format: 'hex', data: 'x1Bx00' } // or data: '1B00'
   ];

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

Decimal

function printDecimal() {
   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); });
}

Right To Left

Some languages such as Arabic are right-to-left and not interpreted properly by raw printers. Although Java can render these languages properly, not all printers are capable of rendering RTL correctly. The workaround is to reverse the text so that it renders properly.

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

   var data = [
      'Lorem: ',
      '	الرياض'.split('').reverse().join(''), // reverse Arabic text for certain printer models
      'Ipsum. '
   ];

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

Note: The split('') method can corrupt data. For a more comprehensive reverse solution, see esrever project.

Code Page

Force Java to use a specific code-page for printing.

function printCodePage() {
   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

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

   // Example only, not valid ESC/POS
   var data = [
      "My Raw Commands",
      String.fromCharCode(27) + String.fromCharCode(0),
      { type: 'raw', format: 'hex', data: 'x1Bx00' },
      { type: 'raw', format: 'image', 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.

function copies() {
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.

function customJobName() {
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); });
}

Alternate Printing

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

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 altPrinting. This parameter has no effect in a Windows environment.

function alternatePrint() {
var config = qz.configs.create("Printer Name", { altPrinting: true });

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');            ////// First 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

Using a Promise Loop, we can defer items (printers, data)

function promiseLoop() {
    var data = [
        "^XA\n^FO50,50^ADN,36,20^FDPRINT 1 ^FS\n^XZ\n",
        "^XA\n^FO50,50^ADN,36,20^FDPRINT 2 ^FS\n^XZ\n",
        "^XA\n^FO50,50^ADN,36,20^FDPRINT 3 ^FS\n^XZ\n",
        "^XA\n^FO50,50^ADN,36,20^FDPRINT 4 ^FS\n^XZ\n"
    ];
    var configs = [
        { "printer": "ZDesigner LP2844-Z" },
        { "printer": "ZDesigner LP2844-Z" },
        { "printer": "ZDesigner LP2844-Z" },
        { "printer": "ZDesigner LP2844-Z" }
    ];
    var chain = [];

    for(var i = 0; i < data.length; i++) {
        (function(i_) {
            //setup this chain link
            var link = function() {
                return qz.printers.find(configs[i_].printer).then(function(found) {
                    return qz.print(qz.configs.create(found), [data[i_]]);
                });
            };

            chain.push(link);
        })(i);
        //closure ensures this promise's concept of `i` doesn't change
    }
	
    //can be .connect or `Promise.resolve()`, etc
    var firstLink = new RSVP.Promise(function(r, e) { r(); });

    var lastLink = null;
    chain.reduce(function(sequence, link) {
        lastLink = sequence.then(link);
        return lastLink;
    }, firstLink);

    //this will be the very last link in the chain
    lastLink.catch(function(err) {
        console.error(err);
    });
}
Edit this page