Hide navigation sidebar
Hide table of contents sidebar
Skip to content
Back to top
View this page
Toggle table of contents sidebar
Find #mupdf on Discord
Do you have any feedback on this page?

# Using MuPDF WASM

## Installing

- From the command line, select the folder you want to work from and do:

  > `npm install mupdf`

- To verify your installation you can then create a JavaScript file as such:

  >     const mupdf = require("mupdf");
  >     console.log(mupdf);

- Save this file as “test.js”.

- Then run:

  > `node test.js`

- It should print the `mupdf` object along with details on the internal objects.

## Loading a Document

The following JavaScript sample demonstrates how to load a local document and then print out the page count. Ensure you have a valid PDF for “my_document.pdf” file alongside this JavaScript sample before trying it.

>     const fs = require("fs");
>     const mupdf = require("mupdf");

>     var input = fs.readFileSync("my_document.pdf");
>     var doc = mupdf.Document.openDocument(input, "application/pdf");
>     console.log(doc.countPages());

## Creating a PDF

The following JavaScript sample demonstrates how to create a blank PDF file with an assortment of annotations.

>     var fs = require("fs")
>     var mupdf = require("mupdf")

>     function createBlankPDF() {
>         var doc = new mupdf.PDFDocument()
>         doc.insertPage(0, doc.addPage([0, 0, 595, 842], 0, null, ""))
>         return doc
>     }

>     function savePDF(doc, path, opts) {
>         fs.writeFileSync(path, doc.saveToBuffer(opts).asUint8Array())
>     }

>     try {
>         var doc = createBlankPDF()
>         var page = doc.loadPage(0)
>         var annot

>         annot = page.createAnnotation("Text")
>         annot.setRect([200, 10, 250, 50])
>         annot.setContents("This is a Text annotation!")
>         annot.setColor([0,0.5,1])

>         annot = page.createAnnotation("FreeText")
>         annot.setRect([10, 10, 200, 50])
>         annot.setContents("This is a FreeText annotation!")
>         annot.setDefaultAppearance("TiRo", 18, [0])

>         annot = page.createAnnotation("Circle")
>         annot.setRect([100, 100, 300, 300])
>         annot.setColor([0, 1, 1])
>         annot.setInteriorColor([0.5, 0, 0])
>         annot.setBorderEffect("Cloudy")
>         annot.setBorderEffectIntensity(4)
>         annot.setBorderWidth(10)

>         annot = page.createAnnotation("Polygon")
>         annot.setColor([1, 0, 0])
>         annot.setInteriorColor([1, 1, 0])
>         annot.addVertex([10, 100])
>         annot.addVertex([200, 200])
>         annot.addVertex([30, 300])

>         annot = page.createAnnotation("Line")
>         annot.setColor([1, 0, 0])
>         annot.setInteriorColor([0, 0, 1])
>         annot.setLine([10, 300], [200, 500])
>         annot.setLineEndingStyles("None", "ClosedArrow")

>         annot = page.createAnnotation("Highlight")
>         annot.setColor([1, 1, 0])
>         annot.setQuadPoints([
>             [
>                 80, 70,
>                 190, 70,
>                 80, 90,
>                 190, 90,
>             ]
>         ])

>         annot = page.createAnnotation("Stamp")
>         annot.setRect([10, 600, 200, 700])
>         annot.setAppearance(null, null, mupdf.Matrix.identity, [ 0, 0, 100, 100 ], {}, "0 1 0 rg 10 10 50 50 re f")

>         annot = page.createAnnotation("Stamp")
>         annot.setRect([10, 750, 200, 850])
>         annot.setIcon("TOP SECRET")

>         annot = page.createAnnotation("FileAttachment")
>         annot.setRect([300, 10, 350, 60])
>         annot.setFileSpec(
>             doc.addEmbeddedFile (
>                 "readme.txt",
>                 "text/plain",
>                 "Lorem ipsum dolor...",
>                 new Date(),
>                 new Date(),
>                 false
>             )
>         )

>         annot = page.createAnnotation("Ink")
>         annot.setColor([0.5])
>         annot.setBorderWidth(5)
>         annot.addInkListStroke()
>         for (let i = 0; i < 360; i += 5) {
>             let y = Math.sin(i * Math.PI / 180)
>             annot.addInkListStrokeVertex([ 200 + i, 700 + y * 50 ])
>         }

>         page.createLink([ 500, 20, 590, 40 ], "https://mupdf.com/")
>         page.createLink([ 500, 40, 590, 60 ], doc.formatLinkURI({ type: "Fit", page: 0 }))

>         page.update()

>         savePDF(doc, "out.pdf", "")

>     } catch (err) {
>         console.error(err)
>         process.exit(1)
>     }

## Trying the Viewer

From the previous installation step you should have a folder called `node_modules`. From `node_modules/mupdf/lib` copy the 3 files `mupdf-wasm.js`, `mupdf-wasm.wasm` & `mupdf.js` into `platform/wasm/lib` in your local checkout of mupdf.git. Then you can open `platform/wasm/viewer/mupdf-view.html` to try it out.

Note

You need to run this HTML viewer page within a suitable Development Environment in order to load and view PDFs, if you see the error message “TypeError: this.mupdfWorker.openDocumentFromBuffer is not a function”, please read that section.

If running locally you can append `?file=my_file.pdf` to the browser URL to automatically load the PDF you need without using the “Open File” option from the GUI.

## Development Environment

### Browser setup

If you developing a WASM webpage it is important to note the following pre-requisites for local development:

- You should run the webpage in a localhost environment, or:

- Run the webpage locally in a browser which allows for a less strict origin policy allowing for local file loads - see below for how to do this in Firefox.

Artifex recommends Firefox as the browser of choice for local development due to its feature set of highly configurable developer options.

#### Firefox - enabling local files loads

If you are not running in a local host environment then this is required for local JS files to load & execute into the webpage without hindrance. It also allows for local PDF files to be chosen and loaded via the File JS interface.

By default Firefox is set to not allow local files to be loaded into the browser environment.

You can enable local file loads in Firefox by setting `security.fileuri.strict_origin_policy` in the `about:config` menu to `false`.

Steps to do this:

- Type `about:config` into a Firefox tab.

- Click “Accept the Risk and Continue”.

- Search for `security.fileuri.strict_origin_policy`.

- Click on the value to toggle it to `false`.

Note

If you do this you should probably use an entirely separate browser for development use - e.g. Firefox Developer Edition. Or reset the origin policy back to default at a later time.

### JavaScript methodology

Due to the asynchronous nature of a WASM web application Web Workers and Promises should be used within your application to handle the life-cycle and document events.

#### Web Workers

By utilizing Web Workers your webpage will be able to run scripts on background threads which will not interfere with the user interface. As there may be a fair amount of file I/O and page rendering occurring the Web Worker solution will allow for this whilst not hanging or slowing down (or seemingly crashing) your webpage.

See Mozilla’s page on Using Web Workers for more.

#### Promises

By utilizing Promises your JavaScript code will be better equipped to manage asynchronous operations. Code should be easier to follow and maintain as you develop your WASM application.

See Mozilla’s page on Using Promises for more.

Do you have any feedback on this page?

This software is provided AS-IS with no warranty, either express or implied. This software is distributed under license and may not be copied, modified or distributed except as expressly authorized under the terms of that license. Refer to licensing information at artifex.com or contact Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, CA 94129, USA, for further information.