pdf.js实现pdf预览

需求:实现点击左侧pdf文件时,右侧可以实时预览内容。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

可以实现点击预览;但不能按住ctrl进行缩放;清晰度的问题;不能固定左侧对右侧加滚轮;

package.js:

在"dependencies"里加一行"jspdf": “^2.3.1”,然后npm install 重新下载需要的依赖;

main.js:

import * as pdfjsLib from ‘pdfjs-dist’;
import “pdfjs-dist/build/pdf.worker.entry.js”;
pdfjsLib.GlobalWorkerOptions.workerSrc = window.pdfjsWorker;
window.pdfjsLib = pdfjsLib;

展示的页面.vue:

<div class="pages" style="height:auto;overflow-y: auto;">
                  <el-col :span="8">
                        <el-menu
                          class="el-menu-vertical-demo"
                          >
                          <el-submenu index="1">
                            <template slot="title">
                              <span style="color: black;line-height: 30px;font-size: 15px">目录</span>
                            </template>
                            <el-menu-item-group>
                              <div style="width:auto;height:40px;text-overflow:ellipsis;white-space:nowrap;overflow: hidden;" @click="viewfFile()">
                                <el-menu-item style="color: black;line-height: 30px;font-size: 15px">{{this.你的pdfName}}</el-menu-item>
                              </div>
                            </el-menu-item-group>
                          </el-submenu>
                      </el-menu>
                  	</el-col>
				 <el-col :span="16">
                      <div class="page" v-for="page in pageTotal" :style="{'width':pageWidth+'px'}">
                        <canvas :id="`pdfCanvas${page}`"></canvas>
                      </div>
                 </el-col>
</div>
//预览pdf
viewFile() {
  let data = {
    csId: this.csId,
  }
  let url = '/**/***'//点击这个文件拿它id去后端取它的url地址
  this.$request.post(url, data).then(data => {
    if (data.data.obj==null||data.data.obj==''){
      this.$message.info('pdf无')
    }else{
      let pdfUrl = *window*.location.origin + data.data.obj.url;//拼接出能直接点击访问pdf的链接赋给pdfUrl
      this.loadPdf(pdfUrl);
    }
  })
},
    loadPdf(pdfUrl){
      this.clearPage();
      let loadingTask = window.pdfjsLib.getDocument(pdfUrl);
      loadingTask.promise.then((pdf) =>{
        let total = pdf.numPages;
        this.pageTotal = total;
        this.pdfDoc = pdf;
        this.$nextTick(() => {
          this.pageNum = 1;
          this.renderPage(1) // 表示渲染第 1 页
        })
      });
    },
    // 渲染指定页面的内容
    renderPage(num){
      let pdfDoc = this.pdfDoc;
      if(pdfDoc){
        pdfDoc.getPage(num).then((page)=>{
          let canvas = document.getElementById(`pdfCanvas${num}`);
          let scale = 1;
          let viewport = page.getViewport({ scale: scale, });
          let outputScale = window.devicePixelRatio || 1;


          canvas.width = Math.floor(viewport.width * outputScale);
          canvas.height = Math.floor(viewport.height * outputScale);
          canvas.style.width = Math.floor(viewport.width) + "px";
          canvas.style.height =  Math.floor(viewport.height) + "px";
          this.pageWidth = Math.floor(viewport.width);
          this.pageHeight = Math.floor(viewport.height);
          this.pdfScale = scale;
    
          let ctx = canvas.getContext("2d")
          let transform = outputScale !== 1 ? [outputScale, 0, 0, outputScale, 0, 0] : null;
          // 将 PDF 页面渲染到 canvas 上下文中
          let renderContext = {
            canvasContext: ctx,
            transform: transform,
            viewport: viewport
          };
    
          page.render(renderContext);
    
          if (this.pageTotal > num) {
            this.renderPage(num + 1);
          }
        })
      }
    },

在这里插入图片描述

当npm install后出现的bug:ERROR Failed to compile with 1 error;error in ./node_modules/pdfjs-dist/build/pdf.js
在这里插入图片描述
再次执行npm i pdfjs-dist@2.4.456(看你项目里pdf-dist的版本),单独下载pdfjs-dist依赖,然后再执行npm run serve;

参考与感谢:

①原文链接:https://blog.csdn.net/forward_xx/article/details/126915088;
②原文链接:https://blog.csdn.net/weixin_64310738/article/details/129073031;

第三方插件:pdf.js(基于Promise 对象而实现的,渲染 pdf 时底层还使用了Web Worker),一款开源的 pdf 文档读取解析插件,实现在 html 下直接浏览 pdf 文档。

