1.1.4 • Published 7 months ago

electron-secure-pos-printer v1.1.4

Weekly downloads
-
License
MIT
Repository
github
Last release
7 months ago

License Version Issues

electron-secure-pos-printer

A secure POS (point of sale) printer for Electron. By default, supports 58mm printers, however, it is very configurable, and is designed such that it can even be used without Electron (provided you supply the correct shims).

Note: The API for this module is inspired by electron-pos-printer, however it is NOT the same, so please pay close attention below if you are transitioning over from electron-pos-printer.

Installation

NPM:

$ npm install electron-secure-pos-printer

Yarn:

$ yarn add electron-secure-pos-printer

Usage

The module requires only that you configure it in the main Electron process. No script imports or configuration are needed for the renderer HTML.

Step 1: Configure the IPC hooks for the main process

main.js

const Path      = require('path');
const Electron  = require('electron');

const { setupSecurePOSPrinter } = require('electron-secure-pos-printer');

var mainWindow;

function createWindow() {
  mainWindow = new Electron.BrowserWindow({
    width: 800,
    height: 600,
    show: true,
    webPreferences: {
      preload: Path.join(__dirname, 'preload.js')
    },
  });

  // Load your app/site into the main window
  mainWindow.loadFile(Path.join(__dirname, 'main.html'));

  mainWindow.on('closed', function () {
    mainWindow = null;
  });
}

const app = Electron.app;

app.on('ready', () => {
  // Setup secure bridge with renderer
  setupSecurePOSPrinter(Electron);

  createWindow();
});

app.on('window-all-closed', function () {
  if (process.platform !== 'darwin') {
    app.quit();
  }
});

app.on('activate', function () {
  if (mainWindow === null) {
    createWindow();
  }
});

Step 2: Preload for renderer process

preload.js

const { contextBridge, ipcRenderer }  = require('electron');
const { setupSecureBridge }           = require('electron-secure-pos-printer');

// Setup secure bridge with main process
setupSecureBridge(contextBridge, ipcRenderer);

Step 3: Inside your HTML

<!DOCTYPE html>
<html>
  <head>
    <title>Secure POS Printer Test</title>

    <script>
      // This global is exposed by Electron
      /* global securePOSPrinter */

      async function test() {
        // Get a list of attached printers
        var printers = await securePOSPrinter.getPrinters();

        // Print some data

        var data = [
          {
            type:     'text',
            value:    'Testing 123',
          },
          {
            type:     'qrCode',
            value:    'https://www.saltlakefilmsociety.org/',
            options: {
              scale: 4,
            },
          },
          {
            type:     'barCode',
            value:    123456789999,
          },
          {
            // Path to image on file system
            // mimeType is required when loading images from the file system
            type:     'image',
            path:     './assets/printer-image.png',
            mimeType: 'image/png',
          }
          {
            // You can also specify a "src" attribute directly
            type:     'image',
            src:      'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAIAAABLbSncAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH5gIREQQbbUH0CgAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAAMUlEQVQI13WOQQ4AIAzCWv//53kwmjiFYyGAAFBVbKmAjR7Ply6NK6Ufo7elqjye7k6T7hILeH2VsAAAAABJRU5ErkJggg==',
            sectionStyle: {
              alignItems: 'center',
              justifyContent: 'center',
            },
            attributes: {
              width: '100px',
              height: '100px',
            },
          },
          {
            type:     'table',
            header: [ 'Item', 'Price' ],
            rows: [
              [ 'Popcorn',  '$5.00' ],
              [ 'Soda',     '$3.00' ],
              [ 'Candy',    '$2.00' ],
            ],
            footer: [ 'Total', '$10.00' ],
          },
        ];

        var options = {
          printerName: 'SomePrinterName',
          // You can specify your own global stylesheet if you want
          styleSheet: "body,#container { width: '110mm'}",
          preview: true,
        };

        // Note: This promise will not resolve until
        // 1) The preview window is shown, or
        // 2) The document has been sent to the printer, or
        // 3) An error occurred
        await securePOSPrinter.print(data, options);
      }

      test();
    </script>
  </head>

  <body>
  </body>
