Realize online preview pdf and add watermark

1. The embed tag realizes online preview pdf

Recently, I want to implement a function - online preview of pdf files. At the beginning, I searched for information on the Internet, and they all said to use pdf.jsto realize online preview of pdf files. However, for the function to be realized, it is necessary to load the entire file, which seems a bit unsatisfactory. Later, I recall that html5 provides the embed tag, which can embed external content in a specified location in the document. We can see the usage:

<embed src="资源地址" width="400" height="400"></embed>

Effect display (the displayed effect will display different interface effects according to the browser's own support):

insert image description here

2. Hide the toolbar

After realizing the online preview of pdf, sometimes I don’t want users to download and print through the download button and print button on the page, so I need to hide this function. At first, my idea was to get the DOM of the toolbar on the page, and then add styles , let the button be hidden, but it is a pity that this DOM cannot be obtained (maybe it can be obtained, but I don’t know how to get it yet, the big guy who knows can let me know, thank you~), so I checked the information, we can Splicing #toolbar=0behind to hide the toolbar, although the download button and print button can be hidden, but at the same time it also limits other operations, but fortunately, only preview is needed, and no other operations are required. This method is still advisable.
insert image description here

3. Add watermark to pdf

After solving the problem of downloading and printing, another function is added. It is necessary to add a watermark on the pdf, that is, it needs to operate on the pdf object. Here is a plug-in library that is specially designed to operate on pdf files pdf-lib. , allows us to obtain the properties of the pdf object and manipulate the pdf object, without further ado, the code:

(1) Installation dependencies
// 1、安装依赖
npm install pdf-lib --save
// 2、自定义字体库依赖
npm install "@pdf-lib/fontkit" --save
(2) Use pdf-lib
import {
    
     PDFDocument } from "pdf-lib"
export const addWaterMark = async (url: string, config?: object) => {
    
    
    // 获取文件的 arrayBuffer 流,获取路径可以前端本地项目文件,如果是脚手架,文件需要放在 public 目录下
    // 也可以从后台获取返回的 base64 文件流
    const existingPdfBytes = await fetch(url).then(res => res.arrayBuffer())
    
    // 生成一个 pdf 文档对象
    const pdfDoc = await PDFDocument.load(existingPdfBytes)
    
    // 获取所有的 pdf 页面
    const pages = pdfDoc.getPages()
    for (let i = 0; i < pages.length; i++) {
    
    
        const page = pages[i]
        const {
    
     height } = page.getSize()
        for (let i = 0; i < 10; i++) {
    
    
            for (let j = 0; j < 3; j++) {
    
    
                page.drawText('watermark', {
    
    
                    x: 200 * j,
                    y: (height / 4) * i,
                    size: 16,
                    opacity: 0.3,
                })
            }
        }
    }
    // 生成 unit64Arrary文件流
    const pdfBytes = await pdfDoc.save();
    let blobData = new Blob([pdfBytes], {
    
     type: "application/pdf;Base64" });
    
    // 返回一个新的 url 链接
    return window.URL.createObjectURL(blobData);
}

insert image description here

The above code can simply implement the function of adding watermark to pdf, but there is a problem that pdf-libChinese is not supported. If Chinese is used, the console will report an error;

insert image description here

If you want to realize the Chinese watermark, there are two solutions, the first is to add a custom font package, the second is to generate a text image through canvas, and then draw it on the pdf file, personally prefer the second, because the first One needs to load the entire font package, which is generally relatively large, so it is not recommended. Let's take a look at the respective implementation methods:

Method 1: Add a custom font package

import {
    
     PDFDocument } from "pdf-lib"
import fontkit from "@pdf-lib/fontkit"
export const addWaterMark = async (url: string, config?: object) => {
    
    
    const existingPdfBytes = await fetch(url).then(res => res.arrayBuffer())
    const pdfDoc = await PDFDocument.load(existingPdfBytes)
    
    // 自定义字体包路径,放在 public 目录
    const fonturl = './font/font.ttf';
    const fontBytes = await fetch(fonturl).then((res) => res.arrayBuffer());
    pdfDoc.registerFontkit(fontkit)
    const customFont = await pdfDoc.embedFont(fontBytes)
    
    const pages = pdfDoc.getPages()
    for (let i = 0; i < pages.length; i++) {
    
    
        const page = pages[i]
        const {
    
     width, height } = page.getSize()
        for (let i = 0; i < 10; i++) {
    
    
            for (let j = 0; j < 3; j++) {
    
    
                page.drawText('中文', {
    
    
                    x: 200 * j,
                    y: (height / 4) * i,
                    size: 16,
                    // 自定义字体
                    font: customFont,
                    opacity: 0.3,
                })
            }
        }
    }
    const pdfBytes = await pdfDoc.save();
    let blobData = new Blob([pdfBytes], {
    
     type: "application/pdf;Base64" });
    return window.URL.createObjectURL(blobData);
}

insert image description here

Method 2: Generate text images through canvas

export const addWaterMark = async (url: string, config: PDFConfig) => {
    
    
    // 水印文字,文字大小
    const {
    
     text, size } = config;
    const existingPdfBytes = await fetch(url).then(res => res.arrayBuffer())
    const pdfDoc = await PDFDocument.load(existingPdfBytes)
	
    // 生成 canvas 文字图片
    let canvas = document.createElement('canvas')
    const textBlockWidth = size * (text.length + 1)
    const textBlockHeight = size * 2
    canvas.width = textBlockWidth
    canvas.height = textBlockHeight
    const ctx = canvas.getContext('2d')
    ctx.fillStyle = '#000'
    ctx.font = `${
      
      size}px Microsoft`
    ctx.fillText(text, size / 2, size)
    const png = canvas.toDataURL('img/png')
    const imagePDF = await pdfDoc.embedPng(png)

    const pages = pdfDoc.getPages()
    for (let i = 0; i < pages.length; i++) {
    
    
        const page = pages[i]
        const {
    
     width, height } = page.getSize()
        for (let i = 0; i < 10; i++) {
    
    
            for (let j = 0; j < 3; j++) {
    
    
                // 将文字图片绘制到 pdf
                page.drawImage(imagePDF, {
    
    
                    x: 200 * j,
                    y: (height / 4) * i,
                    opacity: 0.3,
                })
            }
        }
    }
    const pdfBytes = await pdfDoc.save();
    let blobData = new Blob([pdfBytes], {
    
     type: "application/pdf;Base64" });
    return window.URL.createObjectURL(blobData);
}

insert image description here

The above are the two ways to implement watermarking, in which two methods drawTextand drawImage. On the page object, there are other operable methods that can realize more functions, so I won’t introduce them in detail here;

insert image description here

4. Summary

You can use embedthe tag , but there may be certain browser compatibility issues, use it with caution, or use pdf.jsto achieve preview, if we still need to operate on the pdf object, we can use pdf-libthe plug- library, the specific steps are divided into:

  • Get the arrayBuffer stream of the file;
  • generate a pdf document object;
  • operate on pdf objects;
  • Generate unit64Arrary file stream;
  • generate a new pdf link;

In addition to adding a watermark, you can set the rotation angle and color of the watermark, and you can also download the pdf with the watermark added (pdf-lib's download method), which can be done according to actual needs. It should be noted that setting the color requires Use the color conversion API provided by the plug-in library, that is rgb, the specific use can see the implementation of the source code;

Guess you like

Origin blog.csdn.net/Ljwen_/article/details/127876863