9

I am currently building an electron app. I have a PDF on my local file system which I need to silently print out (on the default printer). I came across the node-printer library, but it doesn't seem to work for me. Is there an easy solution to achieve this?

Megajin
  • 2,648
  • 2
  • 25
  • 44
Simon Schiller
  • 644
  • 1
  • 8
  • 23

3 Answers3

16

Well first of all it is near impossible to understand what you mean with "silent" print. Because once you send a print order to your system printer it will be out of your hand to be silent at all. On Windows for example once the order was given, at least the systemtray icon will indicate that something is going on. That said, there are very good described features for printing with electron even "silent" is one of them:

You need to get all system printers if you do not want to use the default printer:

contents.getPrinters()

Which will return a PrinterInfo[] Object.

Here is an example how the object will look like from the electron PrtinerInfo Docs:

{
  name: 'Zebra_LP2844',
  description: 'Zebra LP2844',
  status: 3,
  isDefault: false,
  options: {
    copies: '1',
    'device-uri': 'usb://Zebra/LP2844?location=14200000',
    finishings: '3',
    'job-cancel-after': '10800',
    'job-hold-until': 'no-hold',
    'job-priority': '50',
    'job-sheets': 'none,none',
    'marker-change-time': '0',
    'number-up': '1',
    'printer-commands': 'none',
    'printer-info': 'Zebra LP2844',
    'printer-is-accepting-jobs': 'true',
    'printer-is-shared': 'true',
    'printer-location': '',
    'printer-make-and-model': 'Zebra EPL2 Label Printer',
    'printer-state': '3',
    'printer-state-change-time': '1484872644',
    'printer-state-reasons': 'offline-report',
    'printer-type': '36932',
    'printer-uri-supported': 'ipp://localhost/printers/Zebra_LP2844',
    system_driverinfo: 'Z'
  }
}

To print your file you can do it with

contents.print([options])

The options are descriped in the docs for contents.print():

  • options Object (optional):
  • silent Boolean (optional) - Don’t ask user for print settings. Default is false.
  • printBackground Boolean (optional) - Also prints the background color and image of the web page. Default is false.
  • deviceName String (optional) - Set the printer device name to use. Default is ''.

Prints window’s web page. When silent is set to true, Electron will pick the system’s default printer if deviceName is empty and the default settings for printing.

Calling window.print() in web page is equivalent to calling webContents.print({silent: false, printBackground: false, deviceName: ''}).

Use page-break-before: always; CSS style to force to print to a new page.

So all you need is to load the PDF into a hidden window and then fire the print method implemented in electron with the flag set to silent.

// In the main process.
const {app, BrowserWindow} = require('electron');
let win = null;

app.on('ready', () => {
  // Create window
  win = new BrowserWindow({width: 800, height: 600, show: false });
  // Could be redundant, try if you need this.
  win.once('ready-to-show', () => win.hide())
  // load PDF.
  win.loadURL(`file://directory/to/pdf/document.pdf`);
 // if pdf is loaded start printing.
  win.webContents.on('did-finish-load', () => {
    win.webContents.print({silent: true});
    // close window after print order.
    win = null;
  });
});

However let me give you a little warning: Once you start printing it can and will get frustrating because there are drivers out there which will interpret data in a slightly different way. Meaning that margins could be ignored and much more. Since you already have a PDF this problem will most likely not happen. But keep this in mind if you ever want to use this method for example contents.printToPDF(options, callback). That beeing said there are plently of options to avoid getting frustrated like using a predefined stylesheet like descriped in this question: Print: How to stick footer on every page to the bottom?

If you want to search for features in electron and you do not know where they could be hidden, all you have to do is to go to "all" docs and use your search function: https://electron.atom.io/docs/all/

regards, Megajin

