24

i'm trying to convert my web into an app made in ElectronJS

in my web i print a div with a barcode. this works pretty fine, but in electronjs i can't reach this.

originally i'd use this function

$scope.printDiv = function (divName) {
    var printContents = document.getElementById(divName).innerHTML;
    var popupWin = window.open('', '_blank', 'width=500,height=500');
    popupWin.document.open();
    popupWin.document.write('<html><head><link rel="stylesheet" type="text/css" href="styles/main.css"  type=\"text/css\" media=\"print\" /></head><body onload="window.print()">' + printContents + '</body></html>');
    popupWin.document.close();
}

with electronjs

i don't know how to pass the object to print.

also i'm trying to generate a PDF from content that i can load. but the PDF's are corrupted

var windowPrint = require('electron').remote.BrowserWindow;
    var fs = require('fs');
    var newWindow = new windowPrint({width: 800, height: 600, show: false});
    console.log(newWindow);
    newWindow.loadURL('http://github.com');
    newWindow.show();
    newWindow.webContents.print({silent: true, printBackground: true});
    newWindow.webContents.printToPDF({printSelectionOnly : true, printBackground: true}, function (error, data) {
        if (error) {
            throw error;
        }
        console.log(error);
        console.log(data);
        fs.writeFile('print.pdf', function (data, error) {
            if (error) {
                throw error;
            }
            console.log(error);
            console.log(data);
        });
    });

there's a simple way to print a DIV with electronjs?

thank you for reading.

Paulo Galdo Sandoval
  • 2,173
  • 6
  • 27
  • 44
  • https://github.com/electron/electron-api-demos You can create a invisible blank window which receive signals (html string) from main process and then prints pdf. – Zen Jun 05 '16 at 11:26
  • i've seen that, but this just create a pdf? or also send the print command? – Paulo Galdo Sandoval Jun 05 '16 at 22:28
  • Sorry for my late reply, have you figured it out? – Zen Jun 10 '16 at 17:15
  • i've see it before, but can't print the pdf well, still getting corrupted files. is there any documentation complete about printing and pdf on electronjs?. thanks for your answer – Paulo Galdo Sandoval Jun 10 '16 at 17:20

5 Answers5

29

You have printed this page before loading is finished.

My approach: 1. create a mainwindow and a (invisible) worker window

import {app, BrowserWindow, Menu, ipcMain, shell} from "electron";
const os = require("os");
const fs = require("fs");
const path = require("path");

let mainWindow: Electron.BrowserWindow = undefined;
let workerWindow: Electron.BrowserWindow = undefined;

async function createWindow() {

    mainWindow = new BrowserWindow();
    mainWindow.loadURL("file://" + __dirname + "/index.html");
    mainWindow.webContents.openDevTools();
    mainWindow.on("closed", () => {
        // close worker windows later
        mainWindow = undefined;
    });

    workerWindow = new BrowserWindow();
    workerWindow.loadURL("file://" + __dirname + "/worker.html");
    // workerWindow.hide();
    workerWindow.webContents.openDevTools();
    workerWindow.on("closed", () => {
        workerWindow = undefined;
    });
}

// retransmit it to workerWindow
ipcMain.on("printPDF", (event: any, content: any) => {
    console.log(content);
    workerWindow.webContents.send("printPDF", content);
});
// when worker window is ready
ipcMain.on("readyToPrintPDF", (event) => {
    const pdfPath = path.join(os.tmpdir(), 'print.pdf');
    // Use default printing options
    workerWindow.webContents.printToPDF({}).then((data) {
        fs.writeFile(pdfPath, data, function (error) {
            if (error) {
                throw error
            }
            shell.openItem(pdfPath)
            event.sender.send('wrote-pdf', pdfPath)
        })
    }).catch((error) => {
       throw error;
    })
});

2, mainWindow.html

<head>
</head>
<body>
    <button id="btn"> Save </button>
    <script>
        const ipcRenderer = require("electron").ipcRenderer;

        // cannot send message to other windows directly https://github.com/electron/electron/issues/991
        function sendCommandToWorker(content) {
            ipcRenderer.send("printPDF", content);
        }

        document.getElementById("btn").addEventListener("click", () => {
            // send whatever you like
            sendCommandToWorker("<h1> hello </h1>");
        });
    </script>
</body>

3, worker.html

<head> </head>
<body>
    <script>
        const ipcRenderer = require("electron").ipcRenderer;

        ipcRenderer.on("printPDF", (event, content) => {
            document.body.innerHTML = content;

            ipcRenderer.send("readyToPrintPDF");
        });
    </script>
</body>
Sebastian Kaczmarek
  • 8,120
  • 4
  • 20
  • 38
