Fork me on GitHub

pdf.js使用

需求:将从服务器请求回来的 pdf 文件展示为图片
填坑填坑,github 上的项目中的例子很重要,不要怕英文

https://github.com/mozilla/pdf.js
如果是直接展示 pdf 文件,window.open(url)就好了
也可以使用 pdf.js 中的 viewer.js

这次的需求是将 pdf 渲染为类似 image
例子可以参考 github 下 examples/learning/helloworld.html
请求 pdf 文件,使用 canvas 渲染到网页

 在 React 项目中使用

在项目 public/index.html 引入 pdf.js\

  • 引入网络资源

    window 对象中增加 pdfjsLib 方法
  • 下载到本地引入,放到 server/build 中

    _使用_
    js

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    pdfjsLib.getDocument(url).then(pdf=>{
    pdf.getPage(1).then(page=>{
    var scale = 1.5;
    var viewport = page.getViewport({ scale: scale, });
    var canvas = document.getElementById('the-canvas');
    var context = canvas.getContext('2d');
    canvas.height = viewport.height;
    canvas.width = viewport.width;
    })
    var renderContext = {
    canvasContext: context,
    viewport: viewport,
    };
    page.render(renderContext);
    })

    html

    1
    <canvas id="the-canvas" style="border:1px  solid black"></canvas>

问题
url 是 pdf 文件的路径,使用本地的 pdf 文件,采用 es6 的方法引入,可以正常调用
但是变成服务器的地址时,产生跨域问题。

解决办法
参考 github 下 examples/learning/helloworld64.html
需要后台改接口,将返回的文件路径变为二进制文件流,然后使用 window 自带的解码方法 atob 解码,将解码后的数据传给 pdf.js 的方法,

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
//模拟请求回来的数据,使用 axios/fetch 请求代替
var pdfData = atob(
'JVBERi0xLjcKCjEgMCBvYmogICUgZW50cnkgcG9pbnQKPDwKICAvVHlwZSAvQ2F0YWxvZwog' +
'IC9QYWdlcyAyIDAgUgo+PgplbmRvYmoKCjIgMCBvYmoKPDwKICAvVHlwZSAvUGFnZXMKICAv' +
'TWVkaWFCb3ggWyAwIDAgMjAwIDIwMCBdCiAgL0NvdW50IDEKICAvS2lkcyBbIDMgMCBSIF0K' +
'Pj4KZW5kb2JqCgozIDAgb2JqCjw8CiAgL1R5cGUgL1BhZ2UKICAvUGFyZW50IDIgMCBSCiAg' +
'L1Jlc291cmNlcyA8PAogICAgL0ZvbnQgPDwKICAgICAgL0YxIDQgMCBSIAogICAgPj4KICA+' +
'PgogIC9Db250ZW50cyA1IDAgUgo+PgplbmRvYmoKCjQgMCBvYmoKPDwKICAvVHlwZSAvRm9u' +
'dAogIC9TdWJ0eXBlIC9UeXBlMQogIC9CYXNlRm9udCAvVGltZXMtUm9tYW4KPj4KZW5kb2Jq' +
'Cgo1IDAgb2JqICAlIHBhZ2UgY29udGVudAo8PAogIC9MZW5ndGggNDQKPj4Kc3RyZWFtCkJU' +
'CjcwIDUwIFRECi9GMSAxMiBUZgooSGVsbG8sIHdvcmxkISkgVGoKRVQKZW5kc3RyZWFtCmVu' +
'ZG9iagoKeHJlZgowIDYKMDAwMDAwMDAwMCA2NTUzNSBmIAowMDAwMDAwMDEwIDAwMDAwIG4g' +
'CjAwMDAwMDAwNzkgMDAwMDAgbiAKMDAwMDAwMDE3MyAwMDAwMCBuIAowMDAwMDAwMzAxIDAw' +
'MDAwIG4gCjAwMDAwMDAzODAgMDAwMDAgbiAKdHJhaWxlcgo8PAogIC9TaXplIDYKICAvUm9v' +
'dCAxIDAgUgo+PgpzdGFydHhyZWYKNDkyCiUlRU9G');

pdfjsLib.GlobalWorkerOptions.workerSrc =
'https://cdn.jsdelivr.net/npm/pdfjs-dist@2.0.943/build/pdf.worker.js';

var loadingTask = pdfjsLib.getDocument({ data: pdfData, });
loadingTask.promise.then(function(pdf) {
// Fetch the first page.
pdf.getPage(1).then(function(page) {
var scale = 1.5;
var viewport = page.getViewport({ scale: scale, });
// Prepare canvas using PDF page dimensions.
var canvas = document.getElementById('the-canvas');
var context = canvas.getContext('2d');
canvas.height = viewport.height;
canvas.width = viewport.width;
// Render PDF page into canvas context.
var renderContext = {
canvasContext: context,
viewport: viewport,
};
page.render(renderContext);
});
});

