如何在PDF.JS中启用Annotations (替换pdf文本域的内容)

参考链接:https://usefulangle.com/post/94/javascript-pdfjs-enable-annotation-layer

1、添加一个<div>元素来保存注释层

<div id="annotation-layer"></div>

这个div将保存PDF页面的注释数据。PDF将在canvas中呈现。

<canvas id="pdf-canvas"></canvas>
<div id="annotation-layer"></div>

2、为注释层添加CSS

#annotation-layer {
  position: absolute;
  section {
    position: absolute;
    display: flex !important;
    align-items: center !important;
    div {
      white-space: pre;
      color: black;
      font-size: 12px !important;
      line-height: 1 !important;
    }
  }
}

3、获取PDF注释

在canvas中呈现PDF之后,您需要获得页面的注释数据,然后在注释层元素中呈现该数据。

方法getAnnotations()返回一个Promise,该Promise解析后返回页面的注释数据。render()将呈现注释层div中的数据。

完整代码:

<template>
  <div class="pdf-preview-container">
    <div
      v-for="page in docPages"
      :key="page"
      ref="container"
      class="page-container"
      :style="{
        height: `${pageHeight}px`,
      }"
    >
      <canvas v-if="renderList.includes(page)" id="pdf-canvas"> </canvas>
      <div id="annotation-layer"></div>
    </div>
  </div>
</template>

<script>
const pdfJS = require('pdfjs-dist/build/pdf')
const pdfjsWorker = require('pdfjs-dist/build/pdf.worker.entry')
pdfJS.GlobalWorkerOptions.workerSrc = pdfjsWorker

export default {
  props: {
    url: {
      type: String,
      required: true,
    },
    data: {
      type: Object,
      default: () => {},
    },
    customScroll: {
      type: Boolean,
      default: false,
    },
    offsetHeight: {
      type: Number,
      default: 0,
    },
  },
  data() {
    return {
      doc: null,
      docPages: 0,
      currentPage: 0,
      pageHeight: 0,
      renderList: [],
    }
  },
  watch: {
    url: {
      immediate: true,
      handler() {
        this.getPDFFile()
      },
    },
  },
  mounted() {
    if (!this.customScroll) {
      document.addEventListener('scroll', this.scroll)
    }
  },
  beforeDestroy() {
    document.removeEventListener('scroll', this.scroll)
  },
  methods: {
    async getPDFFile() {
      if (!this.url) return
      this.currentPage = 0

      const pdf = await pdfJS.getDocument(this.url)
      this.doc = pdf
      this.docPages = pdf._pdfInfo.numPages
      this.$emit('getDocPages', this.docPages)
      this.$nextTick(() => {
        this.docPages && this.scrollToPage(1)
      })
    },
    scrollToPage(pageNo) {
      if (this.currentPage === pageNo) return
      this.currentPage = pageNo
      const list = []
      for (let page = pageNo; page <= this.docPages; page++) {
        list.push(page)
      }
      this.$nextTick(() => {
        this.renderList = list
        this.renderList.forEach(page => {
          this.renderPage(page)
        })
      })
    },
    // 渲染page
    async renderPage(pageNo) {
      const page = await this.doc.getPage(pageNo)
      const container = this.$refs.container[pageNo - 1]
      if (!container) return
      const canvas = container.querySelector('#pdf-canvas')
      const annotationLayer = container.querySelector('#annotation-layer')

      if (!canvas || canvas.__rendered) return
      const ctx = canvas.getContext('2d')
      const dpr = window.devicePixelRatio || 1
      const bsr =
        ctx.webkitBackingStorePixelRatio ||
        ctx.mozBackingStorePixelRatio ||
        ctx.msBackingStorePixelRatio ||
        ctx.oBackingStorePixelRatio ||
        ctx.backingStorePixelRatio ||
        1
      const ratio = dpr / bsr
      const rect = container.getBoundingClientRect()
      const viewport = page.getViewport({ scale: 1 })
      const width = rect.width
      const height = (width / viewport.width) * viewport.height
      canvas.style.width = `${width}px`
      canvas.style.height = `${height}px`
      this.pageHeight = height
      canvas.height = height * ratio
      canvas.width = width * ratio
      ctx.setTransform(ratio, 0, 0, ratio, 0, 0)
      const scale = width / viewport.width
      const renderContext = {
        canvasContext: ctx,
        viewport: page.getViewport({ scale }),
      }
      page.render(renderContext)
      canvas.__rendered = true

      const annotations = await page.getAnnotations()
      // console.log(pageNo, annotations)
      for (const annotation of annotations) {
        if (this.data[annotation.fieldName]) {
          annotation.fieldValue = this.data[annotation.fieldName]
        }
      }
      annotationLayer.style.width = `${width}px`
      annotationLayer.style.height = `${height}px`
      annotationLayer.style.left = `${canvas.offsetLeft}px`
      annotationLayer.style.top = `${canvas.offsetTop}px`

      // Render the annotation layer
      pdfJS.AnnotationLayer.render({
        viewport: viewport.clone({ dontFlip: true, scale }),
        div: annotationLayer,
        annotations,
        page,
      })
    },
    scroll() {
      this.checkRender(document.documentElement)
    },
    checkRender(el) {
      if (!this.pageHeight) return
      let scrollTop = el.scrollTop
      if (el === document.documentElement) {
        scrollTop =
          el.scrollTop || window.pageYOffset || document.body.scrollTop
      }
      let page = Math.floor((scrollTop - this.offsetHeight) / this.pageHeight)
      page = Math.max(page, 1)
      page = Math.min(page, this.docPages)
      this.scrollToPage(page)
    },
  },
}
</script>

<style lang="scss">
#annotation-layer {
  position: absolute;
  section {
    position: absolute;
    display: flex !important;
    align-items: center !important;
    div {
      white-space: pre;
      color: black;
      font-size: 12px !important;
      line-height: 1 !important;
    }
  }
}
</style>

这里想要吐槽一下pdfjs的文档真是太不完善了,这个还是我研究了好几天源码才发现的功能。希望pdfjs能够把文档完善一下,要不用起来太不方便了o(╥﹏╥)o

 

posted @ 2022-05-18 15:24  放飞的回忆  阅读(4044)  评论(0)    收藏  举报