# AI Source: https://webviewer-docs.mupdf.com/ai/index ## Build AI Citation in WebViewer **AI Citation** connects an LLM answer to exact locations in the PDF so users can verify where each claim comes from. The core API is [`text.locateSource()`](/api-reference/text/index#locatesource), which maps quoted source text to page coordinates you can highlight in the viewer. ### Why this matters In document-heavy workflows (legal, finance, compliance, research), users need traceability, not just fluent answers. AI Citation solves that by: * taking LLM-provided source quotes * locating those quotes in the document text layer * rendering highlight rects directly in WebViewer No additional LLM call is needed for the locate/highlight step. ### Prerequisites * A loaded PDF in WebViewer * LLM output that includes quote citations (not plain prose only) * High-quality Markdown/text extracted from the same PDF (for quote grounding) `text.locateSource()` is designed for high-quality model output. Avoid passing noisy, manually typed snippets. ### Flow `Your app: PDF -> Markdown -> LLM answer with quote citations` `MuPDF WebViewer APIs: text.locateSource() -> viewer.highlight() + viewer.scrollTo()` ```mermaid theme={null} flowchart LR subgraph yourApp [Your app] pdfDoc[PDF] markdownText[Markdown] llmAnswer[LLM answer with quote citations] pdfDoc --> markdownText --> llmAnswer end subgraph webViewerApis [MuPDF WebViewer APIs] locateSource["text.locateSource()"] highlightApi["viewer.highlight()"] scrollApi["viewer.scrollTo()"] locateSource --> highlightApi --> scrollApi end llmAnswer --> locateSource ``` * **You implement:** PDF-to-Markdown pipeline, prompt/response contract for quoted citations, and when citation actions should run (for example on answer render, hover, or click). * **WebViewer provides:** quote-to-coordinate mapping via `text.locateSource()`, plus rendering/navigation APIs (`viewer.highlight()` and `viewer.scrollTo()`). ### Recommended answer contract Use a structured response where each paragraph carries one or more citations with verbatim quote text. ```json theme={null} { "paragraphs": [ { "text": "MuPDF minimizes global state by isolating context and document lifetimes.", "citations": [ { "chunk_id": 12, "quote": "MuPDF has no global variables and therefore no hidden dependencies..." } ] } ] } ``` The important field for AI Citation is `quote`. That quote is what you pass to `text.locateSource()`. ### Example This example resolves all quotes from an answer, highlights every matched rect, and scrolls to the first resolved page. ```javascript theme={null} async function highlightAnswerSources(webViewer, paragraphs) { // Reuse locateSource results when the same quote appears multiple times. const quoteCache = new Map() // Collect every rect first, then draw highlights in a single call. const highlightRects = [] // Remember the first match so we can navigate users to it. let firstResolvedPage = null for (const paragraph of paragraphs) { const citations = Array.isArray(paragraph?.citations) ? paragraph.citations : [] for (const citation of citations) { // Normalize AI output and skip empty/non-string-like quote values. const quote = String(citation?.quote ?? '').trim() if (!quote) { continue } let located = quoteCache.get(quote) if (located === undefined) { try { // Map a quote to page/word rectangles in the loaded PDF. located = await webViewer.text.locateSource({ text: quote }) } catch { // Cache failures too, so repeated bad quotes do not re-query. located = null } quoteCache.set(quote, located) } // Ignore unresolved matches or unexpected result shapes. if (!located || !Array.isArray(located.words)) { continue } if (firstResolvedPage === null && Number.isFinite(located.pageIndex)) { firstResolvedPage = located.pageIndex } for (const word of located.words) { const rects = Array.isArray(word?.rects) ? word.rects : [] for (const rect of rects) { highlightRects.push({ color: '#ff00ff', pageIndex: located.pageIndex, rect, }) } } } } if (highlightRects.length > 0) { // Batch highlight for better performance and fewer UI updates. await webViewer.viewer.highlight({ rects: highlightRects }) } if (Number.isFinite(firstResolvedPage)) { // Move viewport to the first citation hit for immediate context. await webViewer.viewer.scrollTo({ type: webViewer.refs.scroll.type.PAGE, value: firstResolvedPage, }) } } ``` ### Production checklist * Cache `quote -> locateSource result` to remove duplicate lookups. * Handle unresolved quotes gracefully (skip or show "source not found"). * Batch highlight rects in one `viewer.highlight()` call when possible. * Optionally use `pageRange` in `text.locateSource({ text, pageRange })` for faster scoped lookup. * Keep citation click targets in the UI so users can jump between answer and source pages. ### Next steps * API details: [`text.locateSource()`](/api-reference/text/index#locatesource) # Annotations Source: https://webviewer-docs.mupdf.com/annotations/index ## Working with Annotations Annotations can be read from, and written to, a **MuPDF** document instance. In this way a developer is able to separately store annotations and programmatically manage them. ## Annotation data format Annotations are read and written to the **MuPDF WebViewer** in a **JSON** format, referenced as `Annotation[]` the format is as follows: ```javascript theme={null} { "annotations": [ { "oid": 0, "type": webViewer.refs.annotation.tool.TYPE_NAME, "pageIndex": 0, ... }, ... ] } ``` The data within each object is dependent on the annotation type, for example a highlight annotation might be as follows: **Example** ```javascript theme={null} { "annotations": [ { "oid": 30, "type": webViewer.refs.annotation.tool.HIGHLIGHT, "pageIndex": 0, "name": "81ba5e29-1930-4453-b594-f5771cf83a57", "rect": { "top": 10, "bottom": 40, "left": 10, "right": 40 }, "opacity": 1, "rotation": 0, "createdAt": "D:20250710153823+01'00'", "modifiedAt": "D:20250710153823+01'00'", "author": "Jane Doe", "canBePrinted": true, "locked": false, "rects": [ { "top": 10, "bottom": 40, "left": 10, "right": 40 } ], "fillColor": "#ffd100" } ] } ``` ## Reading annotation data To read annotation data from a document we use the [annotation.get()](/api-reference/annotation#get) method. Once we have the data we can work with it just as we would with any JSON object. **Example** ```javascript theme={null} async function saveAnnotationsLocally() { const annotations = await webViewer.annotation.get(); let annotsJSON = JSON.stringify(annotations); // for example store the data in local storage localStorage.setItem('pdfAnnotations', annotsJSON); webViewer.toast.show({ type: 'success', content: 'Annotations saved locally' }); } ``` ## Writing annotation data To write annotation data to a document we use the [annotation.add()](/api-reference/annotation#add) method. For example, to write annotations to the document from JSON data stored in local storage we could do the following: **Example** ```javascript theme={null} const savedAnnotations = JSON.parse(localStorage.getItem('pdfAnnotations') ?? '{ "annotations": [] }'); if (savedAnnotations?.annotations.length > 0) { await webViewer.annotation.add(savedAnnotations); webViewer.toast.show({ type: 'notification', content: 'Annotations loaded', }); } ``` Or to add a note annotation to a document we might do: **Example** ```javascript theme={null} const annotations = [ { type: webViewer.refs.annotation.tool.HIGHLIGHT, pageIndex: 0, rects: [{ top: 10, bottom: 40, left: 10, right: 40, }], fillColor: '#ffd100', } ]; await webViewer.annotation.add({ annotations }); webViewer.toast.show({ type: 'notification', content: 'Annotations added' }); ``` ## Removing annotation data Annotations can be removed from a document by using the [annotation.remove()](/api-reference/annotation#remove) method. To remove an annotation, provide either its `oid` (unique across the document) or its `name` and `pageIndex` (since `name` is only unique within a page). **Example** ```javascript theme={null} webViewer.annotation.remove({ annotations: [ { name: "squiggle_1", pageIndex: 0 } ] }); // remove by name webViewer.annotation.remove({ annotations: [ { oid: 30 } ] }); // remove by oid ``` ## Setting the Annotation Author When creating annotations in **MuPDF WebViewer** you can predefine the author of the annotation by listening to the `ANNOTATION_CREATE` event and then setting the annotation metadata for the author name. **Example** ```javascript theme={null} webViewer.addEventListener(webViewer.refs.event.type.ANNOTATION_CREATE, event => { event.data.annotation.author = 'Jane Doe'; webViewer.annotation.set({ annotations: [ event.data.annotation, ], }); }); ``` # Annotation API Source: https://webviewer-docs.mupdf.com/api-reference/annotation/index The [`annotation`](#annotation) object is an instance accessible from the main [MuPDFWebViewer](/api-reference/introduction#initmupdfwebviewer) instance as follows: ```javascript theme={null} const annotation = webViewer.annotation; ``` This assumes you have returned your instance name as `webViewer` from the [initMuPDFWebViewer()](/api-reference/introduction#initmupdfwebviewer) promise! ## annotation The `annotation` object has the following methods: ### remove ```typescript theme={null} remove(config: { annotations: ({ name: string; pageIndex: number } | { oid: number; pageIndex: number })[]; emitEvent?: boolean; }): Promise; ``` Removes annotations. #### Parameters The configuration object. Array of annotation identifiers to remove (by `{ name, pageIndex }` or `{ oid, pageIndex }`). Whether to emit events. #### Returns A Promise. **Example** ```javascript theme={null} webViewer.annotation.remove({annotations:[ {name:"squiggle_1", pageIndex:0}, {name:"rectangle_10", pageIndex:3}, {oid:36245, pageIndex:1} ] }); ``` ### get ```typescript theme={null} get(config?: { pageIndex: number }): Promise<{ annotations: Annotation[] }>; ``` Gets annotations. Returns array of annotations. #### Parameters Optional configuration. If omitted, returns all annotations for all pages. Page index. #### Returns A Promise that resolves to an object containing an `Annotation[]` array. **Example** ```javascript theme={null} webViewer.annotation.get({pageIndex:0}); ``` The `Annotation[]` array contains [annotation objects](#annotation-object), also see the [Working with Annotations guide](/annotations). ### add ```typescript theme={null} add(config: { annotations: Annotation[]; emitEvent?: boolean }): Promise<{ annotations: Annotation[] }>; ``` Adds annotations. Returns array of added annotations. #### Parameters The configuration object. An array of [annotation objects](#annotation-object). Whether to emit events. #### Returns A Promise that resolves to an object containing an `Annotation[]` array. The `Annotation[]` array contains [annotation objects](#annotation-object), also see the [Working with Annotations guide](/annotations). ### set ```typescript theme={null} set(config: { annotations: Annotation[]; emitEvent?: boolean }): Promise; ``` Updates annotations. #### Parameters The configuration object. An array of [annotation objects](#annotation-object). Whether to emit events. The `Annotation[]` array contains [annotation objects](#annotation-object), also see the [Working with Annotations guide](/annotations). ### undo ```typescript theme={null} undo(): Promise<{ success: boolean }>; ``` Undoes annotation operations and returns success status. #### Returns A Promise that resolves to a success status. **Example** ```javascript theme={null} webViewer.annotation.undo(); ``` ### redo ```typescript theme={null} redo(): Promise<{ success: boolean }>; ``` Redoes undone annotation operations and returns success status. #### Returns A Promise that resolves to a success status. **Example** ```javascript theme={null} webViewer.annotation.redo(); ``` ### Annotation Object The `Annotation` object type: ```typescript theme={null} export interface Annotation { oid: number; type: AnnotType; pageIndex: number; name: string; rect: TRect; rects?: TRect[]; opacity?: number; rotation?: number; createdAt?: string | null; modifiedAt?: string | null; author?: string; canBePrinted?: boolean; locked?: boolean; strokeColor?: string; strokeWidth?: number; imageData?: string; position?: TPoint; inkList?: TPoint[][]; fillColor?: string; strokeCloudRadius?: number; strokeDashPattern?: number[]; startPoint?: TPoint; endPoint?: TPoint; startPointStyle?: LineEnd; endPointStyle?: LineEnd; popupNote?: { oid?: number; rect: TRect; createdAt?: string | null; modifiedAt?: string | null; author?: string; }; contents?: string; vertices?: TPoint[]; fontColor?: string; textAlign?: TextAlign; fontFamily?: string; fontSize?: number; link?: { type: string; value: string | number; }; } ``` ### Supporting Types ```typescript theme={null} export interface TPoint { x: number; y: number; } export interface TRect { top: number; left: number; right: number; bottom: number; } ``` # Capture API Source: https://webviewer-docs.mupdf.com/api-reference/capture/index The [`capture`](#capture) object is an instance accessible from the main [MuPDFWebViewer](/api-reference/introduction#initmupdfwebviewer) instance as follows: ```javascript theme={null} const capture = webViewer.capture; ``` This assumes you have returned your instance name as `webViewer` from the [initMuPDFWebViewer()](/api-reference/introduction#initmupdfwebviewer) promise! ## capture The `capture` object has the following methods: ### selectAndExport ```typescript theme={null} selectAndExport(): Promise<{ imageBytes: Uint8Array }>; ``` Once this method is called it allows the user to select a region which is then exported as an image and returned as a promise with the image data. #### Returns A Promise that resolves to the captured image bytes. Captured images do not include viewer-only overlays such as those created with [viewer.highlight()](/api-reference/viewer/index#highlight). To include highlighted regions in output, create real PDF annotations with [annotation.add()](/api-reference/annotation/index#add) first. **Example** ```javascript theme={null} webViewer.capture.selectAndExport().then(captureSuccess, captureFailure) function captureSuccess(data) { console.log(`Capture data is: ${data.imageBytes}`); } function captureFailure(error) { console.error(`Capture error: ${error}`); } ``` # CHANGELOG Source: https://webviewer-docs.mupdf.com/api-reference/changelog/index ## 0.15.0 ### New Features * Extended the `position` parameter of Frontend API `viewer.addButton()` to support right toolbar placement (`TOOLBAR.RIGHT_SECTION.FIRST`, `TOOLBAR.RIGHT_SECTION.LAST`). ### Improvements * Added language normalization and an English fallback when an unsupported language code is configured. ## 0.14.0 ### Improvements * Improved parameter validation for redaction-related APIs to make validation rules clearer. * Improved page rendering for a sharper display. ### Bug Fixes * Fixed an issue where `redaction.get()` always extracted text as an empty string (`''`) when the `textData` parameter was provided. ## 0.13.3 ### Improvements * Added an interface to set the author of annotations on viewer load. * `initMuPDFWebViewer(/* ... */, { author: '-' });` ### Bug Fixes * Fixed an issue where clicking a page could trigger the `textSelectionChange` event unexpectedly. * Now triggers only when an existing text selection is cleared by a click. * Fixed an issue where replies could not be added to already-saved annotations. * Fixed an issue where adding a text box without `strokeWidth` via the Frontend API caused text to overflow outside the border. ## 0.13.2 ### Bug Fixes Fixed an issue where the `text.locateSource()` API did not work. ## 0.13.1 Do not use - please use version 0.13.2 or later. ### Bug Fixes * Fixed an issue where the viewer failed to work due to missing library files. ## 0.13.0 Do not use - please use version 0.13.2 or later. ### New Features * Added `text.locateSource()` API to locate the source of text cited by the LLM in a document. * Added title support for custom buttons created via the Frontend API. * `viewer.addButton()` - `title` ### Improvements * Improved Frontend API `unhighlight()` to support the `mode: 'all'` option. * Improved highlight color visibility when selecting search results in the Redaction panel. * Improved the Frontend API to ensure calls made before a document is opened are still executed. ### Bug Fixes * Fixed an issue where an incorrect error message was shown when an invalid `rect` value was passed via the Frontend API. * Fixed an issue where highlights were rendered in the wrong position when using the `keywords` property of `viewer.highlight()`. * Fixed an issue where calling `text.getSelected()` after selecting text across multiple paragraphs caused an error. ### ETC * Applied CSP (Content Security Policy) and removed internal inline scripts so deployments no longer need `unsafe-inline` in `script-src`. ## 0.12.1 ### Bug Fixes * Fixed an issue where the viewer failed to initialize when `libraryPath` was not specified. * Expected behavior: loads assets from the CDN ## 0.12.0 ### New Features * Added API support to hide the `Redact` button in the top toolbar. * `viewer.setViewVisibility()` - `refs.TOOLBAR_REDACTION` * Added API support to hide `Sticky Note` button in the top Annotate toolbar. * `viewer.setViewVisibility()` - `refs.ANNOTATION_TEXT_POPUP` ### Improvements * Improved Thumbnails panel UI responsiveness based on panel size. * Clarified the loading state when no document is loaded, and added messages for timeouts and end-of-document to improve UX. ### Bug Fixes * Fixed an issue where the selected redaction in the Redaction panel was deselected when creating a new redaction. ## 0.11.0 ### Improvements * Disabled license verification on localhost. (`127.0.0.1`, `localhost`, `*.test`) * Eliminates unnecessary network I/O during local development to reduce startup latency and improve developer experience. * Improved logging and error handling during viewer initialization. ## 0.10.0 ### Breaking Changes * Changed to load assets from the CDN server when calling `initMuPDFWebViewer()` without `libraryPath`. ### New Features * Added an API to configure the text selection menu. * Implemented the ability to hide the Redaction panel's Apply button via Frontend API. * `viewer.setViewVisibility()` - `refs.SIDE_VIEW_REDACTION_APPLY` * Added `removeEventListener()` to remove event listeners. ### Improvements * Improved the document page outline with shadows. * Improved panel animation behavior in mobile responsive layouts. * Left panel slides from left to right. * Right panel slides from right to left. ### Bug Fixes * Fixed an issue where specifying an unsaved annotation with Frontend API `viewer.scrollTo()` duplicating the annotation. * Fixed a memory issue causing `document.export()` to fail when exporting large documents. * Fixed an issue where replying to an annotation created a text annotation. * Fixed a calculation error that occurred when the page range and scroll range did not overlap. * Fixed issues where annotation opacity was applied twice. * Fixed an issue where opacity was applied twice to the AP (appearance) of text markup annotations. * Fixed an issue where opacity was applied twice when selecting an annotation. * Fixed an issue where editing a text markup annotation with opacity less than 1 applied opacity twice. ### ETC * Added a `title` attribute to the iframe wrapping the viewer to improve accessibility. * Removed a `name` attribute to the iframe wrapping the viewer. ## 0.9.1 ### ETC * Added a `name` attribute to the iframe wrapping the viewer to improve accessibility. ## 0.9.0 ### New Features * Added a `capture.selectAndExport()` API for region selection and export. ### Bug Fixes * Fixed an issue where [`text.search()`](/api-reference/text/index#search) `results` > `words` > `rects` were returned using the previous coordinate system. ### ETC * Removed duplicated, unnecessary font files from the library. ## 0.8.1 ### Improvements * Improved error messages when rect parameter is invalid during API usage. ### Bug Fixes * Fixed issue where memo annotations could not be controlled through Frontend API. * Fixed issue where redaction did not work when drawing, saving, or applying (occurred since v0.8.0). * Fixed issue where annotation creation via API failed when rect was missing (rect is optional for highlight annotations, etc.). * Fixed issue where link annotations were not being extracted. ## 0.8.0 ### Breaking Changes * Coordinate system in API parameters and return values have been changed from [user space to device space](/coordinate-system/). * Origin coordinates have been moved from bottom-left to top-left. * Origin is now unaffected by rotation values. * Affected APIs and events: * `viewer.scrollTo()` * `viewer.highlight()` * `text.search()` * `annotation.get()` * `annotation.add()` * `annotation.set()` * `redaction.get()` * `redaction.set()` * `redaction.add()` * `annotationCreate` * `annotationModify` * `annotationRemove` * `redactionCreate` * `redactionModify` * `redactionRemove` * `annotationSelectionChange` * Removed the rect property from `text.getSelected()` API. * Removed `customContextMenuExecute` event type. ### New Features * Added `viewer.defineRightClickAction()` API for defining a right-click action on the content area. * Added `rects`, `pageIndex` property to `text.getSelected()` API. * `rects` property returns an array of `TRect` that contains the selected text. * `pageIndex` property returns the page index of the selected text. ### Improvements * Updated to MuPDF.js v1.26.5. ### Bug Fixes * Fixed overlapping text issue when viewing documents containing CJK fonts. * Fixed an issue where the `withoutLoader` parameter was not applied when opening a document using `document.open()`. * Fixed an issue where `annotation.get()` did not work when `pageIndex` was not specified. * Fixed an issue where two lines were extracted as one line. ## 0.7.2 ### Bug Fixes * Fixed pages wrapper removal from PageInfo interface. * Fixed issue with not being able to select text with height 0. ## 0.7.1 ### Bug Fixes * Fixed an issue where the viewer works in viewing-mode when the `standalone` parameter was set to `true`. (Issue introduced in v0.6.0) ## 0.7.0 ### New Features * Enhanced `text.getSelected()` API to include `rect` property in return value. * Now returns both selected text content and DOMRect positioning information. * Added `viewer.openContextMenu()` API for programmatically opening context menus. * Added `TEXT_SELECTION_CHANGE` event type to the event system. * Allows listening for text selection changes within the document viewer. ## 0.6.0 ### New Features * Added free license support for viewing-only functionality with feature restrictions. * Free licenses are available starting from v0.6.0 with limited features. * Free license keys are not compatible with versions below 0.6.0. * Added `REDACTION` and `REDACTION_SEARCHING` panel types to `viewer.togglePanel()` API. * Added comprehensive redaction CRUD API operations: * `redaction.get()` - Retrieve redactions. * `redaction.add()` - Add new redactions. * `redaction.set()` - Update existing redactions. * `redaction.remove()` - Remove redactions. * `redaction.apply()` - Apply redactions. * Added `annotation.set()` method for updating existing annotations. ## 0.5.0 ### New Features * Added `text.getSelected()` to get selected text. * Added the ability to apply current properties as default in the annotation properties panel. * Enhanced `addEventListener()` functionality with comprehensive event system. * Added `EventType` enum with support for 25+ event types. * Added `EventDataMap` interface for type-safe event data handling. * Events now include scale changes, annotation operations, user interactions, and more. * Added the following redaction-related features: * Display borders for completed redaction areas. * Show overlay text. * Full redaction preview. ### Improvements * Improved support for loading multiple viewer instances. * Optimized static image loading using NgOptimizedImage. * Standardized feature terminology to the official term "redaction". * Changed "redacting" to "redaction" throughout the interface. ### Bug Fixes * Fixed typos and removed unnecessary code throughout the project. ## 0.4.0 ### New Features * Added embedded key validation. * If `standalone` parameter is set to `true`, the viewer will validate the key on the client side. * Added `viewer.defineAnnotSelectMenu()` to customize annotation selection menus. * Added `document.open()` to open a document. * Added `addEventListener()` to listen for events. * Added keywords parameter to API `viewer.highlight()`. * When search terms are passed to the keywords parameter, highlight effects are generated on the searched text. ### Improvements * Improved UI/UX for Redact panel. * Restricted the ability to specify transparent color for redaction applied areas. * Improved so that the entire text search results are highlighted in the document. * Changed the existing pagination to navigation functionality so that text search results can be checked one by one. * Enhanced visibility of keywords within text search results. ## 0.3.0 ### Breaking Changes * UI * Moved the floating navigation menus from the bottom of the screen to the center of the toolbar. * Changed the design of the quick search modal. ### Improvements * Changed the font to Inter. * Changed the assets to be loaded lazily. ### Bug Fixes * Fixed an issue where the author of a note annotation was cut off when it was too long. * Fixed an issue where the document panel buttons did not work on mobile screens. ## 0.2.0 ### New Features * Added API `viewer.defineDocumentPanel()` to customize document panels. * Added document panel menus. * Bookmark panel. * Markups panel. * Added external variable `refs` for API calls. ### Improvements * Improved to parse document name from `uri` parameter when opening a document without a name. ### Bug Fixes * Fixed the following issues in `viewer.setViewVisibility()`: * Issue where the left side of the toolbar could not be hidden. * Issue where the separator remained even when all file menus on the right side of the toolbar were hidden. ## 0.1.1 ### Breaking Changes * API * Removed `viewer.toggleMenu` ### Improvements * API * Modified `viewer.setLogo` to maintain the aspect ratio of the added logo. * Added error message for key validation failure in localhost environment. * Reduced bundle size. ### Bug Fixes * Fixed an issue where the default reading direction was incorrectly set from right to left in two-page view. * API * Fixed a bug that "view" parameter of `viewer.setViewVisibility` does not work. * Fixed an issue where some styles were not applied during loading due to missing viewer theme configuration logic. * Fixed the following issues that occurred when using `annotation.add()` and `annotation.remove()`: * Fixed an issue where the API did not terminate when the `annotations` parameter was an empty array. * Fixed an issue where an error occurred when color values were entered in uppercase. ## 0.1.0 ### Improvements * Improve the handling of errors that occur when passing invalid parameters to initialize the viewer. * Editing the author of a note annotation is now triggered by a single click instead of a double click. ## 0.1.0-alpha.2 ### Breaking Changes * UI * Remove the "Bookmark" panel. * Remove the page indicator on bottom-left of the screen. * API * `document.getBookmarks` is removed. * `document.setBookmarks` is removed. * 'BOOKMARK' type in `viewer.openSideView` is removed. * 'BOOKMARK' type in `viewer.togglePanel` is removed. ### New Features * Add the "Redact" tool. * Add the feature that allows you to select annotations by dragging. ### Improvements * Change the threshold for the top toolbar's right menu to be merged into the more menu from 575px to 767px. * Change that the top toolbar's tool menu is merged into the more menu when the screen size is less than 767px. # Document API Source: https://webviewer-docs.mupdf.com/api-reference/document/index The [`document`](#document) object is an instance accessible from the main [MuPDFWebViewer](/api-reference/introduction#mupdfwebviewer) instance as follows: ```javascript theme={null} const document = webViewer.document; ``` This assumes you have returned your instance name as `webViewer` from the [initMuPDFWebViewer()](/api-reference/introduction#initmupdfwebviewer) promise! ## document The `document` object has the following methods: ### open ```typescript theme={null} open(config: { url: string; filename?: string }): Promise; ``` Opens a PDF document. #### Parameters The configuration object. File path (or remote URL) to open. The file name to use for the file. #### Returns A Promise.
**Example** ```javascript theme={null} webViewer.document.open({url:"my-file.pdf", filename:"My File"}); // remote URL webViewer.document.open({url:"https://example.com/my-file.pdf", filename:"My File"}); ``` Please note: when loading a remote PDF then ensure that you have the correct CORS & CSP settings in place to provide the PDF. CORS (Cross-Origin Resource Sharing) and CSP (Content Security Policy) are both web security mechanisms. * CORS is about server-to-server communication from browsers * CSP is about what content your own webpage can load and execute If a remote PDF fails to load in **MuPDF WebViewer** then it is very possible that this might be related to one of these security mechanisms - ensure to check your console logs for any errors! ### download ```typescript theme={null} download(config?: { fileName?: string; includeAnnotations?: boolean }): Promise; ``` Downloads the PDF file. #### Parameters Optional configuration. If omitted, the original document filename is used and annotations are included. Name of the file to download. Default: `true`. Whether to include annotations. #### Returns A Promise. **Example** ```javascript theme={null} webViewer.document.download({fileName:"my-file.pdf", includeAnnotations:false}); ``` ### getPages ```typescript theme={null} getPages(config?: { pageRange?: string }): Promise<{ pages: PageInfo[] }>; ``` Gets PDF page information. #### Parameters Optional configuration. If omitted, all pages are returned. Default: `"all"`. Page index range (e.g., `"0-5, 7, 9-12"`, `"all"`). Page references are zero-indexed. #### Returns A Promise that resolves to page information. **Example** ```javascript theme={null} webViewer.document.getPages({pageRange:"0-3"}); // returns e.g. { pages: [ { pageIndex: 0, read: true, isVisible: true, bbox: { width: 595, height: 842, x: 0, y: 0 } } ] } ``` ### getPageCount ```typescript theme={null} getPageCount(): Promise<{ pageCount: number }>; ``` Gets the total number of pages in the PDF. #### Returns A Promise that resolves to the page count. **Example** ```javascript theme={null} webViewer.document.getPageCount(); // returns e.g { pageCount: number } ``` ### close ```typescript theme={null} close(): Promise; ``` Closes the currently opened PDF document. #### Returns A Promise. **Example** ```javascript theme={null} webViewer.document.close(); ``` ### print ```typescript theme={null} print(config?: { pageRange: string }): Promise; ``` Prints the PDF. #### Parameters Optional configuration. If omitted, the whole document is printed. Page index range (e.g., `"0-5, 7, 9-12"`, `"all"`). Page references are zero-indexed. #### Returns A Promise that resolves to the print result. **Example** ```javascript theme={null} webViewer.document.print({pageRange:"0-3"}); // returns e.g. { status: 'PRINTED' } ``` ### rotatePage ```typescript theme={null} rotatePage(config: { pageRange: string; degree: 0 | 90 | 180 | 270 | 360 }): Promise; ``` Rotates pages. #### Parameters The configuration object. Page index range (e.g., `"0-5, 7, 9-12"`, `"all"`). Page references are zero-indexed. Rotation degree. #### Returns A Promise. **Example** ```javascript theme={null} webViewer.document.rotatePage({pageRange:"0", degree:webViewer.refs.degree.DEG_90}); ``` ### getText ```typescript theme={null} getText(config?: { pageRange?: string }): Promise<{ pageIndex: number; text: string }[]>; ``` Extracts text from the PDF. #### Parameters Optional configuration. If omitted, the whole document is used. Default: `"all"`. Page index range (e.g., `"0-5, 7, 9-12"`, `"all"`). Page references are zero-indexed. #### Returns A Promise that resolves to extracted text for each page. **Example** ```javascript theme={null} async function getText() { return webViewer.document.getText({pageRange:"0"}); } function successCallbackGetText(data) { console.log(`Text Data is: ${data[0].text}`); } function failureCallbackGetText(error) { console.error(`Error getting text: ${error}`); } getText().then(successCallbackGetText, failureCallbackGetText); ``` ### export ```typescript theme={null} export(config?: { includeAnnotations?: boolean }): Promise; ``` Exports the PDF. Returns the PDF data in `Uint8Array` format. #### Parameters Optional configuration. If omitted, the document will be exported with annotations. Default: `true`. Whether to include annotations. #### Returns A Promise that resolves to the exported PDF bytes. **Example** ```javascript theme={null} async function exportDoc() { webViewer.toast.show({ type: 'notification', content: 'Exporting ... please wait' }); webViewer.document.export({includeAnnotations:true}).then(exportSuccess, exportFailure) }; async function exportSuccess(data) { webViewer.toast.show({ type: 'success', content: 'Exporting complete' }); // do what you need with the `data` } async function exportFailure(error) { webViewer.toast.show({ type: 'fail', content: 'Export error' }); console.error(`error: ${error}`); } exportDoc() ``` See [exporting troubleshooting](/troubleshooting#how-can-mupdf-webviewer-load-a-large-document-no-problem-but-have-problems-exporting-it%3F) ## Types Used By `document` ### `PageInfo` ```typescript theme={null} export interface PageInfo { pageIndex: number; read: boolean; isVisible: boolean; bbox: BBox; } ``` ### `BBox` ```typescript theme={null} export interface BBox { width: number; height: number; x: number; y: number; } ``` ### `PrintResult` ```typescript theme={null} export type PrintResult = { status: 'PRINTED' | 'CANCELLED'; } ``` # Event Listening Source: https://webviewer-docs.mupdf.com/api-reference/events/index **MuPDF WebViewer** can listen for the following events: | Event Type | Description | | ----------------------------- | ------------------------------------------------------------------ | | `ACTION_HISTORY_CHANGE` | When an action causes the history to change | | `ANNOTATION_CREATE` | A new annotation is created | | `ANNOTATION_MODIFY` | An existing annotation is modified | | `ANNOTATION_REMOVE` | An existing annotation is deleted | | `ANNOTATION_SELECTION_CHANGE` | Another annotation is selected | | `ANNOTATION_TOOL_CHANGE` | A different annotation tool type is selected | | `CURRENT_PAGE_INDEX_CHANGE` | The current page index changes | | `CURRENT_READING_PAGE_CHANGE` | The current reading page changes | | `DOCUMENT_DOWNLOAD` | A document download is initiated | | `KEYDOWN` | A key is pressed down | | `KEYUP` | A key is released | | `MOUSEDOWN` | A mouse button is pressed down | | `MOUSEUP` | A mouse button is released | | `POINTERDOWN` | Fires for all pointer down devices: mouse, touch, stylus/pen, etc. | | `POINTERUP` | Fires for all pointer up devices: mouse, touch, stylus/pen, etc. | | `REDACTION_CREATE` | A new redaction is created | | `REDACTION_MODIFY` | An existing redaction is modified | | `REDACTION_REMOVE` | An existing redaction is removed | | `SCALE_CHANGE` | The document scale changes | | `SCROLL_POSITION_CHANGE` | The document is scrolled | | `SIDE_VIEW_CLOSE` | The side view is closed | | `SIDE_VIEW_OPEN` | The side view is opened | | `TEXT_SEARCH_START` | A text search is started | | `TEXT_SELECTION_CHANGE` | The text selection changes | In order to register a listener just use the `webViewer.addEventListener` method. ## TypeScript Signatures ```typescript theme={null} addEventListener( type: T, callback: (event: { type: T; data: EventDataMap[T] }) => void ): void; removeEventListener( type: T, callback: (event: { type: T; data: EventDataMap[T] }) => void ): void; ``` ## Event Data Map `event.data` payloads by event type: | Event Type | `event.data` type | | ----------------------------- | ---------------------------------------------------------------- | | `SCALE_CHANGE` | `{ scale: number }` | | `ANNOTATION_TOOL_CHANGE` | `{ tool: AnnotType \| WidgetType }` | | `CURRENT_PAGE_INDEX_CHANGE` | `{ currentPageIndex: number }` | | `DOCUMENT_DOWNLOAD` | `{}` | | `SIDE_VIEW_OPEN` | `{ type: PanelSide }` | | `SIDE_VIEW_CLOSE` | `{ type: PanelSide }` | | `KEYDOWN` | `{ event: KeyboardEvent }` | | `KEYUP` | `{ event: KeyboardEvent }` | | `SCROLL_POSITION_CHANGE` | `{ position: 'top' \| 'bottom' \| 'topover' \| 'bottomover' }` | | `CURRENT_READING_PAGE_CHANGE` | `{ pageInfo: { pageIndex: number }[] }` | | `MOUSEDOWN` | `{ event: MouseEvent }` | | `MOUSEUP` | `{ event: MouseEvent }` | | `POINTERDOWN` | `{ event: PointerEvent }` | | `POINTERUP` | `{ event: PointerEvent }` | | `ANNOTATION_CREATE` | `{ annotation: Annotation }` | | `ANNOTATION_MODIFY` | `{ annotation: Annotation }` | | `ANNOTATION_REMOVE` | `{ annotation: Annotation }` | | `REDACTION_CREATE` | `{ redaction: Annotation }` | | `REDACTION_MODIFY` | `{ redaction: Annotation }` | | `REDACTION_REMOVE` | `{ redaction: Annotation }` | | `TEXT_SEARCH_START` | `{ keyword: string; caseSensitive: boolean; useRegex: boolean }` | | `ACTION_HISTORY_CHANGE` | `{ availUndoCount: number; availRedoCount: number }` | | `ANNOTATION_SELECTION_CHANGE` | `{ annotations: Annotation[] }` | | `TEXT_SELECTION_CHANGE` | `undefined` | # Examples ## Page Change ```javascript theme={null} webViewer.addEventListener(webViewer.refs.event.type.CURRENT_PAGE_INDEX_CHANGE, (e) => { console.log(Object.keys(e.data)); console.log(e.data.currentPageIndex); }); ``` ## Redaction and Annotation Events ### Redaction Create Event ```javascript theme={null} webViewer.addEventListener(webViewer.refs.event.type.REDACTION_CREATE, (e) => { console.log("REDACTION_CREATE"); }); ``` ### Annotation Removed Event ```javascript theme={null} webViewer.addEventListener(webViewer.refs.event.type.ANNOTATION_REMOVE, (e) => { console.log("ANNOTATION_REMOVE"); }); ``` ## Key Events ```javascript theme={null} // Listen for a key down webViewer.addEventListener(webViewer.refs.event.type.KEYDOWN, keyDown); function keyDown(e) { console.log(Object.keys(e.data)); for (var i in e.data) { console.log(e.data[i]); } console.log("Keycode="+e.data.event.keyCode); } ``` ## Pointer Events ```javascript theme={null} // Listen for a pointer down webViewer.addEventListener(webViewer.refs.event.type.POINTERDOWN, pointerDown); function pointerDown(e) { console.log(Object.keys(e.data)); for (var i in e.data) { console.log(e.data[i]); } console.log("clientX="+e.data.event.clientX); } ``` ## Listening for Multiple Key Presses For example, if you would like to add a shortcut for `ctrl+s` to save a document you could do the following to register for multiple key presses: ```javascript theme={null} webViewer.addEventListener(webViewer.refs.event.type.KEYDOWN, (event) => { if (event.data.event.ctrlKey && event.data.event.key === 's') { webViewer.document.download(); } }); ``` ## Removing Event Listeners Event listeners can be removed using the `webViewer.removeEventListener` method. You need to pass in the same function reference that was used to add the event listener. ```javascript theme={null} function keyDown(e) { console.log("Keycode="+e.data.event.keyCode); } webViewer.removeEventListener(webViewer.refs.event.type.KEYDOWN, keyDown); ``` # Introduction Source: https://webviewer-docs.mupdf.com/api-reference/introduction The MuPDF WebViewer API ## Initialization The MuPDF WebViewer API can only be accessed after initializing with [initMuPDFWebViewer()](#initmupdfwebviewer). This should return a [MuPDFWebViewer](#mupdfwebviewer) object to your code base or an error if there is any problem with the initialization. ### initMuPDFWebViewer ```typescript theme={null} export function initMuPDFWebViewer( selector: string, docURL: string, options?: { licenseKey?: string; libraryPath?: string; filename?: string; standalone?: boolean; withoutLoader?: boolean; author?: string; } ): Promise; ``` #### Parameters A [CSS selector](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Selectors) used to find the DOM element that will host the viewer. Supports any selector supported by `querySelector`. The URL of the document you wish to display. Optional initialization options. The [license key](https://webviewer.mupdf.com/pricing) to use. Library path for library assets. See [Optionally set the library path](/getting-started#optionally-set-the-library-path). Filename for the PDF. Whether to run in standalone mode. Whether to hide the document loader. Default author used in annotation metadata. #### Returns A Promise that resolves to a `MuPDFWebViewer` instance. **Example** ```javascript theme={null} import { initMuPDFWebViewer } from 'mupdf-webviewer' initMuPDFWebViewer('#viewer', 'sample.pdf', { libraryPath: 'lib', licenseKey: 'YOUR_LICENSE_KEY', }) .then(webViewer => { /* Returns a MuPDFWebViewer object for our API access */ webViewer.toast.show({ type: 'success', content: 'Opened' }); }) .catch(err => { /* Error handling */ console.log(err); }); ``` ## `MuPDFWebViewer` The `MuPDFWebViewer` instance exposes object instances and helper APIs as follows: ### `document` instance The PDF document instance. * [Document API](/api-reference/document/index) * [`document`](/api-reference/document/index#document) * [`document.open()`](/api-reference/document/index#open) * [`document.download()`](/api-reference/document/index#download) * [`document.getPages()`](/api-reference/document/index#getpages) * [`document.getPageCount()`](/api-reference/document/index#getpagecount) * [`document.close()`](/api-reference/document/index#close) * [`document.print()`](/api-reference/document/index#print) * [`document.rotatePage()`](/api-reference/document/index#rotatepage) * [`document.getText()`](/api-reference/document/index#gettext) * [`document.export()`](/api-reference/document/index#export) *** ### `viewer` instance The viewer user interface used for interaction. * [Viewer API](/api-reference/viewer/index) * [`viewer`](/api-reference/viewer/index#viewer) * [`viewer.toggleDialog()`](/api-reference/viewer/index#toggledialog) * [`viewer.getScale()`](/api-reference/viewer/index#getscale) * [`viewer.setScale()`](/api-reference/viewer/index#setscale) * [`viewer.zoomIn()`](/api-reference/viewer/index#zoomin) * [`viewer.zoomOut()`](/api-reference/viewer/index#zoomout) * [`viewer.getCurrentPageIndex()`](/api-reference/viewer/index#getcurrentpageindex) * [`viewer.getRotation()`](/api-reference/viewer/index#getrotation) * [`viewer.setRotation()`](/api-reference/viewer/index#setrotation) * [`viewer.rotateClockwise()`](/api-reference/viewer/index#rotateclockwise) * [`viewer.rotateCounterClockwise()`](/api-reference/viewer/index#rotatecounterclockwise) * [`viewer.setViewMode()`](/api-reference/viewer/index#setviewmode) * [`viewer.fitTo()`](/api-reference/viewer/index#fitto) * [`viewer.scrollTo()`](/api-reference/viewer/index#scrollto) * [`viewer.scrollToNextPage()`](/api-reference/viewer/index#scrolltonextpage) * [`viewer.scrollToPreviousPage()`](/api-reference/viewer/index#scrolltopreviouspage) * [`viewer.selectAnnotationTool()`](/api-reference/viewer/index#selectannotationtool) * [`viewer.toggleAnnotationTool()`](/api-reference/viewer/index#toggleannotationtool) * [`viewer.openSideView()`](/api-reference/viewer/index#opensideview) * [`viewer.closeSideView()`](/api-reference/viewer/index#closesideview) * [`viewer.togglePanel()`](/api-reference/viewer/index#togglepanel) * [`viewer.highlight()`](/api-reference/viewer/index#highlight) * [`viewer.unhighlight()`](/api-reference/viewer/index#unhighlight) * [`viewer.searchText()`](/api-reference/viewer/index#searchtext) * [`viewer.setViewVisibility()`](/api-reference/viewer/index#setviewvisibility) * [`viewer.addButton()`](/api-reference/viewer/index#addbutton) * [`viewer.openContextMenu()`](/api-reference/viewer/index#opencontextmenu) * [`viewer.addContextMenu()`](/api-reference/viewer/index#addcontextmenu) * [`viewer.defineDocumentPanel()`](/api-reference/viewer/index#definedocumentpanel) * [`viewer.defineTextSelectionMenu()`](/api-reference/viewer/index#definetextselectionmenu) * [`viewer.defineAnnotSelectMenu()`](/api-reference/viewer/index#defineannotselectmenu) * [`viewer.defineRightClickAction()`](/api-reference/viewer/index#definerightclickaction) * [`viewer.setBackgroundColor()`](/api-reference/viewer/index#setbackgroundcolor) * [`viewer.setPageBorderColor()`](/api-reference/viewer/index#setpagebordercolor) * [`viewer.setColor()`](/api-reference/viewer/index#setcolor) * [`viewer.setTheme()`](/api-reference/viewer/index#settheme) * [`viewer.setLanguage()`](/api-reference/viewer/index#setlanguage) * [`viewer.getSize()`](/api-reference/viewer/index#getsize) * [`viewer.setLogo()`](/api-reference/viewer/index#setlogo) *** ### `watermark` instance An interface to manage document watermarks. * [Watermark API](/api-reference/watermark/index) * [`watermark`](/api-reference/watermark/index#watermark) * [`watermark.create()`](/api-reference/watermark/index#create) *** ### `capture` instance The interface for capturing images from a document. * [Capture API](/api-reference/capture/index) * [`capture`](/api-reference/capture/index#capture) * [`capture.selectAndExport()`](/api-reference/capture/index#selectandexport) *** ### `text` instance The interface for the document text. * [Text API](/api-reference/text/index) * [`text`](/api-reference/text/index#text) * [`text.search()`](/api-reference/text/index#search) * [`text.locateSource()`](/api-reference/text/index#locatesource) * [`text.getSelected()`](/api-reference/text/index#getselected) *** ### `annotation` instance An interface for managing document annotations. * [Annotation API](/api-reference/annotation/index) * [`annotation`](/api-reference/annotation/index#annotation) * [`annotation.remove()`](/api-reference/annotation/index#remove) * [`annotation.get()`](/api-reference/annotation/index#get) * [`annotation.add()`](/api-reference/annotation/index#add) * [`annotation.set()`](/api-reference/annotation/index#set) * [`annotation.undo()`](/api-reference/annotation/index#undo) * [`annotation.redo()`](/api-reference/annotation/index#redo) *** ### `redaction` instance An interface for managing document redactions. * [Redaction API](/api-reference/redaction/index) * [`redaction`](/api-reference/redaction/index#redaction) * [`redaction.get()`](/api-reference/redaction/index#get) * [`redaction.set()`](/api-reference/redaction/index#set) * [`redaction.add()`](/api-reference/redaction/index#add) * [`redaction.remove()`](/api-reference/redaction/index#remove) * [`redaction.apply()`](/api-reference/redaction/index#apply) * [`Redaction Types`](/api-reference/redaction/index#redaction-types) *** ### `toast` instance An object used to display messages. * [Toast API](/api-reference/toast/index) * [`toast`](/api-reference/toast/index#toast) * [`toast.show()`](/api-reference/toast/index#show) ## Events How to listen to events in the **MuPDF WebViewer**. * [Events API](/api-reference/events/index) ## References A glossary of object references. * [References](/api-reference/refs/index) * [`webViewer.refs`](/api-reference/refs/index#webviewer-refs) * [`scroll`](/api-reference/refs/index#scroll) * [`fit`](/api-reference/refs/index#fit) * [`viewMode`](/api-reference/refs/index#viewmode) * [`degree`](/api-reference/refs/index#degree) * [`dialog`](/api-reference/refs/index#dialog) * [`panel`](/api-reference/refs/index#panel) * [`theme`](/api-reference/refs/index#theme) * [`language`](/api-reference/refs/index#language) * [`annotation`](/api-reference/refs/index#annotation) * [`visibility`](/api-reference/refs/index#visibility) * [`redaction`](/api-reference/refs/index#redaction) * [`text`](/api-reference/refs/index#text) * [`icon`](/api-reference/refs/index#icon) * [`event`](/api-reference/refs/index#event) # Redaction API Source: https://webviewer-docs.mupdf.com/api-reference/redaction/index The [`redaction`](#redaction) object is an instance accessible from the main [MuPDFWebViewer](/api-reference/introduction#initmupdfwebviewer) instance as follows: ```javascript theme={null} const redaction = webViewer.redaction; ``` This assumes you have returned your instance name as `webViewer` from the [initMuPDFWebViewer()](/api-reference/introduction#initmupdfwebviewer) promise! ## redaction The `redaction` object has the following methods: ### get ```typescript theme={null} get(config?: { textData: TextDataOption }): Promise<{ redactions: Annotation[] }>; ``` Returns an object containing (unapplied) redactions for the document. #### Parameters Optional configuration. If omitted, returns all redactions for all pages. The text data option for redactions. Required when `config` is provided. #### Returns A Promise that resolves to an object containing `redactions`. **Example** ```javascript theme={null} webViewer.redaction.get(); ``` Note: if redactions have been previously applied then these redactions are permanent and, as we should expect, will **not be** returned! Use `result.redactions` to access the redaction array. ### set ```typescript theme={null} set(config: { redactions: { oid: number; pageIndex: number; name: string; rect?: TRect; opacity?: number; author?: string; canBePrinted?: boolean; locked?: boolean; }[]; }): Promise; ``` Updates redactions. #### Parameters The configuration object. An array where each item requires `oid`, `pageIndex`, and `name`. Use this method to update existing redactions by unique identifier. ### add ```typescript theme={null} add(config: { redactions: { oid?: number; pageIndex: number; name?: string; rect: TRect; opacity?: number; author?: string; canBePrinted?: boolean; locked?: boolean; }[]; }): Promise<{ redactions: Annotation[] }>; ``` Adds redactions. #### Parameters The configuration object. An array where each item requires `pageIndex` and `rect`. `oid` and `name` are optional. ### remove ```typescript theme={null} remove(config: { redactions: { oid: number; name: string; pageIndex: number; }[]; }): Promise; ``` Removes redactions. #### Parameters The configuration object. An array where each item requires `oid`, `name`, and `pageIndex`. Each redaction item must include `oid`, `name`, and `pageIndex`. Matching redactions are removed. ### apply ```typescript theme={null} apply(config: { redactions: { oid: number; name: string; pageIndex: number; }[]; }): Promise; ``` Applies redactions. #### Parameters The configuration object. An array where each item requires `oid`, `name`, and `pageIndex`. Each redaction item must include `oid`, `name`, and `pageIndex`. Matching redactions are applied. ## Redaction Types The API uses different item shapes per method: ```typescript theme={null} type SetRedaction = { oid: number; pageIndex: number; name: string; rect?: TRect; opacity?: number; author?: string; canBePrinted?: boolean; locked?: boolean; }; type AddRedaction = { oid?: number; pageIndex: number; name?: string; rect: TRect; opacity?: number; author?: string; canBePrinted?: boolean; locked?: boolean; }; type TargetRedaction = { oid: number; name: string; pageIndex: number; }; ``` ### Supporting Types ```typescript theme={null} export interface TRect { top: number; left: number; right: number; bottom: number; } ``` # References Source: https://webviewer-docs.mupdf.com/api-reference/refs/index **MuPDF WebViewer** has a reference list for typical objects you will need to access and have control over. To access the keys for these objects use the `webViewer.refs` object. ## `webViewer.refs` ### `scroll` Object references for the scroll settings. #### `type` A sub-object of `scroll`. | Object references | | ----------------- | | `PAGE` | | `ANNOTATION` | **Example** `webViewer.refs.scroll.type.PAGE` *** ### `fit` Object references for the viewer sizing settings. #### `to` A sub-object of `fit`. | Object references | | ----------------- | | `WIDTH` | | `HEIGHT` | | `PAGE` | | `READ` | **Example** `webViewer.refs.fit.to.WIDTH` *** ### `viewMode` Object references for the viewer mode setting. | Object references | | ----------------- | | `SINGLE` | | `DOUBLE` | | `SINGLE_SCROLL` | | `DOUBLE_SCROLL` | | `EBOOK` | **Example** `webViewer.refs.viewMode.DOUBLE` *** ### `degree` Object references for the viewer rotation. | Object references | | ----------------- | | `DEG_0` | | `DEG_90` | | `DEG_180` | | `DEG_270` | **Example** `webViewer.refs.degree.DEG_90` *** ### `dialog` Object references for the dialog types. #### `type` A sub-object of `dialog`. | Object references | | ----------------- | | `PRINT` | | `SEARCH_TOOL` | **Example** `webViewer.refs.dialog.type.PRINT` *** ### `panel` Object references for the panel types. You can open a specific panel type or close the left or right panel. #### `open` A sub-object of `panel`. | Object references | | --------------------- | | `ANNOTATION` | | `ANNOTATION_PROPERTY` | | `BOOKMARK` | | `REDACTION` | | `REDACTION_SEARCHING` | | `TEXT_SEARCH` | | `THUMBNAIL` | #### `close` A sub-object of `panel`. | Object references | | ----------------- | | `LEFT` | | `RIGHT` | **Example** `webViewer.refs.panel.open.BOOKMARK` `webViewer.refs.panel.close.LEFT` *** ### `theme` Object references for the viewer theme. | Object references | | ------------------------ | | `DARK_MODE` | | `LIGHT_MODE` | | `SYSTEM_SYNCHRONIZATION` | **Example** `webViewer.refs.theme.DARK_MODE` *** ### `language` Object references for the viewer language. | Object references | | ----------------- | | `ENGLISH` | | `KOREAN` | | `JAPANESE` | **Example** `webViewer.refs.language.ENGLISH` *** ### `annotation` Object references for annotations. #### `tool` A sub-object of `annotation`. | Object references | | -------------------- | | `BUTTON` | | `CHECK_BUTTON` | | `CIRCLE` | | `CLOUD` | | `COMBO_BOX` | | `ERASER` | | `HIGHLIGHT` | | `INK` | | `LINE` | | `LINE_DIMENSION` | | `LINK` | | `LIST_BOX` | | `POLYGON` | | `POLYGON_DIMENSION` | | `POLYLINE` | | `POLYLINE_DIMENSION` | | `RADIO_BUTTON` | | `SIGNATURE` | | `SQUARE` | | `STAMP` | | `STRIKE` | | `TEXT_CALLOUT` | | `TEXT_FIELD` | | `TEXT_FREE` | | `TEXT_POPUP` | | `UNDERLINE` | **Example** `webViewer.refs.annotation.tool.STAMP` *** ### `redaction` Object references for redactions. #### `textDataOption` A sub-object of `redaction`. | Object references | | ----------------- | | `FULL` | | `NONE` | | `TEXT_ONLY` | **Example** `webViewer.refs.redaction.textDataOption.FULL` *** ### `visibility` Object references for setting view visibility. #### `view` A sub-object of `visibility`. | Object references | UI element | | --------------------------- | ---------------------------------------- | | `ANNOTATION_HIGHLIGHT` | Highlight annotation Icon | | `ANNOTATION_PROPERTY_PANEL` | Annotation Properties Panel | | `ANNOTATION_STAMP` | Stamp annotation Icon | | `ANNOTATION_STRIKE` | Strikeout annotation Icon | | `ANNOTATION_TEXT_POPUP` | Text Popup (Sticky Note) annotation Icon | | `ANNOTATION_UNDERLINE` | Underline annotation Icon | | `ANNOTATION_UNDO_REDO` | Undo/Redo annotation Icon | | `CONTEXT_MENU` | Context Menu | | `CONTEXT_MENU_COPY` | Copy option in Context Menu | | `CONTEXT_MENU_HIGHLIGHT` | Highlight option in Context Menu | | `CONTEXT_MENU_SEARCH` | Search option in Context Menu | | `CONTEXT_MENU_STRIKEOUT` | Strikeout option in Context Menu | | `CONTEXT_MENU_UNDERLINE` | Underline option in Context Menu | | `FLOATING_NAV` | Floating Navigation | | `FLOATING_NAV_SEARCH` | Floating Navigation Search | | `INDICATOR` | Indicator Bar | | `INDICATOR_PAGE_NUMBER` | Page Number in Indicator Bar | | `INDICATOR_SCALE` | Scale in Indicator Bar | | `SIDE_VIEW` | Side View | | `SIDE_VIEW_ANNOTATION` | Annotation Side View | | `SIDE_VIEW_REDACTION_APPLY` | Redaction Apply Side View | | `SIDE_VIEW_BOOKMARK` | Bookmark Side View | | `SIDE_VIEW_THUMBNAIL` | Thumbnail Side View | | `TOOLBAR` | Toolbar/Header | | `TOOLBAR_ANNOTATION` | Annotation Button in Toolbar/Header | | `TOOLBAR_DOWNLOAD` | Download Icon in Toolbar/Header | | `TOOLBAR_LEFT` | Left Area of Toolbar/Header | | `TOOLBAR_PRINT` | Print Icon in Toolbar/Header | | `TOOLBAR_REDACTION` | Redaction Button in Toolbar/Header | | `TOOLBAR_RIGHT` | Right Area of Toolbar/Header | | `TOOLBAR_ROTATE` | Rotate Icon in Toolbar/Header | | `TOOLBAR_VIEW_MODE` | View Mode Icon in Toolbar/Header | | `TOOLBAR_ZOOM` | Zoom Icon in Toolbar/Header | **Example** `webViewer.refs.visibility.view.TOOLBAR` *** ### `text` Object references for text settings. #### `align` A sub-object of `text`. | Object references | | ----------------- | | `CENTER` | | `LEFT` | | `RIGHT` | **Example** `webViewer.refs.text.align.LEFT` *** ### `icon` Object references for icons. | Object references | | -------------------------------- | | `BIDIRECTIONAL_HORIZONTAL_ARROW` | | `BOOKMARK` | | `CALENDAR` | | `CASE_SENSITIVE` | | `CHECK_MARK` | | `CIRCLE` | | `CIRCLE_CHECK_MARK` | | `CIRCLE_HORIZONTAL_3DOT` | | `CLIP` | | `COLLAPSE` | | `COMMENT` | | `COPY` | | `CROSS` | | `DOUBLE_DICE` | | `DOWNLOAD` | | `DOWN_CHEVRON` | | `DOWN_CHEVRON2` | | `DOWN_CHEVRON3` | | `EDIT` | | `ENTER_FULLSCREEN` | | `EXIT_FULLSCREEN` | | `EXPAND` | | `FILLED_ROUND_SQUARE_CHECK_MARK` | | `FILLED_STAMP` | | `FIRST` | | `FUNNEL` | | `GEAR` | | `GRID` | | `HAND` | | `HORIZONTAL_3DOT` | | `HYPERLINK` | | `IMAGE` | | `INVISIBLE` | | `LAST` | | `LEFT_CHEVRON` | | `LEFT_CHEVRON2` | | `LEFT_CHEVRON3` | | `LIST` | | `LIST2` | | `LOCKED` | | `MAIL` | | `MEDIA_FAST_FORWARD` | | `MEDIA_NEXT` | | `MEDIA_PAUSE` | | `MEDIA_PLAY` | | `MEDIA_PREVIOUS` | | `MEDIA_REWIND` | | `MEDIA_STOP` | | `MEMO` | | `MEMO2` | | `MINUS` | | `MONITOR` | | `MP3_FILE` | | `NEXT` | | `NOTE` | | `OCR_FILE` | | `PAGE` | | `PAGE_HEIGHT` | | `PAGE_SEARCH` | | `PAGE_WIDTH` | | `PENCIL` | | `PHONE` | | `PLUS` | | `POINTER` | | `POLYGON` | | `PREVIOUS` | | `PRINT` | | `REDO` | | `REFRESH` | | `RIGHT_CHEVRON` | | `RIGHT_CHEVRON2` | | `RIGHT_CHEVRON3` | | `ROTATE_CLOCKWISE` | | `ROTATE_COUNTER_CLOCKWISE` | | `ROUND_SQUARE_CHECK_MARK` | | `SAVE` | | `SEARCH` | | `SEND` | | `SHARE` | | `SIGN_OUT` | | `SIGNATURE` | | `SQUARE` | | `SQUARE_CHECK_MARK` | | `SQUARE_NEXT` | | `SQUARE_PREVIOUS` | | `STAMP` | | `TEXT_BOX` | | `TEXT_CURSOR` | | `TEXT_HIGHLIGHT` | | `TEXT_STRIKEOUT` | | `TEXT_UNDERLINE` | | `TRASH_CAN` | | `TXT_FILE` | | `TWO_WAY_HORIZONTAL_ARROW` | | `TWO_WAY_VERTICAL_ARROW` | | `UNDO` | | `UNLOCKED` | | `UP_CHEVRON` | | `UP_CHEVRON2` | | `UP_CHEVRON3` | | `USER` | | `VISIBLE` | **Example** `webViewer.refs.icon.REFRESH` *** ### `event` Object references for the event types. #### `type` A sub-object of `event`. | Object references | | ----------------------------- | | `ACTION_HISTORY_CHANGE` | | `ANNOTATION_CREATE` | | `ANNOTATION_MODIFY` | | `ANNOTATION_REMOVE` | | `ANNOTATION_SELECTION_CHANGE` | | `ANNOTATION_TOOL_CHANGE` | | `CURRENT_PAGE_INDEX_CHANGE` | | `CURRENT_READING_PAGE_CHANGE` | | `DOCUMENT_DOWNLOAD` | | `KEYDOWN` | | `KEYUP` | | `MOUSEDOWN` | | `MOUSEUP` | | `POINTERDOWN` | | `POINTERUP` | | `REDACTION_CREATE` | | `REDACTION_MODIFY` | | `REDACTION_REMOVE` | | `SCALE_CHANGE` | | `SCROLL_POSITION_CHANGE` | | `SIDE_VIEW_CLOSE` | | `SIDE_VIEW_OPEN` | | `TEXT_SEARCH_START` | | `TEXT_SELECTION_CHANGE` | **Example** `webViewer.refs.event.type.KEYDOWN` *** # Text API Source: https://webviewer-docs.mupdf.com/api-reference/text/index The [`text`](#text) object is an instance accessible from the main [MuPDFWebViewer](/api-reference/introduction#initmupdfwebviewer) instance as follows: ```javascript theme={null} const text = webViewer.text; ``` This assumes you have returned your instance name as `webViewer` from the [initMuPDFWebViewer()](/api-reference/introduction#initmupdfwebviewer) promise! ## text The `text` object has the following methods: ### search ```typescript theme={null} search(config: { keyword: string; caseSensitive?: boolean; useRegex?: boolean; pageRange?: string; }): Promise<{ results: { words: { prefix: string; keyword: string; suffix: string; redMarked: boolean; rects: TRect[]; }[]; pageIndex: number; }[]; }>; ``` Searches for text. #### Parameters The configuration object. Search keyword. Whether to be case sensitive. Whether to use regular expressions. Page index range to search (e.g., `"0-5, 7, 9-12"`, `"all"`). Page references are zero-indexed. If omitted, searches all pages. #### Returns A Promise that resolves to search results grouped by page. **Example** ```javascript theme={null} webViewer.text.search({keyword:"hello"}); // returns e.g. { results: [ { pageIndex:number, words: [ { prefix: string; keyword: string; suffix: string; redMarked: boolean; rects: { top: number; left: number; bottom: number; right: number; }[]; } ]; } ]; } ``` ### locateSource ```typescript theme={null} locateSource(config: { text: string; pageRange?: string }): Promise<{ pageIndex: number; words: [{ rects: TRect[] }]; }>; ``` Searches for the given text and returns its coordinates for highlighting. This is designed to be used with LLM-generated answers that include quoted source text, allowing you to map that text back to the PDF for highlighting. The input text is expected to be [high-quality Markdown](/ai/index#flow) from an LLM response. #### Parameters The configuration object. Query text. Page index range to search (e.g., `"0-5, 7, 9-12"`, `"all"`). Page references are zero-indexed. If omitted, searches all pages. #### Returns A Promise that resolves to the matched word rects for highlighting. **Example** ```javascript theme={null} webViewer.text.locateSource({text:text}).then( function success(data) { console.log(data); }, function failure(error) { alert(`Error locating text: ${error}`); } ); ``` Refer to [Source Locator: Example](/ai/index#example) for a more detailed example. ### getSelected ```typescript theme={null} getSelected(): Promise<{ text: string; rects: TRect[]; pageIndex: number } | undefined>; ``` Gets the currently selected text from a document. If there is no selected text then it returns `undefined`. #### Returns A Promise that resolves to the current selection, or `undefined` if there is no selection. **Example** ```javascript theme={null} async function getSelectedText() { return webViewer.text.getSelected(); } function success(result) { if (result) { console.log(`Text is: ${result.text}`); console.log(`Page index is: ${result.pageIndex}`); let rects = result.rects; console.log(`rect[0] metrics:\ntop=${rects[0].top}\nright=${rects[0].right}\nbottom=${rects[0].bottom}\nleft=${rects[0].left}`); } } function failure(error) { console.error(`Error: ${error}`); } getSelectedText().then(success, failure); ``` # Toast API Source: https://webviewer-docs.mupdf.com/api-reference/toast/index The [`toast`](#toast) object is an instance accessible from the main [MuPDFWebViewer](/api-reference/introduction#initmupdfwebviewer) instance as follows: ```javascript theme={null} const toast = webViewer.toast; ``` This assumes you have returned your instance name as `webViewer` from the [initMuPDFWebViewer()](/api-reference/introduction#initmupdfwebviewer) promise! ## toast The `toast` object has the following methods: ### show ```typescript theme={null} show(config: { type: 'success' | 'fail' | 'notification'; content: string; header?: string; timeout?: number; }): Promise; ``` Shows a toast message. #### Parameters Configuration object. Toast type (`"success" | "fail" | "notification"`). Toast content. Toast header. Display duration in milliseconds. #### Returns A Promise. **Example** ```javascript theme={null} webViewer.toast.show({ type: 'success', content: 'Document opened' }); ``` # Viewer API Source: https://webviewer-docs.mupdf.com/api-reference/viewer/index The [`viewer`](#viewer) object is an instance accessible from the main [MuPDFWebViewer](/api-reference/introduction#initmupdfwebviewer) instance as follows: ```javascript theme={null} const viewer = webViewer.viewer; ``` This assumes you have returned your instance name as `webViewer` from the [initMuPDFWebViewer()](/api-reference/introduction#initmupdfwebviewer) promise! ## viewer The `viewer` object has the following methods: ### toggleDialog ```typescript theme={null} toggleDialog(config: { dialogType: DialogType; visibility?: boolean }): Promise; ``` Toggles, shows or hides the print or search dialog. #### Parameters An object containing the dialog to show or hide. Dialog type. See [webViewer.refs.dialog.type](/api-reference/refs/index#dialog). Use to explicitly show or hide instead of toggling. #### Returns A Promise. **Example** ```javascript theme={null} webViewer.viewer.toggleDialog({dialogType: webViewer.refs.dialog.type.PRINT, visibility:true}); ``` ### getScale ```typescript theme={null} getScale(): Promise<{ scale: number }>; ``` Gets the current zoom scale. #### Returns A Promise that resolves to the current zoom scale. **Example** ```javascript theme={null} async function getScale() { return webViewer.viewer.getScale(); } function success(result) { console.log(`Scale is: ${result.scale}`); } function failure(error) { console.error(`Error: ${error}`); } getScale().then(success, failure); ``` ### setScale ```typescript theme={null} setScale(config: { scale: number }): Promise; ``` Sets the current zoom scale. #### Parameters Object containing the scale number. Zoom scale. #### Returns A Promise. **Example** ```javascript theme={null} webViewer.viewer.setScale({scale:140}); ``` ### zoomIn ```typescript theme={null} zoomIn(config?: { increment: number }): Promise; ``` Zooms in on the document. #### Parameters Optional configuration. Increment amount. Required when `config` is provided. #### Returns A Promise. **Example** ```javascript theme={null} webViewer.viewer.zoomIn({increment:10}); ``` ### zoomOut ```typescript theme={null} zoomOut(config?: { decrement: number }): Promise; ``` Zooms out on the document. #### Parameters Optional configuration. Decrement amount. Required when `config` is provided. #### Returns A Promise. **Example** ```javascript theme={null} webViewer.viewer.zoomOut({decrement:10}); ``` ### getCurrentPageIndex ```typescript theme={null} getCurrentPageIndex(): Promise<{ currentPageIndex: number }>; ``` Gets the current page index (zero-indexed). #### Returns A Promise that resolves to the current page index (zero-indexed). **Example** ```javascript theme={null} async function getPageIndex() { return webViewer.viewer.getCurrentPageIndex(); } function success(result) { console.log(`Page index is: ${result.currentPageIndex}`); } function failure(error) { console.error(`Error: ${error}`); } getPageIndex().then(success, failure); ``` ### getRotation ```typescript theme={null} getRotation(): Promise<{ degree: 0 | 90 | 180 | 270 }>; ``` Gets the current document rotation angle in degrees. #### Returns A Promise. **Example** ```javascript theme={null} async function getRotation() { return webViewer.viewer.getRotation(); } function success(result) { console.log(`Rotation is: ${result.degree}`); } function failure(error) { console.error(`Error: ${error}`); } getRotation().then(success, failure); ``` ### setRotation ```typescript theme={null} setRotation(config: { degree: 0 | 90 | 180 | 270 | 360 }): Promise; ``` Sets the document rotation angle in degrees. #### Parameters Object containing rotation value. Rotation degree. See [webViewer.refs.degree](/api-reference/refs/index#degree). #### Returns A Promise. **Example** ```javascript theme={null} webViewer.viewer.setRotation({ degree: webViewer.refs.degree.DEG_90 }); ``` ### rotateClockwise ```typescript theme={null} rotateClockwise(): Promise; ``` Rotates clockwise. #### Returns A Promise. **Example** ```javascript theme={null} webViewer.viewer.rotateClockwise(); ``` ### rotateCounterClockwise ```typescript theme={null} rotateCounterClockwise(): Promise; ``` Rotates counter-clockwise. #### Returns A Promise. **Example** ```javascript theme={null} webViewer.viewer.rotateCounterClockwise(); ``` ### setViewMode ```typescript theme={null} setViewMode(config: { viewMode: ViewMode }): Promise; ``` Sets the view mode for the document. #### Parameters Object containing the view mode. View mode. See [webViewer.refs.viewMode](/api-reference/refs/index#viewmode). #### Returns A Promise. **Example** ```javascript theme={null} webViewer.viewer.setViewMode({viewMode:webViewer.refs.viewMode.DOUBLE}); ``` ### fitTo ```typescript theme={null} fitTo(config: { to: FitMode }): Promise; ``` Sets the page fitting. #### Parameters Object containing the page fitting type. Fit mode. See [webViewer.refs.fit.to](/api-reference/refs/index#fit). #### Returns A Promise. **Example** ```javascript theme={null} webViewer.viewer.fitTo({to:webViewer.refs.fit.to.WIDTH}); ``` ### scrollTo ```typescript theme={null} scrollTo(config: { type: ScrollType; value: number }): Promise; scrollTo(config: { type: 'PAGE'; value: number; centerPoint?: { x: number; y: number } }): Promise; scrollTo(config: { type: 'ANNOTATION'; value: number; select?: boolean }): Promise; scrollTo(config: { type: 'ANNOTATION'; name: string; pageIndex: number; select?: boolean }): Promise; ``` Scrolls to a specific position on a page or to an annotation. #### Parameters The configuration object. Scroll type. See [webViewer.refs.scroll.type](/api-reference/refs/index#scroll). Scroll value. Required for `{ type: 'PAGE' }` and `{ type: 'ANNOTATION', value: number }` overloads. Center point of the page (`{ x: number, y: number }`). Only used when `type` is `webViewer.refs.scroll.type.PAGE`. Whether to select the annotation. Only used when `type` is `webViewer.refs.scroll.type.ANNOTATION`. Annotation name. Required for `{ type: 'ANNOTATION', name: string, pageIndex: number }`. Page index. Required for `{ type: 'ANNOTATION', name: string, pageIndex: number }`. Use one of these overload shapes: * `{ type: 'PAGE', value: number, centerPoint?: { x: number; y: number } }` * `{ type: 'ANNOTATION', value: number, select?: boolean }` * `{ type: 'ANNOTATION', name: string, pageIndex: number, select?: boolean }` #### Returns A Promise. **Example** ```javascript theme={null} // scroll to page 4 of the document webViewer.viewer.scrollTo({type:webViewer.refs.scroll.type.PAGE, value:3}); ``` ### scrollToNextPage ```typescript theme={null} scrollToNextPage(): Promise; ``` Scrolls to the next page. #### Returns A Promise. **Example** ```javascript theme={null} webViewer.viewer.scrollToNextPage(); ``` ### scrollToPreviousPage ```typescript theme={null} scrollToPreviousPage(): Promise; ``` Scrolls to the previous page. #### Returns A Promise. **Example** ```javascript theme={null} webViewer.viewer.scrollToPreviousPage(); ``` ### selectAnnotationTool ```typescript theme={null} selectAnnotationTool(config: AnnotationTool | AnnotationStampTool): Promise; ``` Selects an annotation tool. #### Parameters The configuration object. Annotation tool. See [webViewer.refs.annotation.tool](/api-reference/refs/index#tool). #### Returns A Promise. **Example** ```javascript theme={null} webViewer.viewer.selectAnnotationTool({tool:webViewer.refs.annotation.tool.HIGHLIGHT}); ``` ### toggleAnnotationTool ```typescript theme={null} toggleAnnotationTool(config: AnnotationTool | AnnotationStampTool): Promise; ``` Toggles an annotation tool. #### Parameters The configuration object. Annotation tool. See [webViewer.refs.annotation.tool](/api-reference/refs/index#tool). #### Returns A Promise. **Example** ```javascript theme={null} webViewer.viewer.toggleAnnotationTool({tool:webViewer.refs.annotation.tool.HIGHLIGHT}); ``` ### openSideView ```typescript theme={null} openSideView(config: { type: Panel }): Promise; ``` Opens a side view panel. #### Parameters An object containing the side view panel to open. Panel type. See [webViewer.refs.panel.open](/api-reference/refs/index#panel). #### Returns A Promise. **Example** ```javascript theme={null} webViewer.viewer.openSideView({type:webViewer.refs.panel.open.BOOKMARK}) ``` ### closeSideView ```typescript theme={null} closeSideView(config: { type: PanelSide }): Promise; ``` Closes a side view panel. #### Parameters An object containing the side view panel to close. Panel type. See [webViewer.refs.panel.close](/api-reference/refs/index#panel). #### Returns A Promise. **Example** ```javascript theme={null} webViewer.viewer.closeSideView({type: webViewer.refs.panel.close.RIGHT}); ``` ### togglePanel ```typescript theme={null} togglePanel(config: { type: Panel }): Promise; ``` Toggles a panel visibility. #### Parameters An object containing the side view to toggle. Panel type. See [webViewer.refs.panel.open](/api-reference/refs/index#panel). #### Returns A Promise. **Example** ```javascript theme={null} webViewer.viewer.togglePanel({type:webViewer.refs.panel.open.BOOKMARK}); ``` ### highlight ```typescript theme={null} highlight(config: { rects: HighlightRect[] }): Promise; highlight(config: { keywords: HighlightKeyword[] }): Promise; ``` Highlights text. #### Parameters The configuration object. Array of highlight region definitions. Array of keyword highlight definitions. Highlight color. Page index. Highlight opacity. Highlight area rect (`{ top: number; left: number; bottom: number; right: number }`). Keyword to search and highlight. Highlight color. Highlight opacity. Whether to perform case-sensitive matching. Whether to interpret `keyword` as a regular expression. #### Returns A Promise that resolves to an array of highlighted rects. **Example** ```javascript theme={null} webViewer.viewer.highlight({rects:[{color:"#ff00ff", pageIndex:0, rect:{left:0,right:100,top:0, bottom:100}}]}); ``` ### unhighlight ```typescript theme={null} unhighlight(config: { rects: HighlightedRect[] }): Promise; unhighlight(config: { mode: 'all' }): Promise; ``` Removes highlights. #### Parameters The configuration object. Provide either `rects` or `mode`. Array of highlighted rect references to remove. Mode for unhighlighting (for example, `"all"` to remove all highlights). Highlighted rect id. #### Returns A Promise. **Example** ```javascript theme={null} webViewer.viewer.unhighlight({rects:[{id:12}, {id:43}]}); ``` ```javascript theme={null} webViewer.viewer.unhighlight({mode:"all"}); // removes all highlights ``` ### searchText ```typescript theme={null} searchText(config: { keyword: string; caseSensitive?: boolean; useRegex?: boolean; emitEvent?: boolean; }): Promise; ``` Searches for text. This will open up the search panel if it is not already opened and run the search. #### Parameters The configuration object. Search keyword. Whether to be case sensitive. Whether to use regular expressions. Whether to emit events. #### Returns A Promise. **Example** ```javascript theme={null} webViewer.viewer.searchText({keyword:"hello", caseSensitive:false}) ``` ### setViewVisibility ```typescript theme={null} setViewVisibility(config: { view: HidableView; visibility: boolean }): Promise; ``` Sets a view visibility. #### Parameters The configuration object. View reference. See [webViewer.refs.visibility.view](/api-reference/refs/index#view). Boolean indicating visibility state. #### Returns A Promise. Refer to the [Customization: Display/Hide UI Guide](/customization/index#display%2Fhide-ui). ### addButton ```typescript theme={null} addButton(config: { buttons: { position: 'TOOLBAR.LEFT_SECTION.FIRST' | 'TOOLBAR.LEFT_SECTION.LAST' | 'TOOLBAR.RIGHT_SECTION.FIRST' | 'TOOLBAR.RIGHT_SECTION.LAST'; icon: IconName; label: string; onclick: Function; title?: string; }[]; }): Promise; ``` Adds button items to the toolbar. #### Parameters The configuration object. Array of button definitions. Button position: `"TOOLBAR.LEFT_SECTION.FIRST"` or `"TOOLBAR.LEFT_SECTION.LAST"` or `"TOOLBAR.RIGHT_SECTION.FIRST"` or `"TOOLBAR.RIGHT_SECTION.LAST"`. Button icon. See [webViewer.refs.icon](/api-reference/refs/index#icon). Button label (tooltip text on hover). Click handler function. Button title (printed text next to the icon). #### Returns A Promise. Refer to the [Customization: Add Buttons to Toolbar Guide](/customization/index#add-buttons-to-toolbar). ### openContextMenu ```typescript theme={null} openContextMenu(): Promise; ``` Opens the context menu. #### Returns A Promise. Refer to the [Customization: Define When to Show the Context Menu Guide](/customization/index#define-when-to-show-the-context-menu). ### addContextMenu ```typescript theme={null} addContextMenu(config: { menus: { type: 'MENU'; position: 'FIRST' | 'LAST'; icon?: string; label?: string; onclick?: Function; }[]; }): Promise; ``` Adds items to the context menu (this is the pop-up menu you see when you right click on a document). #### Parameters The configuration object. Array of menu definitions. Menu type: `"MENU"`. Item position: `"FIRST"` or `"LAST"`. Item icon. See [webViewer.refs.icon](/api-reference/refs/index#icon). Item label. Click handler function. #### Returns A Promise. Refer to the [Customization: Add Context Menu Guide](/customization/index#add-context-menu). ### defineDocumentPanel ```typescript theme={null} defineDocumentPanel(config: { items: { label: string; onclick: Function; icon?: string; }[]; }): Promise; ``` Defines document panel at the left side of the viewer toolbar. #### Parameters The configuration object. Array of panel item definitions. Item label. Click handler function. Item icon. See [webViewer.refs.icon](/api-reference/refs/index#icon). #### Returns A Promise. Refer to the [Customization: Define Document Panel Guide](/customization/index#define-document-panel). ### defineTextSelectionMenu ```typescript theme={null} defineTextSelectionMenu(config: { menus: { label: string; onclick: Function; icon?: IconName; }; }): Promise; ``` Defines the popup menu when selecting text #### Parameters The configuration object. Menu item definition. Menu label. Click handler. Menu icon. See [webViewer.refs.icon](/api-reference/refs/index#icon). #### Returns A Promise. Refer to the [Customization: Define Text Selection Menu Guide](/customization/index#define-text-selection-menu). ### defineAnnotSelectMenu ```typescript theme={null} defineAnnotSelectMenu(config: { html: string; style?: string; script?: string; tool?: AnnotType; }): Promise; ``` Defines the popup menu when selecting or creating an annotation. #### Parameters The configuration object. HTML content of the menu. CSS content of the menu. JavaScript content of the menu. Annotation tool that the menu is displayed for (see [webViewer.refs.annotation.tool](/api-reference/refs/index#tool)). #### Returns A Promise. When using `style` or `script`, please consider the following * `style`: CSS selectors will apply to all matching elements within the viewer scope. * `script`: JavaScript code will be executed in the viewer's context with the following limitations: * External resources cannot be accessed. * Variables declared will be in global scope. Refer to the [Customization: Define Annotation Selection Menu Guide](/customization/index#define-annotation-selection-menu). ### defineRightClickAction ```typescript theme={null} defineRightClickAction(config: { onclick: Function }): Promise; ``` Defines a right-click action on the content area. #### Parameters The configuration object. Click handler function. ### setBackgroundColor ```typescript theme={null} setBackgroundColor(config: { color: string }): Promise; ``` Sets the background color behind the document page. #### Parameters An object containing the color as a hexadecimal string. Color in format `#RRGGBB`. #### Returns A Promise. **Example** ```javascript theme={null} webViewer.viewer.setBackgroundColor({color: "#222222"}); ``` ### setPageBorderColor ```typescript theme={null} setPageBorderColor(config: { color: string }): Promise; ``` Sets the border color around document page instances in the viewer. #### Parameters An object containing the color as a hexadecimal string. Color in format `#RRGGBB`. #### Returns A Promise. **Example** ```javascript theme={null} viewer.setPageBorderColor({color: "#ff0000"}); ``` ### setColor ```typescript theme={null} setColor(config: { mainColor: string; subColor: string }): Promise; ``` Sets the primary (`mainColor`) and secondary (`subColor`) for the viewer user-interface. #### Parameters An object containing the `mainColor` and `subColor` hex color strings. Primary color in format `#RRGGBB`. Secondary color in format `#RRGGBB`. #### Returns A Promise. **Example** ```javascript theme={null} webViewer.viewer.setColor({mainColor: "#00ff00", subColor: "#0000ff"}); ``` ### setTheme ```typescript theme={null} setTheme(config: { type: Theme }): Promise; ``` Sets the overall theme of the viewer UI. #### Parameters An object containing the theme type. Theme type. See [webViewer.refs.theme](/api-reference/refs/index#theme). #### Returns A Promise. **Example** ```javascript theme={null} webViewer.viewer.setTheme({type:webViewer.refs.theme.DARK_MODE}); ``` ### setLanguage ```typescript theme={null} setLanguage(config: { key: Language }): Promise; ``` Sets the language for the UI. #### Parameters The configuration object. Language key. See [webViewer.refs.language](/api-reference/refs/index#language). #### Returns A Promise. ```javascript theme={null} webViewer.viewer.setLanguage({ key: webViewer.refs.language.ENGLISH }); ``` ### getSize ```typescript theme={null} getSize(): Promise; ``` Gets the viewer size. #### Returns A Promise that resolves to the viewer size. **Example** ```javascript theme={null} async function getSize() { return webViewer.viewer.getSize(); } function success(result) { console.log(`Size is: ${result.width}x${result.height}`); } function failure(error) { console.error(`Error: ${error}`); } getSize().then(success, failure); ``` ### setLogo ```typescript theme={null} setLogo(config: { url: string }): Promise; ``` Sets the brand logo (maximum size: 100x24px). It displays the logo in the top center of the viewer. #### Parameters An object containing a link to the logo image. Logo image URL. #### Returns A Promise. **Example** ```javascript theme={null} webViewer.viewer.setLogo({url: "/logo.png"}); ``` ## Supporting Types These types are used by the `viewer` APIs on this page. ### AnnotationTool ```typescript theme={null} export interface AnnotationTool { tool: AnnotType; annotation?: { opacity?: number; strokeColor?: string; strokeWidth?: number; fillColor?: string; strokeDashPattern?: number[]; startPointStyle?: LineEnd; endPointStyle?: LineEnd; fontColor?: string; fontFamily?: string; fontSize?: number; }; } ``` ### AnnotationStampTool ```typescript theme={null} export interface AnnotationStampTool { tool: AnnotType; width?: number; height?: number; } ``` ### HighlightRect ```typescript theme={null} export interface HighlightRect { color: string; pageIndex: number; opacity?: number; rect: TRect; } ``` ### HighlightKeyword ```typescript theme={null} export interface HighlightKeyword { keyword: string; color: string; opacity?: number; caseSensitive?: boolean; useRegex?: boolean; } ``` ### HighlightedRect ```typescript theme={null} export interface HighlightedRect { id: number; } ``` # Watermark API Source: https://webviewer-docs.mupdf.com/api-reference/watermark/index The [`watermark`](#watermark) object is an instance accessible from the main [MuPDFWebViewer](/api-reference/introduction#initmupdfwebviewer) instance as follows: ```javascript theme={null} const watermark = webViewer.watermark; ``` This assumes you have returned your instance name as `webViewer` from the [initMuPDFWebViewer()](/api-reference/introduction#initmupdfwebviewer) promise! ## watermark The `watermark` object has the following methods: ### create ```typescript theme={null} create(config: { watermarks: (TextWatermark | ImageWatermark)[] }): Promise; ``` #### Parameters An object containing an array of text or image watermarks. Array of text or image watermarks. Watermark type. Opacity. Watermark alignment. Rotation angle. X coordinate. Y coordinate. Whether visible in viewer. Whether printed. Page range. Watermark text. Font size. Text color. Font family name. Bold style. Italic style. Optional border config. Vertical repeat interval. Horizontal repeat interval. Border width. Border height. Border color. Border line width. Horizontal padding. Vertical padding. Watermark type. Opacity. Watermark alignment. Rotation angle. X coordinate. Y coordinate. Whether visible in viewer. Whether printed. Page range. Image scale. Image path. Vertical repeat interval. Horizontal repeat interval. #### Returns A Promise. **Example** ```javascript theme={null} webViewer.watermark.create({ watermarks: [ { type: 'Text', opacity: 0.2, align: 'CENTER', rotate: 45, x: 0, y: 0, text: 'CONFIDENTIAL', size: 32, color: '#ff0000', fontName: 'Helvetica', allowView: true, allowPrint: true }, { type: 'Image', opacity: 0.4, align: 'BOTTOM_RIGHT', rotate: 0, x: 0, y: 0, scale: 0.5, imagePath: '/watermark.png' } ] }); ``` ## Supporting Types ### `WatermarkAlignment` ```typescript theme={null} export enum WatermarkAlignment { CENTER = 'CENTER', TOP_LEFT = 'TOP_LEFT', TOP = 'TOP', TOP_RIGHT = 'TOP_RIGHT', LEFT = 'LEFT', RIGHT = 'RIGHT', BOTTOM_LEFT = 'BOTTOM_LEFT', BOTTOM = 'BOTTOM', BOTTOM_RIGHT = 'BOTTOM_RIGHT' } ``` ### `TextWatermark` ```typescript theme={null} export interface TextWatermark { type: 'Text'; opacity: number; align?: WatermarkAlignment; rotate: number; x: number; y: number; allowView?: boolean; allowPrint?: boolean; range?: string; text: string; size: number; color: string; fontName: string; bold?: boolean; italic?: boolean; border?: { width?: number; height?: number; color: string; strokeWidth: number; horizontalPadding?: number; verticalPadding?: number; }; repeatHeight?: number; repeatWidth?: number; } ``` ### `ImageWatermark` ```typescript theme={null} export interface ImageWatermark { type: 'Image'; opacity: number; align?: WatermarkAlignment; rotate: number; x: number; y: number; allowView?: boolean; allowPrint?: boolean; range?: string; scale: number; imagePath: string; repeatHeight?: number; repeatWidth?: number; } ``` # Coordinate System Source: https://webviewer-docs.mupdf.com/coordinate-system/index ## Origin Point and Y-Axis In **PDF**, traditionally the origin `(0, 0)` of a page is located at its **bottom-left point**. However, in **MuPDF WebViewer**, the origin `(0, 0)` of a page is located at its **top-left point** as this is more suited for web environments and digital displays. WebViewer Coordinate system This is also known as User space versus Device space ## Point Size Coordinates are float numbers and measured in **points**, where: * **one point equals 1/72 inches**. Typical document page sizes are **ISO A4** and **Letter**. A **Letter** page has a size of **8.5 x 11 inches**, corresponding to **612 x 792 points**. Now we know our document size the **MuPDF** coordinate system for the bottom right would be coordinate `(612, 792)`. ## Point Precision Theoretically, there are **infinitely many** coordinate positions on a PDF page. In practice however, at most the first 5 decimal places are sufficient for a reasonable precision. # Customization Source: https://webviewer-docs.mupdf.com/customization/index ## UI Customization UI customization is useful for both branding the MuPDF WebViewer as well as adding or removing features. ### Visual Customization The following visual customization is possible: WebViewer Visual Customization **WCAG** Color contrast The default light and dark themes are designed to achieve WCAG 2.1 Level AAA conformance for text contrast and at least AA conformance for icons. Developers customizing the UI should use tools like the Firefox Accessibility Inspector to maintain proper contrast ratios. #### Set Main and Sub colors This sets the main and sub colors - these reflect the button & text colors when these items are selected. See: [`viewer.setColor()`](/api-reference/viewer/index#setcolor). #### Set Background Color Sets the background color behind the document page. See [`viewer.setBackgroundColor()`](/api-reference/viewer/index#setbackgroundcolor). #### Set Page Border Color Sets the page border color. See [`viewer.setPageBorderColor()`](/api-reference/viewer/index#setpagebordercolor). #### Set Theme Sets the theme for light mode, dark mode or system synchronization. See [`viewer.setTheme()`](/api-reference/viewer/index#settheme). #### Set Logo Allows to set a logo in the top header area. See [`viewer.setLogo()`](/api-reference/viewer/index#setlogo). ### Functional Customization Sometimes you may want to alter the functionality of the **MuPDF WebViewer User Interface** by showing or hiding elements or by editing components. The available customizations are possible: #### Display/Hide UI You can display/hide the UI elements using the [`viewer.setViewVisibility()`](/api-reference/viewer/index#setviewvisibility) function. For example, if you want to hide the toolbar, you can do the following: **Example #1** ```javascript theme={null} webViewer.viewer.setViewVisibility({ view: webViewer.refs.visibility.view.TOOLBAR, visibility: false, }); ``` Or to hide a specific button like the Redaction panel's Apply button in the side view, do: **Example #2** ```javascript theme={null} webViewer.viewer.setViewVisibility({ view: webViewer.refs.visibility.view.SIDE_VIEW_REDACTION_APPLY, visibility: false, }); ``` Or to completely hide Annotation options, do: **Example #3** ```javascript theme={null} webViewer.viewer.setViewVisibility({ view: webViewer.refs.visibility.view.TOOLBAR_ANNOTATION, visibility: false, }); ``` #### Add Buttons to Toolbar You can add buttons to the toolbar using the [`viewer.addButton()`](/api-reference/viewer/index#addbutton) function. For example, if you want to add a button to the toolbar to enter fullscreen, you can do the following: **Example** ```javascript theme={null} webViewer.viewer.addButton({ buttons: [ { position: 'TOOLBAR.LEFT_SECTION.FIRST', icon: webViewer.refs.icon.ENTER_FULLSCREEN, label: 'Enter fullscreen', onclick: () => { document.body.requestFullscreen(); }, }, ], }); ``` Toolbar with fullscreen icon #### Add Context Menu You can add items to the context menu (the pop-up menu you see when you right click on a document in MuPDF WebViewer) using the [`viewer.addContextMenu()`](/api-reference/viewer/index#addcontextmenu) function. For example, if you want to add an item to rotate the page clockwise, you can do the following: **Example** ```javascript theme={null} webViewer.viewer.addContextMenu({ menus: [ { type: 'MENU', position: 'FIRST', icon: webViewer.refs.icon.ROTATE_CLOCKWISE, label: 'Rotate Clockwise', onclick: () => { webViewer.viewer.rotateClockwise(); }, }, ], }); ``` Content menu with rotate icon #### Define Document Panel You can define the document panel using the [`viewer.defineDocumentPanel()`](/api-reference/viewer/index#definedocumentpanel) function. For example, if you want to define the document panel to show the bookmark panel as **"Table of Contents"** and the annotation panel as **"Markups"** then you can do the following: **Example** ```javascript theme={null} webViewer.viewer.defineDocumentPanel({ items: [ { label: 'Table of Contents', icon: webViewer.refs.icon.BOOKMARK, onclick: () => { webViewer.viewer.togglePanel({ type: webViewer.refs.panel.open.BOOKMARK, }); }, }, { label: 'Markups', icon: webViewer.refs.icon.PENCIL, onclick: () => { webViewer.viewer.togglePanel({ type: webViewer.refs.panel.open.ANNOTATION, }); }, }, ], }); ``` "Bookmarks", "Table of Contents" and "Outline" are all synonomous terms - we can't guess which term you like most! 🙂 Customized Document Panel #### Define Text Selection Menu You can define the text selection menu by using the [`viewer.defineTextSelectionMenu()`](/api-reference/viewer/index#definetextselectionmenu) function. **Example** ```javascript theme={null} webViewer.viewer.defineTextSelectionMenu({ menus: [ { label: 'Ask AI', onclick: async () => { console.log(`Selected Texts: ${(await webViewer.text.getSelected()).text}`); }, icon: webViewer.refs.icon.SHARE, }, ], }); ``` Customized Text Selection Popup Panel #### Define Annotation Selection Menu You can define the annotation selection menu by using the [`viewer.defineAnnotSelectMenu()`](/api-reference/viewer/index#defineannotselectmenu) function. For example, if you want to define the annotation selection menu when selecting a highlight annotation, you can do something like the following: **Example** ```javascript theme={null} let html = `

