Some problems encountered in loading pdf from Webview and their solutions

Problem source

The source of all the problems still has to start from that day

One day, Xiao Wang came to my station with a computer: "Hey, Xiao Fu, here is an Online pdf preview function. See if you can do it."

After hearing this, I thought to myself: it's not easy. Loading online pdf is the same as loading web pages. webview plus pdf links, done!

After thinking about this, I immediately compared it to OK: "no problem, simple!"

After that, start work immediately, create a new project, and prepare webview, PDF link, webview loadUrl(" https://www.gjtool.cn/pdfh5/git.pdf "), click Run and wait for the moment when the PDF is loaded.

Eh? Why is it blank? Is there a problem with the webview setting item, but there is no problem loading the web page. At this time, I saw that the iOS big brother next door had successfully loaded the pdf. When I asked, it was also loaded with webview. Why can't I leave it alone? Look down on me?

With doubts.

The original Android webview doesn't support loading pdf at all.

Android is different from iOS. iOS loads pdf, whether local or online, and it can be rendered directly using webview, but Android can't.

How to load pdf?

There are many loading schemes, such as directly jumping to a third-party browser to load, but the product requires that it can only be previewed inside the app, pass; For example, Google service is added before pdf link, but it is inaccessible in China, pass; For example, the pdf is loaded after downloading, but when the pdf volume is large and the network is not good, the download will have problems and pass;

There are many ways, and there are many third-party wheels, but if they are suitable for their own development needs and meet UI design, they need secondary transformation.

After many comparisons, the scheme of loading pdf using webview is more in line with most scenarios.

The following will start from the scheme of loading pdf from webview to describe the problems involved in development.

My journey to climb the pit has begun!

Preliminary loading

The initial idea of webview loading pdf is to use js to render,

Create a new js

var url = location.search.substring(1);

PDFJS.cMapUrl = 'https://unpkg.com/pdfjs-dist@1.9.426/cmaps/';
PDFJS.cMapPacked = true;

var pdfDoc = null;

function createPage() {
    var div = document.createElement("canvas");
    document.body.appendChild(div);
    return div;
}

function renderPage(num) {
    pdfDoc.getPage(num).then(function (page) {
        var viewport = page.getViewport(2.0);
        var canvas = createPage();
        var ctx = canvas.getContext('2d');

        canvas.height = viewport.height;
        canvas.width = viewport.width;

        page.render({
            canvasContext: ctx,
            viewport: viewport
        });
    });
}

PDFJS.getDocument(url).then(function (pdf) {
    pdfDoc = pdf;
    for (var i = 1; i <= pdfDoc.numPages; i++) {
        renderPage(i)
    }
});

New Html

<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=4.0,user-scalable=no"/>
    <title>Document</title>
    <style type="text/css">
        canvas {
            width: 100%;
            height: 100%;
            border: 1px solid black;
        }
    </style>
    <script src="https://unpkg.com/pdfjs-dist@1.9.426/build/pdf.min.js"></script>
    <script type="text/javascript" src="index.js"></script>
</head>
<body>
</body>
</html>

After preparing js and html, use webview to load the online pdf (www.gjtool.cn/pdfh5/git.p... [1]),

webView?.loadUrl("file:///android_asset/index.html?https://www.gjtool.cn/pdfh5/git.pdf");

After running successfully, the pdf is also loaded.

Add two finger zoom

Good guy, the pdf is finally loaded. I'm happy to show the effect to the product.

"You've loaded it, but the font looks a little small. See if you can add the function of double finger scaling." Xiao Wang looked at the product,

"That must be."

Set webview to support zooming, and useWideViewPort to true, so that Webivew supports the viewport property of meta tag,

settings?.useWideViewPort = true
settings?.builtInZoomControls = true
settings?.setSupportZoom(true)
settings?.displayZoomControls = false //Do not display zoom button

Modify the meta attribute in html, set the minimum scale and maximum scale attributes, and set user scale to yes,

After running successfully, the pdf is successfully scaled with two fingers.

After reading the product, I nodded. I also happily submitted the code.

Signature cannot be displayed

I thought this little function had been developed and there was no big problem until my little sister came to me one day,

"There is a problem with your pdf display. When there is a signature on the pdf, the signature cannot be displayed"

"what?"

The signature cannot be displayed, but this one has not been self tested. Quickly find the test link to verify it. After verification, there is a problem with the display of the signature. The so-called signature is to affix the official seal or signature on the pdf. As shown in the figure below

(source network)

Signature is added to pdf later. For signature loading, simple js cannot be loaded successfully.

What should I do?

