使用nodejs(ipp和html-pdf-node)实现连接打印机后端静默打印html文件

使用nodejs实现连接打印机后端静默打印

需求

  • 标签打印需要进行静默打印,前端主要直接生成html文件,此时需要调用接口进行打印

需求分析

  1. 由于前端直接生成的模板是html文件,此时可以根据不同情况进行打印

(1)打印的类型:

  • 直接传输 html 网页链接

  • 直接传输 html 文件的 base64 编码

  • 直接传输 pdf 文件的 base64 编码

(2)适应纸张大小,获取纸张尺寸,网页进行缩放

  • 纸张尺寸:纸张长、纸张宽

  • 网页缩放的比例:用于适应打印大小(范围:0.1-2)

(3)支持多份打印:

  • 可传打印份数(大于等于1)

(4)支持页数打印:

  • 可通过 '1-5,7-9,11’的形式指定打印页号

(5)最终以pdf形式打印

知识点补充

  1. 由于需求是打印html文件,所以需要分割页面,这里转成pdf就相当于预览打印了(多少页,每一页多大尺寸,打印几页都可以控制了)
  2. html转成pdf使用了依赖 html-pdf-node
  3. 使用打印协议(同样是依赖)ipp 通过网络打印非常便捷,重点是不需要安装驱动
  4. 介绍一下 ipphtml-pdf-node
  • ipp

    • 可以通过npm i ipp安装

    • 创建打印实体 const printer = ipp.Printer('http://【PrinterIp】:631')

      • 这里的PrintIp是可以在配置打印机的地方查看的,631端口就默认放着(和配置打印机的端口无关)打印机配置找打印机ip
    • 这里可以访问打印机的几种操作,根据实际情况使用,传输的配置参数可以根据源码测试

      • 获取打印机属性 'Get-Printer-Attributes'
      • 打印工作'Print-Job'
        打印机操作
    • 有了操作,在打印时简单的做法就是,先获取打印机属性,可以获取到说明打印机可连接,那么就打印吧(细节可以在测试时调整)

    • 打印文件的类型,可以通过获取打印机的属性看到所有打印文件格式,比如

      • "document-format": "application/pdf",
      • 打印格式
    • 打印返回的结果,一般这样的结果都是正常的
      正常返回

  • html-pdf-node

    • 可以通过npm i html-pdf-node 安装
    • 这个函数传入html文件内容或urlhtml_to_pdf.generatePdf(file, options)
      • 参数传入的html文件内容是字符串类型,fs.readFile返回的是Buffer类型的,记得toString()一下转成字符串
      • 也可以传入html链接
      • 这个函数返回的也是Buffer类型,刚好打印的数据传入也需要Buffer类型的,皆大欢喜

实现接口

  1. 接口:http://ip:3001/CommonUtilsApi/PrintFile

  2. 模型:PrintHtmlDto

  3. 源码:

