qrcode+jspdf前端打印标签

3,379 阅读2分钟

业务背景

需求是前端打印出一排2个、一排5个、圆标签等,各种样式的标签,并包含二维码、中英文、数字, 如下图:

094a12ae8b69c45d9099c2540c5ca587.jpg 对于打印机来讲,一排就是一页,想要打印出这样的标签,步骤如下:

  1. 确认前端打印功能
  2. 计算每个标签在一页中的位置
  3. 每个标签中打印二维码
  4. 打印英文和数字
  5. 打印中文

方案确认

首先确定jspdf作为前端打印插件,jspdf的文档很细,功能强大,是一个优秀的框架,但是默认不支持中文,需要额外引入字体,最开始想通过html2canvas的方法把页面的中文通过dom生成图片再使用jspdf打印出来的方案,后来发现打印出来的文字很不清晰,清晰度的问题难以解决,所以就只能换成直接使用jspdf直接生成文字的方式处理,就是必须要引入字体文件。

实现方法

一、引入jspdf和qrcode

// 下载包, 本文使用jspdf@2.3.1
npm install jspdf qrcode

// 引入
import jsPDF from 'jspdf'
var QRcode = require('qrcode')

二、确定标签尺寸和纸张尺寸, 配置jspdf

以一排5个为例,使用的纸张尺寸是87 * 33, 标签尺寸是 15 * 30

const pdf = new jsPDF('l', 'mm', [870, 330])

// 声明一套配置
const printConfig = { 
    pageWidth: 870, // 一页宽度
    pageHeight: 330, // 一页的高度
    left: 35, // 标签左边距
    offsetLeft: 174, // 每个标签的偏移量
    top: 25, // 标签上间距
    picWidth: 100, // 二维码宽度
    picHeight: 100, // 二维码高度
    linePicNum: 5, // 一排显示个数
    rotateDeg: 270, // 角度
    fontSize: 58 // 字号
}

三、生成二维码并在指定位置打印

const imageList = []

// 声明一个imageList用了存放二维码base64
list.map((item, index) => {
  QRCode.toDataURL(item.code)
  .then(url => {
    imageList.push(url)
  })
  .catch(err => {
    console.error(err)
  })
})

// 打印二维码图片
let left = printConfig.left
let top = printConfig.top
imageList.map(base64 => {
  left = printConfig.left + printConfig.offsetLeft * (index % printConfig.linePicNum)
   // 添加图片
  pdf.addImage(base64, 'JPEG', left, top, picWidth, picHeight, '', 'FAST')
  
  // 超过限制个数就翻页
  if (index !== 0 && (index + 1) % printConfig.linePicNum === 0 && index < imageList.length - 1 ) {
    pdf.addPage([width,  height], 'l')
  }
})

这样可以在指定位置打印出二维码了

三、打印英文和数字

jspdf直接可以打印英文和数字,所以直接打印即可, left和top是需要增加偏移量的

 pdf.text('this is my word', left + item.offsetLeft, top + item.offsetTop, {angle: printConfig.rotateDeg})

四、打印中文

中文的引入会麻烦一些,需要引入语言包,具体生成方法可以参考官网,或参考 www.cnblogs.com/ww01/p/1149…

先找到ttf文件后convert成一个js,将生成的js放到文件中

function addfont(pdf) {
    var font = 'AA****' // 中的就是ttf转化成的编码
    pdf.addFileToVFS('bolds', font)
    return true;
}
// 在pdf生成后,添加并设置字体
addfont(pdf)
pdf.addFont('bolds', 'customFont', 'normal')
pdf.setFont('customFont')
pdf.setFontSize(58)

//打印
pdf.text('我是中文', left + item.offsetLeft, top + item.offsetTop, {angle: printConfig.rotateDeg})

完整代码

以下是我封装的打印方法, 外部直接调用generatePrint即可

import jsPDF from 'jspdf'
var QRCode = require('qrcode')

let width, height;
let pdf;
let timer

class PrintTag {
  constructor(data) {
    this.imageList = []
    this.list = data
    this.printConfig = { 
        pageWidth: 870, // 一页宽度
        pageHeight: 330, // 一页的高度
        left: 35, // 标签左边距
        offsetLeft: 174, // 每个标签的偏移量
        top: 25, // 标签上间距
        picWidth: 100, // 二维码宽度
        picHeight: 100, // 二维码高度
        linePicNum: 5, // 一排显示个数
        rotateDeg: 270, // 角度
        fontSize: 58 // 字号
    }
    this.setPdfConfig()
  }
  start() {
    this.buildQRcode()
  }
  // 设置pdf
  setPdfConfig() {
    width = this.printConfig.pageWidth
    height = this.printConfig.pageHeight
    pdf = new jsPDF('l', 'mm', [width,  height])
    //添加并设置字体
    addfont(pdf)
    pdf.addFont('bolds', 'customFont', 'normal')
    pdf.setFont('customFont')
    pdf.setFontSize(58)
  }
  // 生成二维码
  buildQRcode() {
    this.list.map((item, index) => {
      QRCode.toDataURL(item.sampleIdLims)
      .then(url => {
        this.imageList.push(url)
      })
      .catch(err => {
        console.error(err)
      })
    })
    this.checkImageLoaded()
  }
  // qrcode是异步,所以延迟生成pdf
  checkImageLoaded() {
    setTimeout(() => {
      if (this.imageList.length === this.list.length) {
        this.generate(this.imageList)
      }
    }, 500)
  }
  // 生成pdf
  generate(arr) {
    console.time('print')
    const picWidth = this.printConfig.picWidth
    const picHeight = this.printConfig.picWidth
    let left = 0
    let top = this.printConfig.top
    const textOpt = {angle: this.printConfig.rotateDeg}

    arr.map((base64, index) => {
      left = this.printConfig.left + this.printConfig.offsetLeft * (index % this.printConfig.linePicNum)
      pdf.addImage(base64, 'JPEG', left, top, picWidth, picHeight, '', 'FAST')
      pdf.text('hello 12345', left + item.offsetLeft, top + item.offsetTop, textOpt)
      pdf.text('我说中文', left + item.offsetLeft, top + item.offsetTop + 25, textOpt)
       
      if (index !== 0 && (index + 1) % this.printConfig.linePicNum === 0 && index < arr.length - 1 ) {
        pdf.addPage([width,  height], 'l')
      }
    })
    
    window.open(pdf.output('bloburl'), '_blank');
    console.timeEnd('print')
  }
}

export function generatePrint(data, step, lableType) {
  console.log(data, step)
  return new PrintTag(data, step, lableType).start()
}