另外还做了一个拖动和放大  缩小的功能,具体参考

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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170

import React ,{ Component } from 'React'
import { Modal, Button, } from 'antd';

class Index extends Component {
constructor(props){
super(props);
this.state={
width:0,
height:0,
show:true,
mouseDownFlag:false,
mouseDownX:null,
mouseDownY:null,
initX:null,
initY:null,
scale:1,
disable:false,
}
}
drawImg=(img,scale=1)=>{
var pdfData = atob(img)
window.pdfjsLib.GlobalWorkerOptions.workerSrc ='http://localhost:8000/pdf.worker.js'
window.pdfjsLib.getDocument({data:pdfData}).then(pdf=> {
pdf.getPage(1).then(page=>{
var viewport = page.getViewport(scale);
var canvas = document.getElementById('modal_img');
var context = canvas.getContext('2d');
context.clearRect(0,0,canvas.width,canvas.height);
canvas.height = viewport.height;
canvas.width = viewport.width;
var renderContext = {
canvasContext: context,
viewport: viewport
};
page.render(renderContext);
this.setState({width:canvas.width,height:canvas.height,})
})
});
}
componentDidMount(){
this.drawImg(this.props.img)
}

handlerMouseUp=()=>{
this.setState({mouseDownFlag:false},()=>{})
}
handlerMouseDown=(e)=>{
this.setState({mouseDownFlag:true, mouseDownX:e.pageX,mouseDownY:e.pageY })
const img=document.getElementById('modal_img')
const initX=img.offsetLeft;
const initY=img.offsetTop;
this.setState({initX,initY})
}
handlerMouseMove=(e)=>{
e.preventDefault && e.preventDefault();
const img=document.getElementById('modal_img')
const { mouseDownX, mouseDownY,initX,initY,width,height}=this.state

const moveX=e.pageX;
const moveY=e.pageY;

if(this.state.mouseDownFlag){
let left=parseInt(moveX)-parseInt(mouseDownX)+parseInt(initX)
let top=parseInt(moveY)-parseInt(mouseDownY)+parseInt(initY)
left=left>0?0:
left<900-width?900-width
:parseInt(moveX)-parseInt(mouseDownX)+parseInt(initX)
top=top>0?0:
top<650-height?650-height:top
if (width<920) {
left=0;
}
if (height<650) {
top=0;
}
// console.log('222',left,top)
img.style.left=left+'px';
img.style.top=top+'px'
}

}

handleScale=(value)=>{
let {scale}=this.state;
let self=this
this.setState({disable:true},
()=>{
setTimeout(() => {
self.setState({disable:false})
}, 800)
}
)
if(value>0){
this.drawImg(this.props.img,scale*1.1)
this.setState({scale:scale*1.1})
}else{
this.drawImg(this.props.img,scale/1.1)
this.setState({scale:scale/1.1})
}
}
handlerMouseWheel=(e)=>{
console.log(e.deltaY)
if(e.deltaY<0){

}
}

render(){
const { img ,name,children}=this.props
// const {show}=this.state
return(
<span>
{/* <span onClick={()=>{this.setState({show:true})}}>
{children}
</span> */}
<Modal
title={<div>
<span style={{
display: 'inline-block',
width:6,
height:16,
marginRight:10,
verticalAlign:'center',
backgroundColor: '#4A9478',
}}>
</span><span>{name}</span>
<div style={{float:'right',marginRight:30}}>
<Button onClick={()=>this.handleScale(1)} disabled={this.state.disable}>放大</Button>
<Button onClick={()=>this.handleScale(-1)} style={{marginLeft:10}} disabled={this.state.disable}>缩小</Button>
</div>
</div>}
visible={true}
closable
onCancel={()=>{this.props.showFlatModal(false)}}
footer={null}
width={900}
bodyStyle={{backgroundColor:'#F3F2F6',borderBottomRightRadius:4,borderBottomLeftRadius:4,
height:650,overflow:'scroll',position:'relative',padding:0,boxSizing:'border-box',textAlign:'center'}}
destroyOnClose
maskClosable
>

<canvas id='modal_img'
style={{
width:this.state.width,
height:this.state.height,
cursor:'pointer',
position:'absolute',
left:0,
top:0,
// transform:`translate(-50%)`,
}}
onMouseDown={this.handlerMouseDown}
onMouseUp={this.handlerMouseUp}
onMouseMove={this.handlerMouseMove}
onWheel={this.handlerMouseWheel}
>

</canvas>

</Modal>
</span>

)
}

}

export default Index
1
2


-------------本文结束感谢阅读-------------