electron-静默打印pdf文件

需求:  支持无感打印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>

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值