当前位置:   article > 正文

vue3中借助 pdfjs-dist 实现pdf文件展示、文本选中功能及使用过程中部分问题处理

pdfjs-dist

其他方法实现:vue3中使用 vue-pdf-embed 实现pdf文件预览、翻页、下载等功能

一、文件预览

1、安装 pdfjs-dist ,此处指定版本为 2.16.105

yarn add pdfjs-dist@2.16.105

注:3.x版本部分功能的实现方法与旧版本存在差异。

2、html 结构内容

<template>
    <div id="pdf-view">
        <canvas v-for="page in state.pdfPages" :key="page" id="pdfCanvas" />
        <div id="text-view"></div>
    </div>
</template>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

3、js 功能实现:

<script setup>
import * as pdfjsViewer from 'pdfjs-dist/web/pdf_viewer.js'
import 'pdfjs-dist/web/pdf_viewer.css'
import * as PDF from 'pdfjs-dist'

// 文件路径
import pdf from './2020试卷.pdf';

import { ref, reactive, onMounted, nextTick } from 'vue';

const state = reactive({
    // 文件路径
    pdfPath: pdf, 
    // 总页数
    pdfPages: 1, 
    // 页面缩放
    pdfScale: 2, 
})

onMounted(() => {
    loadFile(state.pdfPath)
});

let pdfDoc = null;

function loadFile(url) {
    PDF.getDocument({
        url,
        cMapUrl: 'https://cdn.jsdelivr.net/npm/pdfjs-dist@2.16.105/cmaps/',
        cMapPacked: true,
    }).promise.then((pdf) => {
        pdfDoc = pdf
        // 获取pdf文件总页数
        state.pdfPages = pdf.numPages
        nextTick(() => {
            renderPage(1) // 从第一页开始渲染
        })
    })
}

function renderPage(num) {
    pdfDoc.getPage(num).then((page) => {
        const canvas = document.getElementById('pdfCanvas')
        const ctx = canvas.getContext('2d')
        const viewport = page.getViewport({ scale: state.pdfScale })
        canvas.width = viewport.width
        canvas.height = viewport.height
        const renderContext = {
            canvasContext: ctx,
            viewport
        }
        page.render(renderContext)
    })
}
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55

如果要一次性展示全部页面的话,可以将代码修改成:

<template>
    <div id="pdf-view">
        <canvas v-for="page in state.pdfPages" :key="page" :id="`page-${page}`" />
        <div id="text-view"></div>
    </div>
</template>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

修改页面渲染函数:

<script setup>
function renderPage(num) {
    pdfDoc.getPage(num).then((page) => {
        // 绑定 id 值对应的元素
        const canvas = document.getElementById(`page-${num}`);
        ...
        page.render(renderContext);
        // state.pdfPages 为 pdf 文件总页数
        if (num < state.pdfPages) {
            renderPage(num + 1);
        }
    });
}
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

注意: 一次性渲染全部页面可能会出现加载缓慢或卡顿的问题,可以需要做相应的优化。

4、可能出现的问题

(1) 部分字体出现乱码或浏览器控制台出现警告

浏览器警告:

浏览器警告

解决方案:

getDocument 方法中追加 cMapUrlcMapPacked 参数:

PDF.getDocument({
    url,
    cMapUrl: 'https://cdn.jsdelivr.net/npm/pdfjs-dist@2.16.105/cmaps/',
    cMapPacked: true,
})
  • 1
  • 2
  • 3
  • 4
  • 5

注:cMapUrl 参数可指定为本地文件路径,可在路径 node_modules/pdfjs-dist/cmaps 中获取。通过测试发现,该警告即便不处理依然不影响页面展示,但是在后续的文本选中功能上可能会受影响。

二、文本选中

1、功能实现

在文件预览的基础上添加以下代码:

import { TextLayerBuilder } from 'pdfjs-dist/web/pdf_viewer.js';
const pdfjsWorker = import('pdfjs-dist/build/pdf.worker.entry')
PDF.GlobalWorkerOptions.workerSrc = pdfjsWorker

const eventBus = new pdfjsViewer.EventBus();

function renderPage(num) {
    pdfDoc.getPage(num).then((page) => {
        ...
        const renderContext = {
            ...
        }
        // page.render(renderContext)

        // 获取文本内容和渲染页面的 Promise
        const getTextContentPromise = page.getTextContent();
        const renderPagePromise = page.render(renderContext);

        Promise.all([getTextContentPromise, renderPagePromise])
            .then(([textContent]) => {
                const textLayerDiv = document.createElement('div');
                // 注意:此处不要修改该元素的class名称,该元素的样式通过外部导入,名称是固定的
                textLayerDiv.setAttribute('class', 'textLayer');
                // 设置容器样式
                textLayerDiv.setAttribute('style', `
                    z-index: 1;
                    opacity: 1;
                    background-color:#fff;
                    transform: scale(1.1);
                    width: 100%,
                    height: 100%,
                `);
                // 设置容器的位置和宽高
                textLayerDiv.style.left = canvas.offsetLeft + 'px';
                textLayerDiv.style.top = canvas.offsetTop + 'px';
                textLayerDiv.style.height = canvas.offsetHeight + 'px';
                textLayerDiv.style.width = canvas.offsetWidth + 'px';

                const textView = document.querySelector('#text-view');
                textView.appendChild(textLayerDiv);

                const textLayer = new TextLayerBuilder({
                    // container: ,
                    textLayerDiv: textLayerDiv,
                    pageIndex: page.pageIndex,
                    viewport: viewport,
                    eventBus,
                    // textDivs: []
                });

                textLayer.setTextContent(textContent);
                textLayer.render();
            }) 
            .catch((error) => {
                console.error('Error rendering page:', error);
            })
    })
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58

2、可能出现的问题:

(1) 页面文字可选中,但文本不可见

通过测试发现,将 pdfjs-dist/web/pdf_viewer.css 路径下的 color 属性注释后可显示文本。

.textLayer span,
.textLayer br {
  /* color: transparent; */
  position: absolute;
  white-space: pre;
  cursor: text;
  transform-origin: 0% 0%;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

其他参考资料:https://github.com/mozilla/pdf.js/issues/11509

(2) 浏览器控制台报错 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'dispatch')

浏览器报错:

浏览器报错

解决方案:

通过上网查找资料得知,需在 TextLayerBuilder 中追加参数 eventBus

const eventBus = new pdfjsViewer.EventBus();

function renderPage(num) {
    pdfDoc.getPage(num).then((page) => {
        ...
    Promise.all([getTextContentPromise, renderPagePromise])
        .then(([textContent]) => {
                    ...
        const textLayer = new TextLayerBuilder({
            ...
            eventBus,
        });
        ...
}).catch ((error) => {...})})}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

参考资料:

三、效果展示

在这里插入图片描述


四、参考资料

功能实现参考资料

pdf.js 相关参考资料

问题解决参考资料

其他

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/煮酒与君饮/article/detail/934930
推荐阅读
相关标签
  

闽ICP备14008679号