1. 程式人生 > >使用electron靜默列印

使用electron靜默列印

1.使用electron列印的理由

很多情況下程式中使用的列印都是使用者無感知的。並且想要靈活的控制列印內容,往往需要藉助印表機給我們提供的api再進行開發,這種開發方式非常繁瑣,並且開發難度較大。

electron提供的列印api可以非常靈活的控制列印設定的顯示,並且可以通過html來書寫列印內容。

2.api

electron提供了兩種方式進行列印,一種是直接呼叫印表機列印,一種是列印到pdf。

並且有兩種物件可以呼叫列印:

第一是通過window的webcontent物件,使用此種方式需要單獨開出一個列印的視窗,可以將該視窗隱藏,但是通訊呼叫相對複雜。

另一種是使用頁面的webview元素呼叫列印,可以將webview隱藏在呼叫的頁面中,通訊方式比較簡單。

兩個物件呼叫列印方法的使用方式都一樣。

2.1 print

官網api如下

contents.print([options], [callback])
選項 Object (可選)

silent Boolean (可選) - 不詢問使用者列印資訊,預設為 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 ''.
callback Function (可選)

success Boolean - Indicates success of the print call.

列印配置(options)中只有簡單的三個配置:

silent:列印時是否不展示列印配置(是否靜默列印)

printBackground:是否列印背景

deviceName:印表機裝置名稱

首先要將我們使用的印表機名稱配置好,並且要在呼叫列印前首先要判斷印表機是否可用。

使用getPrinters方法可獲取當前裝置已經配置的印表機列表,注意配置過不是可用,只是在此裝置上安裝過驅動。

我們這裡只管關心兩個,name和status,status為0時表示印表機可用。

這裡的status必須經歷一次列印失敗才能返回非0值,也就是說第一次獲取印表機狀態一定是0。但是這一次的列印雖然不能判斷出錯誤,列印的任務已經預存在佇列中了,當下一次印表機狀態變為可用時,將會列印暫存的任務。

當印表機紙張用完時也是這種情況,剩餘任務會暫存起來,下次印表機可用時即可以列印了。

print的第二個引數callback是用於判斷列印任務是否發出的回撥,而不是列印任務完成後的回撥。所以一般列印任務發出,回撥函式即會呼叫並返回引數true。這個回撥並不能判斷列印是否真的成功了。

2.2 printToPdf

contents.printToPDF(options, callback)
選項 Object

marginsType Integer (optional) - Specifies the type of margins to use. Uses 0 for default margin, 1 for no margin, and 2 for minimum margin.
pageSize String (optional) - Specify page size of the generated PDF. Can be A3, A4, A5, Legal, Letter, Tabloid or an Object containing height and width in microns.
printBackground Boolean (optional) - Whether to print CSS backgrounds.
printSelectionOnly Boolean (optional) - Whether to print selection only.
landscape Boolean (optional) - true for landscape, false for portrait.
callback Function - 回撥函式

error Error
data Buffer

printToPdf的用法基本和print相同,但是由於print是native code提供的方法,配置項非常少,而printToPdf則擴充套件了很多屬性。

包括可以對列印的margin,列印頁首頁尾等進行配置。

配置項很多,翻了一下原始碼發現還有很多沒有被貼進api的:

const defaultPrintingSetting = {
  pageRage: [],
  mediaSize: {},
  landscape: false,
  color: 2,
  headerFooterEnabled: false,
  marginsType: 0,
  isFirstRequest: false,
  requestID: getNextId(),
  previewModifiable: true,
  printToPDF: true,
  printWithCloudPrint: false,
  printWithPrivet: false,
  printWithExtension: false,
  deviceName: 'Save as PDF',
  generateDraftData: true,
  fitToPageEnabled: false,
  scaleFactor: 1,
  dpiHorizontal: 72,
  dpiVertical: 72,
  rasterizePDF: false,
  duplex: 0,
  copies: 1,
  collate: true,
  shouldPrintBackgrounds: false,
  shouldPrintSelectionOnly: false
}

3.列印邊距問題

列印的時候印表機會給紙張留一個預設邊距,如果是A4這樣的紙張幾乎可以忽略不計了,但是列印小規格紙張如50mm*50mm,這個邊距就十分明顯了,嚴重影響了整體佈局。

printToPdf方法提供了非常多的配置項,其中包括了配置列印邊距的引數,但是print方法卻沒有該配置項。

我們可以通過一項css配置來解決這個問題,即@page:

    @page {
      margin: 0px;
    }

通過此配置可靈活配置列印邊距。

還有一個css屬性@media print {}此配置是隻有在列印時才生效的css,控制的是列印邊距以內的css,並不能控制列印邊距。

4.列印方案

使用webcontent列印,首先要有一個列印視窗,這個視窗不能隨時列印隨時建立,比較耗費效能。可以將它在程式執行時啟動好,並做好事件監聽。

此過程需和呼叫列印的進行做好通訊:大致過程如下:

image

可見通訊非常繁瑣

使用webview進行列印可實現同樣的效果但是通訊方式會變得簡單,因為渲染程序和webview通訊不需要經過主程序,通過如下方式即可:

// In embedder page.
  const webview = document.querySelector('webview')
  webview.addEventListener('ipc-message', (event) => {
    console.log(event.channel)
    // Prints "pong"
  })
  webview.send('ping')
Copy
// 在訪客頁。
  const {ipcRenderer} = require('electron')
  ipcRenderer.on('ping', () => {
    ipcRenderer.sendToHost('pong')
  })

5.示例程式