</html>

Printing options

OptionDescriptionDefault Value
addFinalMargin(boolean) If true, then add a little extra margin at the bottom of the print contenttrue
bodyAttributes(object) Attributes to assign directly to the body tag in the documentnull
containerAttributes(object) Attributes to assign directly to the <div id="container"> element in the document. Inside this container is where all the data content is renderednull
copies(number) number of copies to print1
developmentMode(boolean) If true, then launch the dev-tools for the preview window (only works if preview is true)false
htmlAttributes(object) Attributes to assign directly to the html tag in the document{ lang: "en" }
margin(string) margin of a page, css values can be used0
pageSize(string) Specify the page medium for the printer'A4'
preview(boolean) preview in a windowfalse
previewWindowHeight(number) height of the preview window (in pixels)720
previewWindowWidth(number) width of the preview window (in pixels)360
printerName(string) the printer's namenull
printOptions(object) Options to pass directly to Electron.WebContents.printnull
silent(boolean) To print silently without printer selection pop-uptrue
styleSheet(string/object) A style sheet (not a file name) to apply globally to the document. This gets inserted in the head of the document. If this is an object, then the keys are selectors, and the values are StyleTypenull

The Print data object (common)

OptionDescriptionDefault
sectionStyle(StyleType) style to apply to this section (the container of this content)null
style(StyleType) style to apply to this typenull
type(string) One of 'text', 'qrCode', 'barCode', 'image', 'table''text'

The Print data object (type = 'text')

OptionDescriptionDefault
raw(boolean) If true, then the value provided will not be wrapped in a <span> elementfalse
value(string) REQUIRED Content to put into this sectionnull

Note: By using raw: true to can specify any HTML code you want as the value

Example:

var data = [
  {
    type: 'text',
    value: 'Some content!',
    // if `true`, then don't wrap content in a <span>
    raw: false,
    // Style applied to the <span> element,
    // ignored if "raw = true"
    style: { fontWeight: 'bold' },
    sectionStyle: {
      alignItems: 'center',
      justifyContent: 'center',
    },
  }
];

The Print data object (type = 'qrCode')

OptionDescriptionDefault
attributes(object) Attributes to assign to the <img> tagnull
height(number) Height in pixels for the generated QR code imagenull
options(object) Options object to pass directly to qrcode.optionsnull
value(string) REQUIRED Content to encode into the QR codenull
width(number) Width in pixels for the generated QR code imagenull

Note: The QR code is generated with qrcode as a PNG image encoded in a data: URI.

Example:

var data = [
  {
    type: 'qrCode',
    value: 'Some content!',
    // Style applied to the <img> element
    style: { width: '40mm', height: '40mm' },
    sectionStyle: {
      alignItems: 'center',
      justifyContent: 'center',
    },
    options: {
      scale: 10,
    }
  }
];

The Print data object (type = 'barCode')

OptionDescriptionDefault
attributes(object) Attributes to assign to the <img> tagnull
height(number) Height in pixels for the generated bar code imagenull
options(object) Options object to pass directly to jsbarcode.optionsnull
value(number) REQUIRED ID to encode into the bar codenull
width(number) Width in pixels for the generated bar code imagenull

Note: The barcode is generated with jsbarcode as an SVG image encoded in a data: URI.

Example:

var data = [
  {
    type: 'barCode',
    value: 123456789999,
    // Style applied to the <img> element
    style: { width: '40mm' },
    sectionStyle: {
      alignItems: 'center',
      justifyContent: 'center',
    },
    options: {
      format: 'CODE128',
    }
  }
];

The Print data object (type = 'image')

OptionDescriptionDefault
attributes(object) Attributes to assign to the <img> tagnull
height(number) Height in pixels for the imagenull
path(string) Path on file system to image. If you specify this option then you must also specify a mimeType for the imagenull
mimeType(string) This is required if you specify a pathnull
src(string) Specify the src attribute of the image directly. If path is specified, that will take precedence over this optionnull
width(number) Width in pixels for the imagenull