Testing custom HTML & CSS for Highlight tool

`; let css = `#my-container { width:200px; height:200px; background-color: #FF00ff; color:#000; font-size:12px; margin:10px; }`; let js = `function helloWorld() { let myObj = document.getElementById('my-container') myObj.innerHTML='Hello World!' }`; webViewer.viewer.defineAnnotSelectMenu({ html: html, style: css, script: js, tool: webViewer.refs.annotation.tool.HIGHLIGHT, }) ``` Customized Annotation Popup Panel Ensure to set dimensions and font sizes in your CSS and scope your content correctly. We recommend using your company namespacing for the HTML DOM objects, CSS references as well as JavaScript! #### Define When to Show the Context Menu Normally when viewing a document the user can right-click on the document to activate the quick shortcut context menu: WebViewer Context Menu with Annotation options But what if you'd like to show this menu *as soon as a user selects* text? In this case you would need to use an event listener which detects if text is indeed selected and then opens the context menu by using the [`viewer.openContextMenu()`](/api-reference/viewer/index#opencontextmenu) function. **Example** ```javascript theme={null} webViewer.addEventListener(webViewer.refs.event.type.TEXT_SELECTION_CHANGE, (e) => { function getSelectedText() { webViewer.text.getSelected().then(successCallbackGetText, failureCallbackGetText) } function successCallbackGetText(result) { if (result) { webViewer.viewer.openContextMenu(); } } function failureCallbackGetText(error) { console.error(`Error: ${error}`); } getSelectedText(); }); ``` #### Define the Right Click Action If required the behaviour for the right-click option can be overridden by using the [`viewer.defineRightClickAction()`](/api-reference/viewer/index#definerightclickaction) function. **Example** ```javascript theme={null} webViewer.viewer.defineRightClickAction({onclick:myFunc}) function myFunc() { alert("Your JS here!"); } ``` # Getting Started Source: https://webviewer-docs.mupdf.com/getting-started/index ## Install Grab the package on NPM with: ```bash theme={null} npm install mupdf-webviewer ``` ## Prepare your DOM Ensure that your HTML page where you want to use **MuPDF WebViewer** has a dedicated DOM node available with the `id` you require, e.g. ```html theme={null}
``` ## Initialization Once ready you should initialize with [initMuPDFWebViewer()](/api-reference/introduction#initmupdfwebviewer). **Example** ```javascript theme={null} import { initMuPDFWebViewer } from 'mupdf-webviewer'; initMuPDFWebViewer( '#viewer', 'https://webviewer.mupdf.com/assets/demo/mupdf-book.pdf', ) .then(webViewer => { /* API */ }) .catch(err => { /* Error handling */ }); ``` File paths to PDFs should be absolute paths. ### Optionally set the library path The main JavaScript viewer libraries will be served from CDN by default, however you can choose to self-host these files by setting the `libraryPath` option during initialization. One of the benefits of self-hosting is that you can reference the files with *relative paths* from your own domain. #### Copy the library assets The library folder for **MuPDF WebViewer** is required to be copied to a library path of your choosing. ```bash Bash theme={null} cp -r node_modules/mupdf-webviewer/lib/* {YOUR_LIBRARY_PATH}/ ``` ```powershell PowerShell theme={null} Copy-Item -Path "node_modules/mupdf-webviewer/lib/*" -Destination "{YOUR_LIBRARY_PATH}/" ``` #### Set the library path during initialization Then set the `libraryPath` option during initialization to point to your chosen path. **Example** ```javascript theme={null} import { initMuPDFWebViewer } from 'mupdf-webviewer'; initMuPDFWebViewer( '#viewer', 'sample.pdf', { libraryPath: 'lib' }, ) .then(webViewer => { /* API */ }) .catch(err => { /* Error handling */ }); ``` In the case above our library path is simply "lib". File paths to PDFs can be *relative* or *absolute* paths if you are self-hosting the library files. ## Running You should be able to run on your local machine's browser. The following local domains work out of the box: * `localhost` * `127.0.0.1` * `*.test` ## Trial License For local development a license key is *not required*, however for deployment to production, a license key *is required* to use **MuPDF WebViewer**. Visit [MuPDF WebViewer](https://webviewer.mupdf.com/pricing) to obtain your trial license. Use the `licenseKey` option during initialization to set your license key. **Example** ```javascript theme={null} import { initMuPDFWebViewer } from 'mupdf-webviewer'; initMuPDFWebViewer( '#viewer', 'https://webviewer.mupdf.com/assets/demo/mupdf-book.pdf', { licenseKey: 'YOUR_LICENSE_KEY' }, ) .then(webViewer => { /* API */ }) .catch(err => { /* Error handling */ }); ``` When deploying to the web don't forget that a license key is required & specific to the domain you registered the key against. ## Opening Files You can open local and remote files with MuPDF Webviewer. You can also open files as blob URLs if required. ### Local files Depending on your integration you can open local files with absolute or relative paths, as follows: #### Absolute paths Supply the absolute path to your file as follows: **Example** ```javascript theme={null} webViewer.document.open({ url: `/doc/my-file.pdf` }); ``` #### Relative paths Supply the relative path to your file as follows: **Example** ```javascript theme={null} webViewer.document.open({ url:"../../doc/my-file.pdf" }); ``` ### Remote files Supply the URL to your file as follows: **Example** ```javascript theme={null} webViewer.document.open({ url: "https://example.com/my-file.pdf" }); ``` Remote PDF files shuold ensure to have the correct CORS permissions set. See the [warning in the API docs for `document.open` and remote files](/api-reference/document/index#open-warning). ### Loading Files as Blob URLS If you want to use [blob URLs](https://developer.mozilla.org/en-US/docs/Web/API/Blob), then MuPDF WebViewer can use that for the file data. The example below converts a PDF into a blob URL then opens it: **Example** ```javascript theme={null} async function openWithBlobURL(url) { const response = await fetch(url); const blob = await response.blob(); const blobUrl = URL.createObjectURL(blob); webViewer.document.open({ url: blobUrl }); } openWithBlobURL('/file.pdf') ``` See the [Sample Projects](/sample-projects) for more. # WebViewer Developer Documentation Source: https://webviewer-docs.mupdf.com/index ## A customizable PDF Viewer Component for the Web **MuPDF WebViewer** is an easy to use drop-in UI component for web pages which allows for in-context PDF viewing. * **Easy Integration** Drop it into your application with just a few lines of code. * **Built for AI** Designed to work seamlessly with LLMs, making it ideal for AI-powered PDF applications. * **Responsive Design** Deliver a flawless experience across devices, including desktops, tablets, and smartphones. * **View Annotations and Markups** With MuPDF WebViewer you get the full picture of the PDF with all the annotations retained. * **High Performance** Optimized for speed and smooth navigation, even with large or complex documents. * **Advanced Search** Find words quickly throughout your PDF. Search by case sensitivity or regular expression. * **Customizable Options** Customize the viewer to suit your brand or display the things you need. # Sample Projects Source: https://webviewer-docs.mupdf.com/sample-projects/index ## Open Source Projects Free to use, to help you get started: [MuPDF WebViewer Vanilla JS Sample](https://github.com/ArtifexSoftware/mupdf-webviewer-vanilla-js-sample) [MuPDF WebViewer React Sample](https://github.com/ArtifexSoftware/mupdf-webviewer-react-sample) [MuPDF WebViewer Vue Sample](https://github.com/ArtifexSoftware/mupdf-webviewer-vue-sample) [MuPDF WebViewer Angular Sample](https://github.com/ArtifexSoftware/mupdf-webviewer-angular-sample) # Troubleshooting Source: https://webviewer-docs.mupdf.com/troubleshooting/index ## How can MuPDF WebViewer load a large document no problem but have problems exporting it? This is a common issue with PDF WASM viewers, and it happens due to fundamental differences between how viewing and [exporting](/api-reference/document#export) work: ### Why Viewing Works Fine **Streaming & Chunked Loading:** * WASM PDF viewers (like MuPDF WebViewer) can request byte ranges for document pages on-demand * They only render visible pages, keeping most content in compressed form * Memory usage stays relatively low since only decoded page data is in RAM **Optimized Rendering:** * Pages are rendered on-demand as DOM elements * Decoded images/fonts are cached but can be garbage collected * The viewer works with compressed PDF streams directly ### Why Saving Fails **Memory Explosion:** * Saving often requires loading the entire PDF into memory at once * All pages, images, fonts, and metadata must be accessible simultaneously * WASM has limited memory (usually 4GB max, often much less) * Large PDFs can easily exceed available memory, especially if they contain many images as this data gets stored in vast base64 data representations **Processing Overhead:** * Saving may involve recompressing or restructuring the PDF * Form data, annotations, or modifications need to be merged * Cross-reference tables must be rebuilt * This creates additional memory pressure ### Browser-Specific Issues **Chrome/Edge:** * More generous with WASM memory * Better garbage collection **Firefox:** * Stricter memory limits * May need explicit memory management **Safari:** * Most restrictive with memory * Often requires server-side processing ### Solution **Update!** As of WebViewer `0.10.0` we have since resoved this issue by implementing a more efficient exporting mechanism that works within the memory constraints of browsers. If you are still experiencing issues please ensure you are using **the latest version of MuPDF WebViewer**!