Zen
  • 5,065
  • 8
  • 29
  • 49
  • Thank you so much, this help me a lot. but i have a few questions. instead of `printToPdf()` it will work with just `print()` ?? – Paulo Galdo Sandoval Jun 12 '16 at 04:09
  • They are not the same thing. `print()` is used with a printer. @PauloGaldoSandoval – Zen Jun 12 '16 at 06:19
  • yeah, that's what i'm trying to reach at first, but print a PDF is also functional to me. but i'm saying if in that way i'm getting the PDF i can send the print command. – Paulo Galdo Sandoval Jun 12 '16 at 06:23
  • I don't know. Maybe you can have a try.@PauloGaldoSandoval – Zen Jun 12 '16 at 06:28
  • well, i will update this once my printer will be fixed next week and update the code above, but thank you so much, this help me a lot of understand more electronjs. – Paulo Galdo Sandoval Jun 12 '16 at 06:30
  • 1
    This still works like a charm. My issue is that the content I want to print to PDF is styled via CSS. Although in the hidden window the content is shown perfectly fine as soon as I create the pdf file all styles are gone in the file. Does anyone has a solution on how I can keep my styles when creating a pdf? – JDK92 Aug 20 '18 at 13:39
  • 1
    There were quite some issues in using your code. In the worker window console, it showed "Not allowed to load local resource: file://src/main/worker.html" I solved it by using the below code `workerWindow = new BrowserWindow({ show: true, webPreferences: { webSecurity: false }, protocol: 'file', // parent:mainWindow }); workerWindow.loadURL(process.env.NODE_ENV === 'development' ? `http://localhost:9080/static/assets/worker.html` : `file://${__dirname}/worker.html`); ` And i had to place the worker.html file in static folder – Shyam Mar 11 '19 at 11:36
  • Could You update this answer please, I try to use it but I face many exceptions – Anyname Donotcare Jul 26 '19 at 13:35
  • 1
    I haven't used electron for a long time. Please edit this answer if you make it. @AnynameDonotcare – Zen Jul 31 '19 at 02:25
  • i need any github link for above example?any one know , i am new to electronjs – Balaji Apr 01 '20 at 19:30
  • As of Electron 5.0.0, you have to add `webPreferences.nodeIntegration = true`, else 'require' won't work. – Daniel M Jan 20 '21 at 15:48
  • This works fine, but not when un-commenting the `workerWindow.hide();` line.. When hiding the window (which is the behavior I would prefer), it becomes impossible to open developer tools, and when closing the app, it does not properly exit (maybe linked to the OS not supporting hidden windows? I use Linux Mint 18.3). – Florent F Jun 04 '21 at 14:57
4

Thank you, works for printing with print() as well

ipcMain.on('print', (event, content) => {
    workerWindow.webContents.send('print', content);
});

ipcMain.on('readyToPrint', (event) => {
    workerWindow.webContents.print({});
});

(events are renamed accordingly)

Johan
  • 843
  • 8
  • 10
2

This is probably a bit late, but for others that want to print a div in electron, I would recommend you select your div using a range object, then use the main process to print the pdf with printSelectionOnly at true.

JS in renderer process :

function printDivToPDF(id) {
    let element = document.getElementById(id);
    let range = new Range();
    range.setStart(element, 0);
    range.setEndAfter(element, 0);
    document.getSelection().removeAllRanges();
    document.getSelection().addRange(range);
    ipcRenderer.send('exportSelectionToPDF');
}

Js in main process :

ipcMain.on('exportSelectionToPDF', (event) => {
    let window = BrowserWindow.fromWebContents(e.sender);
    window.webContents.printToPDF({ printSelectionOnly: true, }).then((data) => {
        // Use the data however you like :)
    });
});
  • Your code is working. but all of the content of window are printed. I though the `printSelectionOnly` option is for printing only selected content. but it is not work properly. if you have any other way, please help me. – Dev Conductor Aug 01 '23 at 21:25
1

You are possibly trying to communicate between the Renderer & the Main process.

You can make use of IPC calls provided by Electron to send messages to Renderer from Main process and the callback function can inject DOM elements inside the HTML.

enter image description here

0

You have printed this page before loading is finished.

My approach: 1. create a mainwindow and a (invisible) worker window

import {app, BrowserWindow, Menu, ipcMain, shell} from "electron";
const os = require("os");
const fs = require("fs");
const path = require("path");

let mainWindow: Electron.BrowserWindow = undefined;
let workerWindow: Electron.BrowserWindow = undefined;

async function createWindow() {

    mainWindow = new BrowserWindow();
    mainWindow.loadURL("file://" + __dirname + "/index.html");
    mainWindow.webContents.openDevTools();
    mainWindow.on("closed", () => {
        // close worker windows later
        mainWindow = undefined;
    });

    workerWindow = new BrowserWindow();
    workerWindow.loadURL("file://" + __dirname + "/worker.html");
    // workerWindow.hide();
    workerWindow.webContents.openDevTools();
    workerWindow.on("closed", () => {
        workerWindow = undefined;
    });
}

// retransmit it to workerWindow
ipcMain.on("printPDF", (event: any, content: any) => {
    console.log(content);
    workerWindow.webContents.send("printPDF", content);
});
// when worker window is ready
ipcMain.on("readyToPrintPDF", (event) => {
    const pdfPath = path.join(os.tmpdir(), 'print.pdf');
    // Use default printing options
    workerWindow.webContents.printToPDF({}).then((data) {
        fs.writeFile(pdfPath, data, function (error) {
            if (error) {
                throw error
            }
            shell.openItem(pdfPath)
            event.sender.send('wrote-pdf', pdfPath)
        })
    }).catch((error) => {
       throw error;
    })
});

2, mainWindow.html

<head>
</head>
<body>
    <button id="btn"> Save </button>
    <script>
        const ipcRenderer = require("electron").ipcRenderer;

        // cannot send message to other windows directly https://github.com/electron/electron/issues/991
        function sendCommandToWorker(content) {
            ipcRenderer.send("printPDF", content);
        }

        document.getElementById("btn").addEventListener("click", () => {
            // send whatever you like
            sendCommandToWorker("<h1> hello </h1>");
        });
    </script>
</body>

3, worker.html

<head> </head>
<body>
    <script>
        const ipcRenderer = require("electron").ipcRenderer;

        ipcRenderer.on("printPDF", (event, content) => {
            document.body.innerHTML = content;

            ipcRenderer.send("readyToPrintPDF");
        });
    </script>
</body>