在这里插入图片描述
在项目中使用pdfjs,主要包括以下内容:

  • 单页pdf加载
  • 多页pdf加载(本文)
  • pdf放大/缩小/大小重置
  • pdf分页展示以及上下翻页
  • pdf添加水印
  • 动态添加pdf
  • 从服务端获取pdf文件

我选择用以图片形式来展示 PDF 文档,这种方法不能选中文本或复制文本。

pdfjs展示pdf文档的原理:实际上是将pdf中的内容渲染到解析,然后渲染到 canvas 中进行展示,因此我们使用pdfjs渲染出来的pdf文件,实际上是一张张canvas图片。

具体步骤:

一、首先 npm i pdfjs-dist 下载 pdf.js 的 Prebuilt 包
百度搜索 npm pdfjs-dist,进入npm官方网站,即可查看pdfjs的安装方法,安装命令:npm i pdfjs-dist:
在这里插入图片描述
二、设置 PDFJS.GlobalWorkerOptions.workerSrc 的地址
三、通过 PDFJS.getDocument(pdf 文件的 url) 处理 pdf 数据,返回一个 PDFDocumentLoadingTask
四、通过 pdfDoc.getPage(i) 单独获取第 i 页的数据
五、创建一个 canvas 元素,并设置元素的画布属性
六、通过 page.render 方法,将数据渲染到画布上

### 关于 `pdfjs-dist` 版本 ^2.2.228 报错的具体解决方案 #### 使用 XHR2 和 CreateObjectURL 处理跨域问题 对于 PDF 文件加载过程中遇到的跨域问题,可以采用 XMLHttpRequest Level 2 (XHR2) 加上 URL.createObjectURL 方法来处理。通过这种方式可以直接读取二进制数据并创建对象 URL 来绕过同源策略限制[^1]。 ```javascript function fetchPdf(url) { var xhr = new XMLHttpRequest(); xhr.open('GET', url, true); xhr.responseType = 'arraybuffer'; xhr.onload = function() { if (xhr.status === 200 || xhr.status === 0) { // status may be 0 in some browsers when loading from local file system. const blob = new Blob([xhr.response], { type: "application/pdf" }); const objectUrl = URL.createObjectURL(blob); // Use the created Object URL with pdf.js or any other library that requires a valid URL to load the document. // Remember to revoke the object URL after use to free up memory resources. setTimeout(() => URL.revokeObjectURL(objectUrl), /* your timeout */ ); } }; xhr.send(null); } ``` #### CMaps 资源缺失导致的错误修复 当使用特定版本 (`^2.2.228`) 的 `pdfjs-dist` 库时,如果缺少必要的字符映射表(CMaps),可能会引发解析失败等问题。为了防止此类情况发生,应该确保正确配置了 CMaps 的路径。即使是在离线环境中也可以预先下载所需文件并将其放置在一个可访问的位置[^2]。 ```html <script> import * as pdfjsLib from 'pdfjs-dist'; // Set default configuration options for pdfjs-lib including setting path to cmaps directory. pdfjsLib.GlobalWorkerOptions.workerSrc = '/path/to/pdf-worker.min.js'; // Adjust according to actual location of worker script. const cMapUrl = "/local/path/to/cmaps/"; pdfjsLib.PDFJS.cMapUrl = cMapUrl; pdfjsLib.PDFJS.cMapPacked = true; async function renderPdf(pdfUrl){ try{ let loadingTask = pdfjsLib.getDocument({url: pdfUrl}); let pdfDocument = await loadingTask.promise; console.log(`Number of pages: ${pdfDocument.numPages}`); // Continue rendering logic here... } catch(error){ console.error("Error while trying to open PDF:", error.message); } } renderPdf('/relative/or/absolute/url/of/the.pdf'); </script> ``` #### Vue3 中集成 PdfEmbed 组件以支持中文显示 针对基于 Vue3 构建的应用程序,在尝试嵌入 PDF 文档时不显示汉字的情况,可以通过自定义属性传递给 `<vue-pdf-embed>` 组件来指定本地存储的 CMaps 地址以及启用打包模式。这有助于解决由于网络请求受限而导致字体资源不可达的问题[^3]。 ```vue <template> <div id="app"> <!-- Pass custom props containing paths and settings required by pdfjs --> <vue-pdf-embed :source="{ cMapUrl: cMapUrl, cMapPacked: true, url: pdfSource }"/> </div> </template> <script setup lang="ts"> import { ref } from 'vue'; import vuePdfEmbed from '@khawaja/vue-pdf-embed'; defineProps<{ msg?: string, }>(); let cMapUrl = ref("/static/cmaps/"); let pdfSource = ref("/documents/sample-chinese-text.pdf"); </script> ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值