原本我使用的 是 vue-pdf-embed 的这个组件 后来 发现这个组件 对应vue2 的版本 可能太过于滞后了,里面的pdf.js大概率是2.x版本左右。这会导致我们渲染出来的部分pdf文件 启用textLayer会有文字排布不对甚至是文本层位置偏移 的大问题,如果对 划词翻译 或者渲染pdf上的文本层没有要求 只需要做简单的pdf渲染 建议使用 vue-pdf-embed 会快很多
这里 给一下 vue-pdf-embed相关模块的使用流程 链接:
这里引入了cMapUrl 字体资源 用的 2.2.228版本 用其他2.x版本的字体资源应该没问题 如果低于或者高于 这个版本 会出现 日文、韩文 或者特殊语言的pdf 渲染不出来,cMapPacked 属性需要设置true 不然不生效。
<div v-for="(item,index) in pdfList" :ref="'child'+index" :key="index" class="pdf">
<VuePdfEmbed
:source="{
cMapUrl: 'https://cdn.jsdelivr.net/npm/pdfjs-dist@2.2.228/cmaps/',
cMapPacked: true,
url: myUrl,
}"
:page="parseInt(item)"
:textLayer="true"
@loaded="loaded"
@rendering-failed="renderingFailed($event,index)"
@loading-failed="loadingFailed($event,index)"
/>
</div>
接下来 讲一下 pdf.js渲染pdf 这里 由于pdf.js 引入 vue2 时 是作为模块引入的 也就是 pdf-dist 模块,基本3.x版本以上 就都是vue3才可以使用了,我们项目引入 pdf-dist@3.x时就会npm 失败 。因此选择直接在public 的index.html 直接引入你想要使用的 pdf.js cdn资源 以pdf_viewer.min.css 样式。
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.5.141/pdf.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.5.141/pdf_viewer.min.css" />
另外在需要渲染pdf的vue页面 获取一下内置的对象
const PDFJS = window['pdfjs-dist/build/pdf'];
PDFJS.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.5.141/pdf.worker.min.js';
然后就是渲染pdf的相关方法 ,因为我封装了一个渲染组件 所以在最后面 当第一页pdf代码执行末尾 我emit 了一个事件 返回给父组件 代表渲染结束。
showPDF(pdf_url) {
this.loading = true
var that = this
let idName = 'canvas-pdf-'
PDFJS.getDocument({ url: pdf_url , cMapUrl: 'https://cdn.jsdelivr.net/npm/pdfjs-dist@3.5.141/cmaps/',cMapPacked: true}).promise.then(function (pdf_doc) {
that.pdfObj = pdf_doc;
console.log("pdf_doc",pdf_doc );
that.totals = that.pdfObj['_pdfInfo'].numPages;
console.log("pdf_doc2",pdf_doc,'this.totals ',that.totals );
// Show the first page 0.00077 每px 的scalc 比例
let pdfContainer = document.getElementById('pdf-container')
let scale;
that.pdfObj.getPage(1).then(p=>{
console.log('pdfContainer',pdfContainer.clientWidth,p.getViewport({ scale: 1.03 }).width);
let containerWidth = pdfContainer.clientWidth;
scale = containerWidth / p.getViewport({ scale: 1.03 }).width;
for (let i = 1; i <= that.totals; i++) {
that.pdfObj.getPage(i).then(async (page) => {
let canvas = document.getElementById(idName + i)
let __CANVAS_CTX = canvas.getContext('2d')
let viewport = page.getViewport({
scale:scale,//that.windowWidth * 0.0007482 //1.18,
});
console.log('that.windowWidth * 0.0007482',that.windowWidth * 0.0007482);
// viewport.width = pdfContainer.clientWidth;
canvas.height = viewport.height;
canvas.width = viewport.width;
var renderContext = {
canvasContext: __CANVAS_CTX,
viewport: viewport
};
page.render(renderContext).promise.then(function () {
return page.getTextContent();
}).then(function (textContent) {
let pageDiv = document.getElementById(`page-${i}`)
var thisNode = document.getElementById('text-layer'+i);
if(thisNode){
pageDiv.removeChild(thisNode)
}
const textLayerDiv = document.createElement('div')
textLayerDiv.setAttribute('id', 'text-layer'+i)
textLayerDiv.setAttribute('class', 'textLayer')
// 将文本图层div添加至每页pdf的div中
pageDiv.appendChild(textLayerDiv)
// Clear HTML for text layer
$("#text-layer"+i).html('');
// Assign the CSS created to the text-layer element
console.log('viewport.scale',viewport.scale);
document.getElementById('text-layer'+i).style.setProperty('--scale-factor', viewport.scale);
$("#text-layer"+i).css({ left: 0 + 'px', top: 0 + 'px'});
// Pass the data to the method for rendering of text over the pdf canvas.
PDFJS.renderTextLayer({
textContentSource: textContent,
container: $("#text-layer"+i).get(0),
viewport: viewport,
textDivs: []
});
if(i==1){
// 渲染成功
that.loading = false
that.$emit('isOverImg',{type:'1',flag:false,isLoadingOver:true})
}
});
})
}
})
}).catch(function (error) {
// 渲染失败
that.loading = false
that.$message({message:"文件渲染失败,请刷新浏览器重试",type:'error',showClose:true})
});
},
<div class="wrapper" id="pdf-container" @mouseleave="mouseleave" >
<div v-for="item in totals" :id="`page-${item}`" :key="item" class="pdf-box" @mouseup="handleMouseSelect" @mousedown="mousedown($event)" :draggable="false" @mousemove="mousemove($event,item)">
<canvas :id="'canvas-pdf-' + item" class="canvas-pdf"></canvas>
</div>
</div>
以上 就是vue2 引入pdf.js做渲染 用这种方式渲染出来的pdf 不仅文本层排列整齐 并且划词 也会比vue-pdf-embed 效果好一些。
@mouseup="handleMouseSelect"
@mousedown="mousedown($event)" :draggable="false"
@mousemove="mousemove($event,item)"
这几个事件 是根治 pdf.js 划词准确性 以及流畅性的 方法。这一章先讲到这里,有任何问题可关注私信我,或者加我QQ私聊问我,后续有空 补充完整 pdf.js 优化划词选中 相关示例。