- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章Vue 集成 PDF.js 实现 PDF 预览和添加水印的步骤由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
Mozilla 提供了 PDF.js 和pdfjs-dist ,两者的区别如下:
Vue 官方插件库 Awesome Vue.js 推荐的vue-pdf 就是对 pdfjs-dist 进行了封装实现,一般情况下使用 vue-pdf 即可快速实现 PDF 的预览效果.
我们的需求是在现有页面中实现 PDF 预览的同时,在 PDF 内容上添加水印.
PDF.js 这种完整版的查看器显得过于臃肿,而 vue-pdf 虽然可以快速实现预览效果,但在添加水印时需要对显示 PDF 的 canvas 进行二次渲染,经过尝试后发现会抛出 Failed to execute 'drawImage' on 'CanvasRenderingContext2D': Overload resolution failed. 的错误.
所以最后选择直接集成 pdfjs-dist 来完成全部功能 。
1
|
yarn add pdfjs-dist
|
必须手动指定 workerSrc ,不然会抛出 Setting up fake worker failed 的错误.
虽然本地目录 node_modules/pdfjs-dist/build/pdf.worker.js 存在该文件,但实际引入时依旧会报错,所以只能使用 CDN 地址下的 pdf.worker.js 。可以通过传入 PDFJS.version 来提高引入的灵活性.
1
2
3
|
import * as PDFJS from
'pdfjs-dist'
PDFJS.GlobalWorkerOptions.workerSrc = `https:
//cdnjs.cloudflare.com/ajax/libs/pdf.js/${PDFJS.version}/pdf.worker.js`
|
1
|
<
canvas
id
=
"pdfCanvas"
></
canvas
>
|
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
|
props: {
// PDF 文件的实际链接
url: {
type: String
}
},
data () {
return
{
totalPage: 1,
// PDFJS 实例
pdfDoc:
null
}
},
methods: {
_initPdf () {
PDFJS.getDocument(
this
.url).promise.then(pdf => {
// 文档对象
this
.pdfDoc = pdf
// 总页数
this
.totalPage = pdf.numPages
// 渲染页面
this
.$nextTick(() => {
this
._renderPage()
})
})
}
}
|
当外部传入的 url 有效时,就可以触发 PDF 查看器的初始化函数 。
1
2
3
4
5
6
7
8
9
|
watch: {
'url'
(val) {
if
(!val) {
return
}
this
._initPdf()
}
},
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
methods: {
_getRatio (ctx) {
let dpr = window.devicePixelRatio || 1
let bsr =
ctx.webkitBackingStorePixelRatio ||
ctx.mozBackingStorePixelRatio ||
ctx.msBackingStorePixelRatio ||
ctx.oBackingStorePixelRatio ||
ctx.backingStorePixelRatio ||
1
return
dpr / bsr
}
}
|
page.getViewport({ scale }) 中的 scale 非常关键,直接关系到渲染出来的内容能不能撑满整个父容器,所以这里分别获取了父容器和页面本身的宽度,父容器宽度 / 页面宽度 后得出的比率就是实际页面需要放大多少的比率.
page.view 是一个数组,里面有四个值,分别是 x轴偏移量、y轴偏移量、宽度、高度。 要获取真实的宽度,还需要考虑当前页面比率,所以使用 page.view[2] * ratio 计算得出实际宽度.
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
|
data () {
return
{
currentPage: 1,
totalPage: 1,
width: 0,
height: 0,
pdfDoc:
null
}
},
methods: {
_renderPage () {
this
.pdfDoc.getPage(
this
.currentPage).then(page => {
let canvas = document.querySelector(
'#pdfCanvas'
)
let ctx = canvas.getContext(
'2d'
)
// 获取页面比率
let ratio =
this
._getRatio(ctx)
// 根据页面宽度和视口宽度的比率就是内容区的放大比率
let dialogWidth =
this
.$refs[
'pdfDialog'
].$el.querySelector(
'.el-dialog'
).clientWidth - 40
let pageWidth = page.view[2] * ratio
let scale = dialogWidth / pageWidth
let viewport = page.getViewport({ scale })
// 记录内容区宽高,后期添加水印时需要
this
.width = viewport.width * ratio
this
.height = viewport.height * ratio
canvas.width =
this
.width
canvas.height =
this
.height
// 缩放比率
ctx.setTransform(ratio, 0, 0, ratio, 0, 0)
page.render({
canvasContext: ctx,
viewport
}).promise.then(() => {})
})
}
}
|
当触发页面跳转时,会调用 _renderQueue() 函数,而不是直接调用 _renderPage() 函数,因为是否开始渲染,要取决于当前是否没有正在被渲染的页面.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
data () {
return
{
// 是否位于队列中
rendering:
false
}
},
methods: {
_renderQueue () {
if
(
this
.rendering) {
return
}
this
._renderPage()
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
methods: {
_renderPage () {
// 队列开始
this
.rendering =
true
this
.pdfDoc.getPage(
this
.currentPage).then(page => {
// ... 省略实现代码
page.render({
canvasContext: ctx,
viewport
}).promise.then(() => {
// 队列结束
this
.rendering =
false
})
})
}
}
|
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
|
data () {
return
{
currentPage: 1,
totalPage: 1
}
},
computed: {
// 是否首页
firstPage () {
return
this
.currentPage <= 1
},
// 是否尾页
lastPage () {
return
this
.currentPage >=
this
.totalPage
},
},
methods: {
// 跳转到首页
firstPageHandler () {
if
(
this
.firstPage) {
return
}
this
.currentPage = 1
this
._renderQueue()
},
// 跳转到尾页
lastPageHandler () {
if
(
this
.lastPage) {
return
}
this
.currentPage =
this
.totalPage
this
._renderQueue()
},
// 上一页
previousPage () {
if
(
this
.firstPage) {
return
}
this
.currentPage--
this
._renderQueue()
},
// 下一页
nextPage () {
if
(
this
.lastPage) {
return
}
this
.currentPage++
this
._renderQueue()
}
}
|
前端添加水印的方式毋庸置疑都是使用 canvas 进行绘制.
最开始找到的方案是准备一个 div 作为透明的遮罩层挡在内容区的上层,然后将 canvas 绘制的水印使用 canvas.toDataURL('image/png') 导出成 Base64 格式,作为遮罩层的背景图片进行平铺。 虽然可以实现效果,但这种方式只要简单的打开浏览器控制台,删除这个遮罩层就可以去除水印.
之后在 Canvas 绘制另一个 Canvas 中找到 canvas 其实是可以将一个 canvas 作为图片绘制到自身上的,于是有了接下来的方案.
因为是组件,所以水印的文字 watermark 由外部传入.
绘制水印的 canvas 不需要添加到页面中,绘制完成后直接将 DOM 元素返回即可,注意,返回的是 DOM 元素 ,而不是使用 getContext(2d) 获取的画布实例.
ctx.fillStyle 表示文字的透明度。 ctx.fillText(this.watermark, 50, 50) 表示文字在画布中的位置,第一个值是文字内容,第二个值是 x轴偏移量,第三个值是 y轴偏移量.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
props: {
watermark: {
type: String,
default
:
'asing1elife'
}
},
methods: {
_initWatermark () {
let canvas = document.createElement(
'canvas'
);
canvas.width = 200
canvas.height = 200
let ctx = canvas.getContext(
'2d'
)
ctx.rotate(-18 * Math.PI / 180)
ctx.font =
'14px Vedana'
ctx.fillStyle =
'rgba(200, 200, 200, .3)'
ctx.textAlign =
'left'
ctx.textBaseline =
'middle'
ctx.fillText(
this
.watermark, 50, 50)
return
canvas
}
}
|
该方法参考自 HTML5 canvas 平铺的几种方法 ,ctx.rect(0, 0, this.width, this.height) 中的 width 和 height 就是在 _renderPage() 函数中记录的页面内容区的实际宽高。只要将实际宽高传入,canvas 就会自动根据水印图片的大小和内容区的大小自动实现 x轴和 y轴的重复次数.
1
2
3
4
5
6
7
8
9
10
11
12
|
methods: {
_renderWatermark () {
let canvas = document.querySelector(
'#pdfCanvas'
)
let ctx = canvas.getContext(
'2d'
)
// 平铺水印
let pattern = ctx.createPattern(
this
._initWatermark(),
'repeat'
)
ctx.rect(0, 0,
this
.width,
this
.height)
ctx.fillStyle = pattern
ctx.fill()
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
methods: {
// 渲染页面
_renderPage () {
this
.pdfDoc.getPage(
this
.currentPage).then(page => {
// ... 省略实现代码
page.render({
canvasContext: ctx,
viewport
}).promise.then(() => {
// 渲染水印
this
._renderWatermark()
})
})
}
}
|
以上就是Vue 集成 PDF.js 实现 PDF 预览和添加水印的的详细内容,更多关于vue 实现 PDF 预览和添加水印的资料请关注我其它相关文章! 。
原文链接:https://juejin.cn/post/6920148445084778510 。
最后此篇关于Vue 集成 PDF.js 实现 PDF 预览和添加水印的步骤的文章就讲到这里了,如果你想了解更多关于Vue 集成 PDF.js 实现 PDF 预览和添加水印的步骤的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
有没有办法获取其他网站页面的屏幕截图? 例如:您在输入中引入一个网址,按 Enter 键,然后脚本会为您提供所输入网站的屏幕截图。我设法使用 headless 浏览器来完成此操作,但我担心这可能会占用
我如何在 UICollectionView 中添加下一个单元格的预览,当当前单元格被滑动时显示?这样感觉就像一堆卡片。我从 Chrome 的 iOS 应用程序及其标签切换器的实现中汲取了很多灵感。任何
HTML javascript 编程新手,我的页面实现有问题。我创建了多页 HTML 表单布局(使用 div),它运行 4 个页面,大约有 140 个输入值(大多数是可选值)。我需要在实际提交之前实现
我正在尝试让 Qt5 QFileDialog 在选择图像打开时显示图像预览。 方法一:扩展QFileDialog 我用了this implementation of the dialog它适用于 Qt
我是 TFS 的新手,并尝试通过托管的 TFS (tfspreview.com) 进行我的第一次自动构建,但由于缺少程序集而失败。 我在解决方案中的一个项目引用了 Microsoft.WindowsA
我正在使用 SwiftUI 并编写了以下示例来展示我遇到的问题。当我添加多个按钮或多个文本时,它会创建两个单独的预览,但是当我在设备上运行应用程序时,它们会同时加载。附上一张照片: 我清理了我的构建文
我无法将代码覆盖率提高到最低。 90% 因为 XCode 考虑了 PreviewProvider。 我该怎么办?删除所有 SwiftUI 预览?或者有没有一种方法可以排除一些带有“PreviewPro
首先,请注意我搜索了一个 SocialMediaStackExchange 来问这个问题,但似乎没有。 这就是我想知道的。向 twitter 发布推文时,如果它是 youtube 链接或特定网站的
我正在使用谷歌地图 API 自动完成来获取搜索的机构的城市和国家/地区。为此,我有一个输入字段和搜索位置的 map 预览。这是 jsfiddle,但它目前不起作用(https://jsfiddle.n
在 OpenCart 商店中提供音频预览的最佳方法和播放器是什么?这将涉及上传完整轨道,然后提取要播放的部分 最佳答案 m3psplt是迄今为止您最好的选择。 有时安装起来有点冒险(特别是在 Cent
如果我运行: 127.0.0.1:8000/document/1/preview 此 pdf 文件已下载。 我需要在 HTML 中显示它(带有打印功能的预览)。怎么做? views.py from x
我在预览 Wagtail 页面时遇到错误,但在发布和实时查看时一切正常。我的设置是这样的: from django.db import models from modelcluster.fields
我是一个新手,我一直在尝试在 docker 上安装 Mattermost(slack 替代方案)的预览版来尝试一下。我一直遵循官方指南。 拱门 Install Docker using the fol
如果我运行: 127.0.0.1:8000/document/1/preview 此 pdf 文件已下载。 我需要在 HTML 中显示它(带有打印功能的预览)。怎么做? views.py from x
我在预览 Wagtail 页面时遇到错误,但在发布和实时查看时一切正常。我的设置是这样的: from django.db import models from modelcluster.fields
VS 调试器给我: _Color = "{Name=ff000040, ARGB=(255, 0, 0, 64)}" 我怎样才能“看到”什么颜色? 我尝试了一个 html 页面: ________
我想显示来自 ImageField 的图像。我正在使用 Django crispy forms 。似乎我需要使用 HTML 布局助手,但我不确定如何在此处访问模板变量。 以下呈现一个空白图像标签: H
The following classes could not be instantiated: androidx.fragment.app.FragmentContainerView (Open C
我正在从事一个涉及数据集之间连接的项目,我们需要允许预览任意数据集之间的任意连接。这很疯狂,但这就是它有趣的原因。这是使用面向所以给定一个连接我想快速显示 ~10 行结果。 我一直在围绕不同的方法进行
我正在尝试上传图像并在用户提交之前进行预览,但由于某种原因我无法更改 div 或图像的宽度或高度,并且它会以正常尺寸进行预览。我什至将它设置为 1px x 1px,但它仍然不起作用。 $(functi
我是一名优秀的程序员,十分优秀!