*Note 1: One of path + mimeType, or src are required*

Note 2: If path is specified, the image will be loaded from disk, and encoded as a data: URI, using the mimeType you specified

Example:

var data = [
  {
    type: 'image',
    path: './assets/some-image.png',
    mimeType: 'image/png',
    // Style applied to the <img> element
    style: { width: '40mm', height: '40mm' },
    sectionStyle: {
      alignItems: 'center',
      justifyContent: 'center',
    },
  },
  {
    type: 'image',
    src: 'https://image-cdn.com/some-image.png',
    // Style applied to the <img> element
    style: { width: '40mm', height: '40mm' },
    sectionStyle: {
      alignItems: 'center',
      justifyContent: 'center',
    },
  }
];

The Print data object (type = 'table')

OptionDescriptionDefault
bodyAttributes(object) Attributes to assign to the <tbody> tagnull
bodyStyle(StyleType) Style to apply to the <tbody> tagnull
columnAttributes(object) Attributes to assign to all <td> tagsnull
columnStyle(StyleType) Style to apply to all <td> tagsnull
footer(arraystring) Columns for the footer. If not specified, then there will be no table footernull
footerAttributes(object) Attributes to assign to the <tfoot> tagnull
footerStyle(StyleType) Style to apply to the <tfoot> tagnull
header(arraystring) Columns for the header. If not specified, then there will be no table headernull
headerAttributes(object) Attributes to assign to the <thead> tagnull
headerStyle(StyleType) Style to apply to the <thead> tagnull
rowAttributes(object) Attributes to assign to all <tr> or <th> tagsnull
rows(array[arraystring]) REQUIRED An array (rows) of arrays (columns) for the tablenull
rowStyle(StyleType) Style to apply to all <tr> or <th> tagsnull
tableAttributes(object) Attributes to assign to the <table> tagnull
tableStyle(StyleType) Style to apply to the <table> tagnull

Note: The number of columns must be the same for every row or an exception will be thrown

Example:

var data = [
  {
    type:     'table',
    header: [ 'Item', 'Price' ],
    rows: [
      [ 'Popcorn',  '$5.00' ],
      [ 'Soda',     '$3.00' ],
      [ 'Candy',    '$2.00' ],
    ],
    footer: [ 'Total', '$10.00' ],
  },
];

StyleType

Styles can be applied to elements in a number of different ways. All of the following style definitions can validly be given to any style option:

  1. As a string: 'border-width: 0.5mm; color: red;'
  2. As an object: { borderWidth: '0.5mm', color: 'red' }
  3. As an array of strings or objects: [ 'border-width: 0.5mm; color: red;', { borderWidth: '0.5mm', color: 'red' }, rootStyleObject ]. If using an array of styles, then all styles will be parsed and merged into a single style sheet.

Note: When using object notation for styles, if you use a number for any value, then by default it will be converted into a mm unit. For example, { width: 10 } would be converted into 'width: 10mm' automatically. If a certain style actually needs a raw number, then specify your style as a string instead.

About the HTML content for the printer

The content that gets renderered for the printer has roughly the following structure:

<html>
  <head>
    <!-- Default and custom style sheets get injected here -->
  </head>

  <!-- The "preview" class is applied to the body if in preview mode -->
  <body class="preview">
    <div id="container">
      <div class="section">
        <!-- content from "data" goes here -->
      </div>
      <div class="section">
        <!-- content from "data" goes here -->
      </div>
      ...
    </div>
  </body>
</html>

Refer to ./src/main-style-sheet.css for the default styles applied to the print document.

If you request preview: true in the options, then extra scripts and content will be injected into the preview document to enable the "Cancel" and "Print" buttons at the top of the preview to function properly.

Sponors

Many thanks to all our sponors!

This work was sponsored by MAST @ Salt Lake Film Society

MAST