Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Electron: print iframe given reference to it

I would like to use the react-to-print library to print an iframe from my Electron app. How can I use the iframe reference to get the correct window/element to print?

const handleElectronPrint = async (target: HTMLIFrameElement) {
  // Instead of this (printing the whole page)
  // let win = BrowserWindow.getFocusedWindow();

  // How do I print just the referenced iframe?
  // `target` iframe has id="printWindow", how to select it?
  let win = BrowserWindow.getMyIframe();
  
  // Is this the right way to do the print once we have the iframe?
  const options = { printBackground: true };
  win.webContents.print(options, (success, failureReason) => {
    if (!success) console.log(failureReason);
  
    console.log('Print Initiated');
  }); 
};

<ReactToPrint
 ...
 print={handleElectronPrint}
/>
like image 315
Matthew Herbst Avatar asked Oct 14 '22 20:10

Matthew Herbst


1 Answers

You need to convert the iframe object to Data URL. And load the URL in a new hidden BrowserWindow object.
Build data URL in Renderer process and send the URL to Main process using preload. In main process do the BrowserWindow.loadURL and printing.

App.js

  // Send print request to the Main process
  this.handlePrint = function (target) {
   return new Promise(() => {
    console.log('forwarding print request to the main process...');

    // convert the iframe into data url
    // https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs
    let data = target.contentWindow.document.documentElement.outerHTML;
    //console.log(data);
    var blob = new Blob([data], { type: 'text/html' });
    var url = URL.createObjectURL(blob);

    window.electronAPI.printComponent(url, (response) => {
     console.log('Main: ', response);
    });
   });
  };

main.js

// List of all options at -
// https://www.electronjs.org/docs/latest/api/web-contents#contentsprintoptions-callback
const printOptions = {
 silent: false,
 printBackground: true,
 color: true,
 margin: {
  marginType: 'printableArea',
 },
 landscape: false,
 pagesPerSheet: 1,
 collate: false,
 copies: 1,
 header: 'Page header',
 footer: 'Page footer',
};

ipcMain.handle('printComponent', (event, url) => {
 let win = new BrowserWindow({ show: false });
 win.loadURL(url);

 win.webContents.on('did-finish-load', () => {
  win.webContents.print(printOptions, (success, failureReason) => {
   console.log('Print Initiated in Main...');
   if (!success) console.log(failureReason);
  });
 });
 return 'done in main';
});

preload.js

const { contextBridge, ipcRenderer } = require('electron');

contextBridge.exposeInMainWorld('electronAPI', {
 printComponent: async (url, callback) => {
  let response = await ipcRenderer.invoke('printComponent', url);
  callback(response);
 },
});


Here is the list of all print options. Some options like page size, margins, orientation can be set in CSS @page rule refer App.css in my demo app.

Here is demo app on GitHub electron-react-to-print-demo.


Print Preview: There is no, Chrome browser style, inbuilt print preview feature due to these reasons. We need to implement our own workaround. Like print to PDF and show pdf in new window: enter image description here

//handle preview
ipcMain.handle('previewComponent', (event, url) => {
 let win = new BrowserWindow({ title: 'Preview', show: false, autoHideMenuBar: true });

 win.loadURL(url);

 win.webContents.once('did-finish-load', () => {
  win.webContents.printToPDF(printOptions).then((data) => {
    let buf = Buffer.from(data);
    var data = buf.toString('base64');
    let url = 'data:application/pdf;base64,' + data;

    win.webContents.on('ready-to-show', () => {
     win.show();
     win.setTitle('Preview');
    });
    win.webContents.on('closed', () => win = null;);
    win.loadURL(url);

   })
   .catch((error) => {
    console.log(error);
   });
 });
 return 'shown preview window';
});

I've added above preview feature in electron-react-to-print-demo.

like image 155
the Hutt Avatar answered Oct 18 '22 12:10

the Hutt