Megajin
  • 2,648
  • 2
  • 25
  • 44
  • And how do I load my pdf into an invisible window? – Simon Schiller Sep 03 '17 at 08:47
  • As noted from be in my answer you can see everything in the [electron docs for hide window](https://electron.atom.io/docs/all/#winhide). The usage is as follows: `win.hide()`. That's it. Consider accepting my answer if it was helpful to you – Megajin Sep 03 '17 at 10:12
  • I guess the question is more about the pdf loading, not about the invisible window, sorry – Simon Schiller Sep 04 '17 at 05:40
  • 2
    Your question was to "silently" print a PDF. In electron you have to load your content to print it. Since you want it to be "silent" you have to load it into a invisible window and instantly print it with the given commands I've provided to you. – Megajin Sep 04 '17 at 08:36
  • Right, everything is clear for me, I just wonder how the content of a PDF-file can be loaded into a `BrowserWindow` – Simon Schiller Sep 04 '17 at 08:37
  • You can try it with [loadURL](https://electron.atom.io/docs/api/web-contents/#contentsloadurlurl-options) just use this prefix `file://` and then the link to your pdf like: `loadURL('file://path/to/my/pdf/myDoc.pdf')` – Megajin Sep 04 '17 at 08:42
  • I've added some code for you so you have a good starting point. See my edited answer. – Megajin Sep 04 '17 at 08:55
  • `contents.getPrinters()` is not a function is it deprecated ? – Jeevan Oct 31 '17 at 10:44
  • @Jeevan what makes you think that `contents.getPrinters();` is deprecated? According to the docs it is not deprecated: https://electron.atom.io/docs/all/#contentsgetprinters . All deprecated functions are listed in the docs as well with the necessary information how to replace it. – Megajin Oct 31 '17 at 11:14
  • @Megajin I have updated electron its working fine now...Its available in electron > 1.7 version – Jeevan Nov 01 '17 at 09:31
  • @Jeevan I'm glad it worked out for you =). They should add a Tag saying on which version the function was added, like in nodejs... – Megajin Nov 02 '17 at 07:20
  • @Megajin : How do i check the printer status, whether it's on,idle,busy or unavailbale. The status in the json returned is always 3 and 'printer-is-accepting-jobs' is 'true' – hablema Jan 11 '18 at 05:55
  • @hablema it depends, please keep in mind that printers may behave differently. For the best results you have to look up the `status-codes` of the given printer. A printer is accepting jobs even if there are errors sometimes. That is what I meant by 'printers behave differently'. Google for your printer and the given codes, that will make things clearer in your case. BTW, updating electron is also a good idea, new features might help as well. – Megajin Jan 15 '18 at 14:41
  • @Megajin this appears to be broken/not working, [here's a similar question](https://stackoverflow.com/q/49650784/1768303). Am I missing something? – noseratio Aug 13 '18 at 20:36
  • @Noseratio I will answer that question, it is not really broken but unnecessarily complex. PDFs work differently on different APPs... I did run into this problem twice. However give me some time and I will answer the question linked by you. – Megajin Aug 20 '18 at 08:13
  • @Megajin, thank you, take your time. I'd be happy to reward your answer with another bounty here. For now, [PDF.js](https://mozilla.github.io/pdf.js/) solves the problem with rendering/previewing individual pages, but as to printing itself, it appears Electron (at the time of this posting) just lacks the proper printing APIs. E.g., you can't set paper size/landscape portrait mode etc. Moreover, both PDF.js and Electron when printing produce rasterized print-outs, unlike Chrome PDF Viewer. That can be seen if you print to "Microsoft Print to PDF" and the view/scale the output. – noseratio Aug 20 '18 at 11:34
  • So for now I think it'll be a combination of PDF.js (for UI in the Electron's Renderer process) and PDFium (for actual printing from the Main process). – noseratio Aug 20 '18 at 11:36
  • How do I print from a specific printer? – Toni Aug 08 '19 at 15:30
  • @toni Just use `contents.getPrinters()`. That will return a `PrinterInfo[]` object. You can then search for your desired printer in there. Once you have found your printer name, you can use this method: `webContents.print({silent: false, printBackground: false, deviceName: '_YOUR_PRINTER_NAME_'})` just replace `_YOUR_PRINTER_NAME_` with your actual printer name. – Megajin Aug 09 '19 at 06:33
9

I recently published NPM package to print PDF files from Node.js and Electron. You can send a PDF file to the default printer or to a specific one. Works fine on Windows and Unix-like operating systems: https://github.com/artiebits/pdf-to-printer.

It's easy to install, just (if using yarn):

yarn add pdf-to-printer

or (if using npm):

npm install --save pdf-to-printer

Then, to silently print the file to the default printer you do:

import { print } from "pdf-to-printer";

print("assets/pdf-sample.pdf")
  .then(console.log)
  .catch(console.error);
artiebits
  • 5,075
  • 1
  • 13
  • 15
2

To my knowledge there is currently no way to do this directly using Electron because while using contents.print([]) does allow for 'silently' printing HTML files, it isn't able to print PDF views. This is currently an open feature request: https://github.com/electron/electron/issues/9029

Edit: I managed to work around this by converting the PDF to a PNG and then using Electron's print functionality (which is able to print PNGs) to print the image based view. One of the major downsides to this is that all of the PDF to PNG/JPEG conversion libraries for NodeJS have a number of dependencies, meaning I had to implement them in an Express server and then have my Electron app send all PDFs to the server for conversion. It's not a great option, but it does work.

antzshrek
  • 9,276
  • 5
  • 26
  • 43
rc1911
  • 33
  • 8
  • can you show your code. i have same task. need to print image from electron/express. – m4a Mar 13 '21 at 14:55