In fact, there is a very powerful third-party library, pdf.js[2], which has been handled for us. Pdf.js can obtain PDF through the address of PDF file or PDF data stream. The specific implementation is to call the interface function PDFJs.getDocument(url/buffer) to load PDF into html, process it through canvas, and then render the PDF file. Of course, the signature can also be displayed.

It's just a little troublesome to use. You need to download pdf.js at [3] and copy it to the assert folder in the Android project,

Finally, the loading method is the same as above, using webview to load. The disadvantage is that the package volume increases.

When we use pdf.js to load PDF by default, we will find that there are redundant control buttons at the top of the rendering, such as the following figure:

However, these control buttons are not included in the UI design diagram. If you submit it like this, it is estimated that the little sister of the UI will come to me soon.

What should I do?

In fact, in the method used at the beginning of this article, there are no control buttons for loading PDF. Then the question arises. Can we combine the first method with pdf.js to load?

Pdf.js mainly contains two core library files, one pdf.js and one pdf.worker.js. One is responsible for API parsing and the other is responsible for core parsing. If it needs to be combined with the first method, we will copy the three files pdf.js, pdf.worker.js and pdf.sandbox.js and put them into asset.

Add references to pdf.js, pdf.worker.js, etc. in the script tag in html,

<script type="text/javascript" src="pdf.js"></script>
<script type="text/javascript" src="pdf.worker.js"></script>
<script type="text/javascript" src="pdf.sandbox.js"></script>
<script type="text/javascript" src="index.js"></script>

Modify the index.js file

var url = location.search.substring(1);

function createPage() {
    var div = document.createElement("canvas");
    document.body.appendChild(div);
    return div;
}

alert(url);

function renderPage(num) {
    pdfDoc.getPage(num).then(function (page) {
        var viewport = page.getViewport({ scale: 2.0 });
        var canvas = createPage();
        var ctx = canvas.getContext('2d');

        canvas.height = viewport.height;
        canvas.width = viewport.width;

        page.render({
            canvasContext: ctx,
            viewport: viewport
        }).promise.then(() => {});
    });
}

pdfjsLib.getDocument(url).promise.then(function (pdf) {
    pdfDoc = pdf;
    for (var i = 1; i <= pdfDoc.numPages; i++) {
        renderPage(i)
    }
});

You can see that after the operation is successful, the signature is successfully displayed, and the redundant control buttons will not be displayed. The effect drawing will not be displayed here.

I happily submitted the code again.

Incomplete display of Chinese characters

After another period of time, I was happily typing the code. At this time, the little sister of the test found me again,

"There is a problem with the pdf display here. Some words and characters are not displayed completely, resulting in the lack of characters"

"what?"

I quickly repeated the verification. When there are multiple fonts on the pdf, there is a probability that the characters will not be displayed completely. After checking, when running and loading this kind of pdf, some warning messages will appear on the console.

"Error during font loading"

This is because when parsing pdf, the default font library can no longer cover multiple fonts, so all fonts cannot be displayed completely.

How to deal with it?

If the default font library cannot be satisfied, add a new font library,

Add cMapUrl = "cdn.jsdelivr.net/npm/pdfjs-d... [4]" in pdf.js file,

params.rangeChunkSize = params.rangeChunkSize || DEFAULT_RANGE_CHUNK_SIZE;
params.CMapReaderFactory = params.CMapReaderFactory || DefaultCMapReaderFactory;
params.ignoreErrors = params.stopAtErrors !== true;
params.fontExtraProperties = params.fontExtraProperties === true;
params.pdfBug = params.pdfBug === true;
params.enableXfa = params.enableXfa === true;
params.cMapPacked = true
params.cMapUrl = "https://cdn.jsdelivr.net/npm/pdfjs-dist@2.2.228/cmaps/"

ok, run and see that the Chinese has been displayed completely.

Above, the problem of webview loading pdf has been basically solved. For the scheme of webview loading pdf, the main problems are as follows:

  • Double finger zoom;
  • The signature cannot be displayed;
  • There are redundant control buttons;
  • Incomplete display of Chinese characters.

These are the main problems in loading pdf, and other small problems are easy to solve.

All the code has been placed in github: PDF WebView [5]

About this article

Author: Fu Xi https://juejin.cn/post/7017840637450043422

reference material

[1]

https://www.gjtool.cn/pdfh5/git.pdf%EF%BC%89

[2]

https://github.com/mozilla/pdf.js

[3]

https://mozilla.github.io/pdf.js/

[4]

https://cdn.jsdelivr.net/npm/pdfjs-dist@2.2.228/cmaps/

[5]

https://github.com/fuusy/PdfWebview

Posted on Wed, 10 Nov 2021 01:35:00 -0500 by godwisam