html2canvas、jspdf结合实现pdf合成,生成多页pdf技术实现

481 阅读1分钟

背景:

在实际工作中往往只需要预览pdf,可以使用pdfjs-dist这个库来实现预览、解析的功能。但是我遇到过基于原始pdf重新合成新的pdf的功能,在元素pdf上面拖拽一些控件元素,类似checkbox,并且在上面打勾,打勾完成以后需要重新合成一个新的pdf。众所周知,pdf上面只能预览无法编辑。以下只展示核心代码:

1、根据A4纸的大小,等比计算pdf每页的宽高。并使用html2canvas截长图并分页,最后生成新的pdf

async function convertToPDF() {
    const element = scrollContainer.value as HTMLElement
    const A4_WIDTH = 592.28
    const A4_HEIGHT = 841.89
    const canvas = await html2canvas(element, {
      scale: window.devicePixelRatio || 3,
      width: element.offsetWidth,
      height: element.offsetHeight,
      useCORS: true
    })
    const canvasWidth = canvas.width
    const canvasHeight = canvas.height
    // html页面实际高度
    let htmlHeight = canvasHeight

    // 页面偏移量
    let position = 0

    // 根据A4纸的宽高等比计算pdf页面对应的高度
    const pageHeight = (canvasWidth * A4_HEIGHT) / A4_WIDTH

    // html页面生成的canvas在pdf中图片的宽高
    const imgWidth = A4_WIDTH
    const imgHeight = (A4_WIDTH * canvasHeight) / canvasWidth
    const imageData = canvas.toDataURL("image/png", 1.0)
    const pdf = new jsPDF("p", "pt", "a4")
    // html页面的实际高度小于生成pdf的页面高度时,即内容未超过pdf一页显示的范围,无需分页
    if (htmlHeight <= pageHeight) {
      pdf.addImage(imageData, "PNG", 0, 0, imgWidth, imgHeight)
    } else {
      // 内容超过一页时,需要分页
      while (htmlHeight > 0) {
        pdf.addImage(imageData, "PNG", 0, position, imgWidth, imgHeight)
        // 更新高度与偏移量
        htmlHeight -= pageHeight
        position -= A4_HEIGHT
        if (htmlHeight > 0) {
          // 在PDF文档中添加新页面
          pdf.addPage()
        }
      }
    }
    return pdf.output("blob")
  }

2、生成blob流以后,使用axios上传到服务器上,具体逻辑根据业务调整,以下只展示粗略代码:

async function uploadFile(blob) {
    const randomKey = generateRandomKey()
    let params = new FormData()
    params.append("file", blob, `${randomKey}`)
    try {
      let res = await axios.post(`https://obs.${suffix}/api/dc/storage/standard/upload`, params)
      if (!res.data.isError) {
        return res.data.data.ossUrl
      }
    } catch (err) {
      Toast("上传失败,请稍后再试!")
    }
  }