Open In App

Generate PDF in ElectronJS

Improve
Improve
Improve
Like Article
Like
Save Article
Save
Share
Report issue
Report

ElectronJS is an Open Source Framework used for building Cross-Platform native desktop applications using web technologies such as HTML, CSS, and JavaScript which are capable of running on Windows, macOS, and Linux operating systems. It combines the Chromium engine and NodeJS into a Single Runtime.

In certain desktop applications, developers would like to provide a feature wherein the user can download the contents of the page and save it as a PDF file onto their system. For example, in a banking application, the user would like to download his/her account statement displayed on the screen and save it as a PDF file. Electron provides a way by which we can achieve this functionality using the BrowserWindow object and the webContents property. The webContents property provides us with certain Instance Events and methods by which we can either convert the contents of the BrowserWindow being displayed to a PDF file or save the contents of a remote URL to a PDF file. This tutorial will demonstrate how to generate PDF files in Electron.

We assume that you are familiar with the prerequisites as covered in the above-mentioned link. For Electron to work, node and npm need to be pre-installed in the system.

Project Structure:

Project Structure

Example: We will start by building the basic Electron Application by following the given steps.

Step 1: Navigate to an Empty Directory to setup the project, and run the following command,

npm init
  • To generate the package.json file. Install Electron using npm if it is not installed.
npm install electron --save
  • This command will also create the package-lock.json file and install the required node_modules dependencies. Create the assets folder according to the project structure. We will save the generated PDF files to this folder. package.json:
{
  "name": "electron-pdf",
  "version": "1.0.0",
  "description": "Generate PDF in Electron",
  "main": "main.js",
  "scripts": {
    "start": "electron ."
  },
  "keywords": [
    "electron"
  ],
  "author": "Radhesh Khanna",
  "license": "ISC",
  "dependencies": {
    "electron": "^8.2.5"
  }
}

Step 2: Create a main.js file according to the project structure. This file is the Main Process and acts as an entry point into the application. Copy the Boilerplate code for the main.js file as given in the following link. We have modified the code to suit our project needs.

 main.js:

javascript




const { app, BrowserWindow } = require('electron')
 
