Electron 静默打印

源码

打印HTML格式

main进程中

const path = require('path')
const {BrowserWindow, app, ipcMain} = require('electron')

const isPrdEnv = process.env.NODE_ENV === 'production'
const staticPath = isPrdEnv ? './static' : '../../../../static' // 根据当前代码的js相对static文件夹路径

let printWindow = null
const url = `file://${path.resolve(__dirname, `${staticPath}/print.html`)}`

app.whenReady().then(() => {
    printWindow = new BrowserWindow({
        show: false,
        webPreferences: {
            nodeIntegration: true,
            contextIsolation: false
        }
    })
    printWindow.loadURL(url)
})

/**
 * 静默打印html
 * @Param content Html字符串
 * @Param deviceName 打印机名称
 * @return promise
 * */
const htmlToPrint = (content, deviceName, margin) => {
    return new Promise((resolve, reject) => {
        if (!printWindow) return reject('请等待控件加载完成后重试')
        const htmlPrintingListener = () => {
            printWindow.webContents.print({
                silent: true,
                printBackground: false,
                deviceName
            }, (success, failureReason) => {
                ipcMain.removeListener('htmlPrinting', htmlPrintingListener)
                if (success) resolve(true)
                else reject('打印失败')
            })
        }

        printWindow.webContents.send('htmlPrint', { content, margin, deviceName })
        ipcMain.on('htmlPrinting', htmlPrintingListener)
    })
}


export default htmlToPrint

static文件夹下新建print.html键入以下代码

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Document</title>
</head>

<body>
<div id='container'></div>
</body>
<script>
    //引入ipcRenderer对象
    const { ipcRenderer } = require('electron')
    ipcRenderer.on('htmlPrint', (e, content) => { //接收响应
        document.querySelector('#container').innerHTML = content
        ipcRenderer.send('htmlPrinting') //向webview所在页面的进程传达消息
    })
</script>
</html>

打印网络PDF

打印本地PDF同理更简单, 未作兼容性处理,详细请看这篇文章,这里需要借助一个第三方软件SumatraPDF 去官网下压缩包解压后放到static文件夹下就行

main进程中


const path = require('path')
const https = require('https')
const fs = require('fs')
const cp = require('child_process')

const isPrdEnv = process.env.NODE_ENV === 'production'
const staticPath = isPrdEnv ? './static' : '../../../../static' // 根据当前代码的js相对static文件夹路径

/*
* 处理await 的异常捕获
* */
const awaitWrapper = promise => promise.then(result => [null, result]).catch(error => [error, null])

/*
* 生成随机字符串
* */
const randomString = () => Math.random().toString(36).slice(-6)

/*
* 获取网络pdf的buffer
* */
const getFileBuffer = url => {
    return new Promise(((resolve, reject) => {
        https.get(url, response => {
            const chunks = []
            let size = 0
            response.on('data', chunk => {
                chunks.push(chunk)
                size += chunk.length
            })
            response.on('end', () => {
                const buffer = Buffer.concat(chunks, size)
                resolve(buffer)
            })
        })
    }))
}

/*
* 将buffer保存为本地临时文件
* */
const savePdf = buffer => {
    return new Promise((resolve, reject) => {
        const pdfUrl = path.resolve(__dirname, `${staticPath}/${randomString()}.pdf`)
        fs.writeFile(pdfUrl, buffer, {encoding: 'utf8'}, err => {
            if (err) {
                reject('缓存pdf打印文件失败')
            } else {
                resolve(pdfUrl)
            }
        })
    })
}

/*
* 调用SumatraPDF 执行pdf打印
* */
const executePrint = (pdfPath, deviceName) => {
    return new Promise((resolve, reject) => {
        cp.exec(`SumatraPDF.exe -print-to "${deviceName}"  "${pdfPath}"`,
            {
                windowsHide: true,
                cwd: path.resolve(__dirname, staticPath)
            },
            e => {
                if (e) {
                    reject(`${url}在${deviceName}上打印失败`)
                } else {
                    resolve(true)
                }
                /* 打印完成后删除创建的临时文件 */
                fs.unlink(pdfPath, Function.prototype)
            })
    })
}

/*
* 静默打印pdf
* */
const pdfToPrint = (url, deviceName) => {
    return new Promise(async (resolve, reject) => {
        /* 根据url获取buffer并返回,如果获取失败就直接reject */
        const [bufferError, buffer] = await awaitWrapper(getFileBuffer(url))
        if (bufferError) return reject('获取网络pdf文件信息失败')
        /* 根据buffer将文件缓存到本地并返回临时pdf文件路径,如果存储失败就直接reject */
        const [pdfPathError, pdfPath] = await awaitWrapper(savePdf(buffer))
        if (pdfPathError) return reject(pdfPathError)
        /* 根据临时pdf文件路径 和打印机名称来执行打印*/
        const [execPrintError, printResult] = await awaitWrapper(executePrint(pdfPath, deviceName))
        if (execPrintError) {
            reject(execPrintError)
        } else {
            resolve(printResult)
        }
    })
}

关键事项

package.json中

1.打包static目录的文件没有打包进去,需要在package.json 里面添加extraResources 额外资源
2.打包后远程下载pdf无法放入/static下,原因是electron-vue 默认是用asar打包,而asar只能读取不能写入,所以需要远程打印pdf就不能打包成asar

   "win": {
         "icon": "dist/electron/static/icon2.ico",
         "extraResources": [
            "./static/*.html",
            "./static/*.txt",
            "./static/*.exe",
            "./static/*.pdf"
         ],
         "asar": false
    }
posted @ 2021-02-26 10:13  demo_you  阅读(2089)  评论(1编辑  收藏  举报