需求: 支持无感打印pdf文件, 支持mac, win两个终端
说明: 一般打印机不支持直接打印word文件, 而电脑上的在word文档中打印其实也是内部转成了pdf才能打印的, 所以如果你的需求要支持打印word, 可以让后端作为中间人, 先把word转化为pdf, 再打印
在网上看了很多相关的经验, 都是找的第三方的工具, 例如SumatraPDF, 但是这个工具不支持mac端, 直接pass, 有的是直接在页面上打开pdf, 从而打印web页面, 如果pdf文件一旦过大, 就没办法打印全部了, 隐患太大
方案: 通过pdf.js在print.html预览, 监听渲染完成后实现静默打印
// main.js
// 打印方法
function printHandle ({ BrowserWindow, arg, socket, printInfo, urlData, mainWindow }) {
const printWin = new BrowserWindow({
webPreferences: {
//关闭web权限检查,允许跨域
webSecurity: false,
// 是否启用Node 环境
nodeIntegration: true,
enableRemoteModule: true,
contextIsolation: false,
plugins: true,
images: true,
allowRunningInsecureContent: true,
webviewTag: true,
navigateOnDragDrop: true,
zoomFactor: 1.0
},
minWidth: 1580,
minHeight: 720,
backgroundColor: '#f5f5f5',
frame: false,
show: false
})
// 因为拿到的是文件服务上的地址, 所以先获取pdf二进制内容
require('http').get('文件服务上的远程pdf地址', { encoding: null }, res => {
let img = []
let size = 0
res.on('data', chunk => {
img.push(chunk)
size += chunk.length
})
res.on('end', () => {
const buffer = Buffer.concat(img, size)
// 获取到内容啦, 写文件
fs.writeFile(path.join(app.getPath('userData'), 'print.pdf'), buffer, function (err) {
// 如果err为true,则文件写入失败,并返回失败信息
if (err) {
return socket.emit('print-succ', { code: 1000, message: '打印失败, 请重试', data: err })
}
// 只触发一次的事件
// 监听print.html页面渲染pdf完成事件
ipcMain.once('getLandscape', (winEvent, bool, pageNum) => {
printInfo.landscape = bool
console.log(pageNum, bool)
printWin.webContents.print(
{
silent: true, // 是否不向用户询问设置
printBackground: false, // 打印网页的背景颜色和图像
deviceName: electronStore.get('printName'), // 打印设备的名称
pageSize: 'A4',
landscape: printInfo.landscape, // 是否横向打印
margins: {
marginType: 'printableArea' // 可打印区域
}
},
(success, failureReason) => {
const result = {
code: success ? 0 : 1000,
message: !failureReason ? '已将数据发送给打印机, 请关注打印机状态。' : '打印失败'
}
socket.emit('print-succ', result)
fs.unlinkSync(path.join(app.getPath('userData'), 'print.pdf'))
printWin.destroy() // 打印完成后终止程序
}
)
})
// 暂时解决打印程序卡死问题
setTimeout(() => {
if (printInfo.isPrint == true) {
printInfo.isPrint = false
if (printWin) printWin.destroy()
socket.emit('print-succ', { code: 1000, message: '打印超时! 请关注打印机状态' })
}
}, 25000)
// 加载静态文件中的print页面
printWin.loadURL(path.join(`${__static}`, 'print.html'))
})
})
})
}
<!-- 这是放在static中的print.html页面 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
<!-- 一定要设置样式, 不然打印有空白页 -->
@page {
size: auto;
margin: 3mm;
}
html {
background-color: #ffffff;
margin: 0px;
}
body {
border: solid 1px #ffffff;
margin: 10mm 15mm 0mm 8mm;
}
</style>
<script src="./build/pdf.min.js"></script>
</head>
<body>
<div id="container">
<!-- <canvas id="the-canvas1"></canvas>
<canvas id="the-canvas2"></canvas> -->
</div>
<script type="text/javascript">
const ipc = require('electron').ipcRenderer
const remote = require('electron').remote
const path = require('path')
var exePath = path.join(remote.app.getPath('userData'), 'print.pdf')
async function renderPDF() {
let url = exePath
// console.log(url, 'url')
const loadingTask = pdfjsLib.getDocument({
url: url,
cMapUrl: './build/cmaps/',
cMapPacked: true
})
const canvasContainer = document.getElementById('container')
const pdf = await loadingTask.promise
async function renderPage(page) {
let canvas = document.createElement('canvas')
canvasContainer.appendChild(canvas)
const currentPage = await pdf.getPage(page)
const scale = 1.5
const viewport = currentPage.getViewport({ scale })
const outputScale = window.devicePixelRatio || 1
// let canvas = document.getElementById('the-canvas'+ page)
const context = canvas.getContext('2d')
canvas.width = Math.floor(viewport.width * outputScale)
canvas.height = Math.floor(viewport.height * outputScale)
canvas.style.width = Math.floor(viewport.width) + 'px'
canvas.style.height = Math.floor(viewport.height) + 'px'
if (page == 1) {
// 根据pdf的宽度设置打印机的横纵向
// ipc.send('getLandscape', canvas.width > canvas.height ? true : false, pdf.numPages);
}
const transform = outputScale !== 1 ? [outputScale, 0, 0, outputScale, 0, 0] : null
const renderContext = {
canvasContext: context,
transform,
viewport
}
await currentPage.render(renderContext).promise
}
console.log(pdf.numPages, 'pdf.numPages')
for (let num = 1; num <= pdf.numPages; num++) {
await renderPage(num)
if (num === pdf.numPages) {
const canvasDom = document.querySelectorAll('canvas')
ipc.send('getLandscape', canvasDom[0].width > canvasDom[0].height ? true : false, pdf.numPages)
}
}
}
renderPDF()
</script>
</body>
</html>