function createWindow() {
    // Create the browser window.
    const win = new BrowserWindow({
        width: 800,
        height: 600,
        webPreferences: {
            nodeIntegration: true,
            //allows remote module
            enableRemoteModule: true
        }
    })
 
    // Load the index.html of the app.
    win.loadFile('src/index.html')
 
    // Open the DevTools.
    win.webContents.openDevTools()
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
// This method is equivalent to 'app.on('ready', function())'
app.whenReady().then(createWindow)
 
// Quit when all windows are closed.
app.on('window-all-closed', () =& gt; {
    // On macOS it is common for applications and their menu bar
    // to stay active until the user quits explicitly with Cmd + Q
    if (process.platform !== 'darwin') {
        app.quit()
    }
})
 
app.on('activate', () =& gt; {
    // On macOS it's common to re-create a window in the
    // app when the dock icon is clicked and there are no
    // other windows open.
    if (BrowserWindow.getAllWindows().length === 0) {
        createWindow()
    }
})
 
// In this file, you can include the rest of your
// app's specific main process code. You can also
// put them in separate files and require them here.


Step 3: Create the index.html file and index.js file within the src directory. We will also copy the boilerplate code for the index.html file from the above-mentioned link. We have modified the code to suit our project needs.

index.html:

html




<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Hello World!</title>
  security#csp-meta-tag -->
    <meta http-equiv="Content-Security-Policy"
        content="script-src 'self' 'unsafe-inline';" />
</head>
<body>
    <h1>Hello World!</h1>
    We are using node
    <script>
        document.write(process.versions.node)
    </script>, Chrome
    <script>
        document.write(process.versions.chrome)
    </script>, and Electron
    <script>
        document.write(process.versions.electron)
    </script>.
     
    <!-- Adding Individual Renderer Process JS File -->
    <script src="index.js"></script>
</body>
</html>


Output: At this point, our basic Electron Application is set up. To launch the Electron Application, run the Command:

npm start

GUI Output

Generate PDF in Electron: The BrowserWindow Instance and webContents Property are part of the Main Process. To import and use BrowserWindow in the Renderer Process, we will be using Electron remote module.

Approach 1: Convert the contents of the current active BrowserWindow Instance and save it as a PDF file. 

Add the following snippet to that file.

index.html: 

html




<br><br>
<button id="pdf">
    Convert Current BrowserWindow to PDF
</button>


Add the following snippet in that file.

index.js

javascript




const electron = require('electron');
const path = require('path');
const fs = require('fs');
 
// Importing BrowserWindow from Main
const BrowserWindow = electron.remote.BrowserWindow;
 
var pdf = document.getElementById('pdf');
var filepath1 = path.join(__dirname, '../assets/print1.pdf');
 
var options = {
    marginsType: 0,
    pageSize: 'A4',
    printBackground: true,
    printSelectionOnly: false,
    landscape: false
}
 
pdf.addEventListener('click', (event) => {
 
    // let win = BrowserWindow.getAllWindows()[0];
    let win = BrowserWindow.getFocusedWindow();
     
    win.webContents.printToPDF(options).then(data => {
        fs.writeFile(filepath1, data, function (err) {
            if (err) {
                console.log(err);
            } else {
                console.log('PDF Generated Successfully');
            }
        });
    }).catch(error => {
        console.log(error)
    });
});


The webContents.printToPDF(options) method prints BrowserWindow contents as a PDF with Chromium’s preview printing custom settings. This method returns a Promise and it gets resolved to a Buffer containing the data to be written to the PDF file. It takes in the following parameters. For more detailed information on webContents.printToPDF() method, Refer to this link.

  • options: Object We can pass an empty options object in which case it will take all respective default values. It takes in the following parameters, 
    • marginsType: Integer (Optional) Specifies the type of margins to be used in the PDF file. It can hold the following values:
      • 0 – Default Margins
      • 1 – No Margins
      • 2 – Minimum Margins
    • pageSize: Object/String (Optional) Specifies the Page size of the generated PDF files. Values can be A3, A4, A5, Legal, Letter, Tabloid. It can also hold an Object containing the height property and the width property defined in microns.
    • printBackground: Boolean (Optional) Whether to Include the CSS Backgrounds (such as background-color) in the PDF file. Default value is false.
    • printSelectionOnly: Boolean (Optional) Whether to print Selections or Highlights only in the PDF file. Default value is false.
    • landscape: Boolean (Optional) Specifies the mode of the PDF file. Value is set to true for landscape mode. Value is set as false for portrait mode. Default value is false.
  • BrowserWindow.getAllWindows(): This method returns an Array of active/opened BrowserWindow Instances. In this application, we have only one active BrowserWindow Instance and it can be directly referred from the Array as shown in the code.
  • BrowserWindow.getFocusedWindow(): This method returns the BrowserWindow Instance which is focused in the Application. If no current BrowserWindow Instance is found, it returns null. In this application, we only have one active BrowserWindow Instance and it can be directly referred using this method as shown in the code.

Approach 2: Convert the contents of a remote URL and save it as a PDF file. 

Add the following snippet to that file.

index.html:

html




<br><br>
    <button id="convert">Convert Google.com to PDF</button>


Add the following snippet to that file.

index.js:

javascript




const electron = require('electron');
const path = require('path');
const fs = require('fs');
// Importing BrowserWindow from Main
const BrowserWindow = electron.remote.BrowserWindow;
 
var convert = document.getElementById('convert');
var filepath2 = path.join(__dirname, '../assets/print2.pdf');
 
var options2 = {
    marginsType: 1,
    pageSize: 'A4',
    printBackground: true,
    printSelectionOnly: false,
    landscape: false
}
 
convert.addEventListener('click', (event) => {
    let win = new BrowserWindow({
        show: false,
        webPreferences: {
          nodeIntegration: true
        }
      });
 
    win.loadURL('https://www.google.com/');
 
    win.webContents.on('did-finish-load', () => {
        win.webContents.printToPDF(options2).then(data => {
            fs.writeFile(filepath2, data, function (err) {
                if (err) {
                    console.log(err);
                } else {
                    console.log('PDF Generated Successfully');
                }
            });
        }).catch(error => {
            console.log(error)
        });
    });
});


Output:
 

In this case, we have created a new BrowserWindow Instance and set the show property to false. Hence the newly created window will never be shown. We have used the win.loadURL(path) method to load the contents of the External URL in the BrowserWindow. The URL path can be a remote address specified by http:// protocol or a path to a file in the local System specified by using the file:// protocol. This method returns a Promise and it is resolved when the page has finished loading and the did-finish-load Event of webContents property is Emitted. For more detailed information, Refer this link.

The did-finish-load Instance Event belongs to the webContents Property. It is emitted when the navigation is done and the page is completely loaded. This happens when the spinner of the page has stopped spinning, and the onload event has been dispatched. In case, this event emitter is not used and the webContents.printToPDF() method is called, the PDF generated will be a blank document since the content did not finish loading in the BrowserWindow. Hence the data returned in the Promise is empty. For more detailed information, Refer to this link



Last Updated : 28 Apr, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads