最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Electron: print iframe given reference to it - Stack Overflow

programmeradmin3浏览0评论

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}
/>

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}
/>
Share Improve this question edited Dec 26, 2021 at 18:30 Matthew Herbst asked Aug 12, 2021 at 4:10 Matthew HerbstMatthew Herbst 32k26 gold badges90 silver badges136 bronze badges 2
  • Try creating a BrowserWindow, and assign the iframe to it temporarily. then print and delete the browserwindow? – Base64__ Commented Dec 27, 2021 at 6:50
  • @Base64__ I have no knowledge of Electron, why I'm asking the question heh. If you could provide an working example, possibly as an answer, that would be appreciated – Matthew Herbst Commented Dec 28, 2021 at 14:53
Add a ment  | 

3 Answers 3

Reset to default 12 +300

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/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;charset=utf-8' });
    var url = URL.createObjectURL(blob);

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

main.js

// List of all options at -
// https://www.electronjs/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:

//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.

I am writing this answer to address a minor issue that you might encounter when following the advice in the Hutt's answer. The character encoding can be lost when creating the blob, which can cause problems when printing non-Latin characters. To prevent this, you should specify the encoding when creating the blob, like this:

const blob = new Blob([data], { type: "text/html;charset=utf-8" });

Adding on to the previous answer: it would be good idea to close the window programmatically, even when show: false. It will take up resources. win?.close();
While minimized or hidden, BrowserWindows still consume some system resources like memory and processing power.

发布评论

评论列表(0)

  1. 暂无评论