import * as ipp from 'ipp'
import * as html_to_pdf from 'html-pdf-node'
  //打印文件
  printFile(dto:PrintHtmlDto):Promise<boolean>{
    return new Promise((_res,_rej)=>{
      try{
        const validMsg = this.validationPrintDto(dto)
        if(validMsg != '') _rej(validMsg);
        const printer = ipp.Printer(`http://${dto.PrinterIp}:631`)
        var msg = {
          "operation-attributes-tag": {
              'attributes-charset': 'utf-8',
              "requesting-user-name": "666",
              "job-name": "testPrint666",
              "document-format": "application/pdf",
          },
          "job-attributes-tag":{
          //   // 'orientation-requested':'reverse-portrait',
          //   // 'page-ranges':'1', 
          //   // 'print-scaling':'auto-fit', //打印缩放
            'copies':dto.PageCopies,//打印份数
          },
        };
        //区分类型
        switch (dto.TemplateFileType) {
          case TPL_FILE_TYPE.htmlFile:{
            //data:text/html;base64,
            const htmlFile = dto.TemplateFileStream;
            if(htmlFile.startsWith('data:application/pdf;base64,')){
              let base64Data = htmlFile.split(';base64,').pop();
              const dataBuffer = new Buffer(base64Data, 'base64')
              msg['data'] = dataBuffer;
              //打印html文件(文件流)
              this.printHtmlFile(dto,printer,msg).then(()=>{
                _res(true);
              }).catch(err=>{
                _rej(err);
              })
            }else{
              _rej(`${dto.TemplateFileType}类型的文件必须传输的是base64的编码类型!`)
            }
          }break;
          case TPL_FILE_TYPE.htmlLink:{
            if(dto.TemplateFileStream && (dto.TemplateFileStream.startsWith('https://') || dto.TemplateFileStream.startsWith('http://'))){
              this.printByHtmlLink(dto,printer,msg).then(()=>{
                _res(true)
              }).catch(err=>{
                _rej(err)
              })
            }else{
              _rej(`${dto.TemplateFileType}类型必须传网页链接!`)
            }
          }break;
          case TPL_FILE_TYPE.pdfFile:{
            const pdfFile = dto.TemplateFileStream;
            if(pdfFile.startsWith('data:application/pdf;base64,')){
              let base64Data = pdfFile.split(';base64,').pop();
              const dataBuffer = new Buffer(base64Data, 'base64')
              msg['data'] = dataBuffer;
              this.printPDFFile(printer,msg).then(()=>{
                _res(true)
              }).catch(err=>{
                _rej(err)
              })
            }else{
              _rej(`${dto.TemplateFileType}类型的文件必须传输的是base64的编码类型!`)
            }
          }break;
          default: _rej('暂不支持该文件类型的打印任务!')
            break;
        }
      }catch(err){
        _rej(err)
      }
    })
  }

  //打印pdf文件
  printPDFFile(printer,msg):Promise<boolean>{
    return new Promise((_res,_rej)=>{
      try{
        // console.log("打印文件msg",msg);
        // _res(true)
        // writeFileSync(join(__dirname,'../../src/common-utils/data/luckysheet.pdf'),msg.data)
        if(msg.data){
          printer.execute("Get-Printer-Attributes", msg, function(err, res){
            if(!err && res['statusCode'] && res['statusCode'] == 'successful-ok'){
               printer.execute("Print-Job", msg, function(err, res){
                 if(err)_rej("打印失败!"+err)
                 _res(true)
               })
            }else{
              _rej('未获取到打印机状态,请检查打印机是否存在'+err)
            }
          })
        }else{
          _rej('打印内容不能为空!')
        }
      }catch(err){
        _rej('未获取到打印机状态,请检查打印机是否存在!'+err)
      }
    })
  }
  
  //打印网页(链接)
  printByHtmlLink(dto:PrintHtmlDto,printer,msg):Promise<boolean>{
    return new Promise((_res,_rej)=>{
      try{
        let options = { 
          width:dto.PageWidth?dto.PageWidth:'297mm',
          height:dto.PageHeight?dto.PageHeight:'210mm',//这里的宽高设置,用于确定纸张尺寸
          scale:dto.Scale?dto.Scale:1,
          pageRanges:dto.PageRanges?dto.PageRanges:"1"
        };
        let file = { url: dto.TemplateFileStream };
        html_to_pdf.generatePdf(file, options).then(pdfBuffer => {
          // console.log("PDF Buffer:-", pdfBuffer);
          // writeFileSync(join(__dirname,'../../src/common-utils/data/cc.pdf'),pdfBuffer)
          msg.data = pdfBuffer;
          this.printPDFFile(printer,msg).then(()=>{
            _res(true)
          }).catch(err=>{
            _rej(err)
          })
        }).catch(err=>{
          _rej(err)
        })
      }catch(err){
        _rej(err)
      }
    })
  }

  //打印html文件
  printHtmlFile(dto:PrintHtmlDto,printer,msg):Promise<boolean>{
    return new Promise((_res,_rej)=>{
      try{
        let options = { 
          width:dto.PageWidth,
          height:dto.PageHeight,//这里的宽高设置,用于确定纸张尺寸
          scale:dto.Scale,
          pageRanges:dto.PageRanges
        };
          let file = { content: msg.data.toString() };
          html_to_pdf.generatePdf(file, options).then(pdfBuffer => {
            // console.log("PDF Buffer:-", pdfBuffer);
            msg.data = pdfBuffer;
            this.printPDFFile(printer,msg).then(()=>{
              _res(true)
            }).catch(err=>{
              _rej(err)
            })
          }).catch(err=>{
            _rej(err)
          })
      }catch(err){
        _rej(err)
      }
    })
  }

  //验证打印参数是否合法
  validationPrintDto(dto:PrintHtmlDto){
    if(!dto.PrinterIp) return '请输入打印机的Ip!'
    if(dto.Scale<0.1 || dto.Scale>2) return '缩放比例范围不能超过0.1-2!';
    if(dto.PageHeight && dto.PageWidth){
      const width = dto.PageWidth
      const height = dto.PageHeight
      const unitW = width.substring(width.length-2,width.length);
      const unitH = height.substring(width.length-2,width.length);
      if(unitW !== 'mm' || unitH != 'mm') return '尺寸必须添加mm单位!'
      if(Number(width.substring(0,width.length-2))<=1 || Number(height.substring(0,width.length-2))<=1 ) return '尺寸必须大于1mm!'
    }else{
      return '请添加纸张尺寸'
    }
    if(dto.PageCopies && dto.PageCopies<1) return '打印份数必须>1!'
    if(String(dto.PageCopies).indexOf('.')>-1) return '打印份数不能是小数!'
    if(!dto.PageRanges && dto.TemplateFileType != TPL_FILE_TYPE.pdfFile)return `请输入打印范围(格式: '1-2,6,7-9')!`
    return '';
  }
}
  • 5
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在 Node.js实现 Scratch Link 串口通讯,需要使用 `serialport` 模块。下面是一些基本的代码示例,你可以根据自己的需求进行修改和扩展: ```javascript const SerialPort = require('serialport'); const Readline = require('@serialport/parser-readline'); const parser = new Readline(); // 创建串口连接 const port = new SerialPort('/dev/ttyACM0', { baudRate: 115200 }); // 监听串口连接事件 port.on('open', () => { console.log('串口连接已打开'); }); // 监听串口数据事件 port.pipe(parser); parser.on('data', data => { console.log(`收到数据:${data}`); }); // 发送数据到串口 function sendToSerial(data) { port.write(data, err => { if (err) { console.log('发送数据失败:', err.message); } else { console.log(`已发送数据:${data}`); } }); } // 示例:发送命令到 Scratch Link sendToSerial('{"jsonrpc":"2.0","id":1,"method":"scratch.extensions.openConnection","params":{}}\n'); ``` 这个示例假设你已经安装了 `serialport` 和 `@serialport/parser-readline` 模块,可以使用以下命令进行安装: ``` npm install serialport @serialport/parser-readline ``` 在上面的示例代码中,我们创建了一个串口连接,并监听了它的 `open` 事件和数据接收事件。`sendToSerial` 函数可以将数据发送到串口,你可以根据需要修改这个函数的实现方式。 最后,我们还提供了一个示例,演示如何发送命令到 Scratch Link。你可以根据 Scratch Link 的 API 文档编写自己的命令,并使用 `sendToSerial` 函数发送它们。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值