
Research
/Security News
Toptal’s GitHub Organization Hijacked: 10 Malicious Packages Published
Threat actors hijacked Toptal’s GitHub org, publishing npm packages with malicious payloads that steal tokens and attempt to wipe victim systems.
mupdf-webviewer
Advanced tools
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.
npm install mupdf-webviewer
Note: A trial license key is required to use MuPDF WebViewer. For local development and testing, please generate a license key for "localhost" domain. Visit MuPDF WebViewer to obtain your trial license.
cp -r node_modules/mupdf-webviewer/lib/* {YOUR_LIBRARY_PATH}/
If you want to use the library in a web application, you need to copy the library assets to your web application.
<div id="viewer"></div>
You need to prepare DOM element with id viewer
in your html.
Initialization function must be called after the DOM element is created.
import { initMuPDFWebViewer } from 'mupdf-webviewer'
initMuPDFWebViewer('#viewer', 'sample.pdf', {
libraryPath: 'YOUR_LIBRARY_PATH',
licenseKey: 'YOUR_LICENSE_KEY',
})
.then(mupdf => {
/* API */
mupdf.toast.show({ type: 'success', content: 'Opened' });
})
.catch(err => {
/* Error handling */
});
export function initMuPDFWebViewer(
selector: string,
docURL: string,
options?: {
licenseKey: string;
libraryPath?: string;
filename?: string;
standalone?: boolean;
withoutLoader?: boolean;
}
): Promise<MuPDFWebViewer>;
MuPDF WebViewer provides reference variables for API calls.
mupdf.refs.icon.SHARE
MuPDF WebViewer provides two primary methods for saving documents:
mupdf.document.export()
.then(buffer => {
const blob = new Blob([ buffer ], { type: 'application/pdf' });
const objUrl = URL.createObjectURL(blob);
window.open(objUrl);
/* or anything you want */
});
mupdf.document.download();
For sharing annotations without the full document:
// Get annotations only
async function getAnnotationsAsJSON() {
const annotations = await mupdf.annotation.get();
return JSON.stringify(annotations);
}
// Save annotations to local storage
async function saveAnnotationsLocally() {
const annotations = await mupdf.annotation.get();
localStorage.setItem('pdfAnnotations', JSON.stringify(annotations));
mupdf.toast.show({
type: 'success',
content: 'Annotations saved locally'
});
}
// Load annotations from local storage
async function loadLocalAnnotations() {
const savedAnnotations = JSON.parse(localStorage.getItem('pdfAnnotations') ?? '{ "annotations": [] }');
if (savedAnnotations?.annotations.length > 0) {
await mupdf.annotation.add(savedAnnotations);
mupdf.toast.show({
type: 'notification',
content: 'Annotations loaded'
});
}
}
You can display/hide the UI of the viewer using viewer.setViewVisibility()
function.
For example, if you want to hide the toolbar, you can do the following:
mupdf.viewer.setViewVisibility({
view: mupdf.refs.visibility.view.TOOLBAR,
visibility: false,
});
You can add buttons to the toolbar using viewer.addButton()
function.
For example, if you want to add a button to the toolbar to enter fullscreen, you can do the following:
mupdf.viewer.addButton({
buttons: [
{
position: 'TOOLBAR.LEFT_SECTION.FIRST',
icon: mupdf.refs.icon.ENTER_FULLSCREEN,
label: 'Enter fullscreen',
onclick: () => {
document.body.requestFullscreen();
},
},
],
});
You can add context menu to the viewer using viewer.addContextMenu()
function.
For example, if you want to add a context menu to the viewer to rotate the page clockwise, you can do the following:
mupdf.viewer.addContextMenu({
menus: [
{
type: 'MENU',
position: 'FIRST',
icon: mupdf.refs.icon.ROTATE_CLOCKWISE,
label: 'Rotate Clockwise',
onclick: () => {
mupdf.viewer.rotateClockwise();
},
},
],
});
You can define document panel using viewer.setDocumentPanel()
function.
For example, if you want to define document panel to show the bookmark panel, you can do the following:
mupdf.viewer.defineDocumentPanel({
items: [
{
label: 'TOC',
icon: mupdf.refs.icon.BOOKMARK,
onclick: () => {
mupdf.viewer.togglePanel({
type: mupdf.refs.panel.open.BOOKMARK,
});
},
},
],
});
You can define annotation selection menu using viewer.defineAnnotSelectMenu()
function.
For example, if you want to define annotation selection menu when selecting a highlight annotation, you can do the following:
mupdf.viewer.defineAnnotSelectMenu({
html: `
<h1>This is a highlight</h1>
`,
tool: mupdf.refs.annotation.tool.HIGHLIGHT,
});
public addEventListener<T extends keyof EventDataMap>(
type: T,
callback: (event: { type: T; data: EventDataMap[T] }) => void
): void;
event: {
type: {
SCALE_CHANGE: EventType.SCALE_CHANGE,
ANNOTATION_TOOL_CHANGE: EventType.ANNOTATION_TOOL_CHANGE,
CURRENT_PAGE_INDEX_CHANGE: EventType.CURRENT_PAGE_INDEX_CHANGE,
DOCUMENT_DOWNLOAD: EventType.DOCUMENT_DOWNLOAD,
SIDE_VIEW_OPEN: EventType.SIDE_VIEW_OPEN,
SIDE_VIEW_CLOSE: EventType.SIDE_VIEW_CLOSE,
KEYDOWN: EventType.KEYDOWN,
KEYUP: EventType.KEYUP,
SCROLL_POSITION_CHANGE: EventType.SCROLL_POSITION_CHANGE,
CURRENT_READING_PAGE_CHANGE: EventType.CURRENT_READING_PAGE_CHANGE,
MOUSEDOWN: EventType.MOUSEDOWN,
MOUSEUP: EventType.MOUSEUP,
POINTERDOWN: EventType.POINTERDOWN,
POINTERUP: EventType.POINTERUP,
ANNOTATION_CREATE: EventType.ANNOTATION_CREATE,
ANNOTATION_MODIFY: EventType.ANNOTATION_MODIFY,
ANNOTATION_REMOVE: EventType.ANNOTATION_REMOVE,
REDACTION_CREATE: EventType.REDACTION_CREATE,
REDACTION_MODIFY: EventType.REDACTION_MODIFY,
REDACTION_REMOVE: EventType.REDACTION_REMOVE,
CUSTOM_CONTEXT_MENU_EXECUTE: EventType.CUSTOM_CONTEXT_MENU_EXECUTE,
TEXT_SEARCH_START: EventType.TEXT_SEARCH_START,
ACTION_HISTORY_CHANGE: EventType.ACTION_HISTORY_CHANGE,
ANNOTATION_SELECTION_CHANGE: EventType.ANNOTATION_SELECTION_CHANGE,
}
}
mupdf.addEventListener(mupdf.refs.event.type.KEYDOWN, (event) => {
if (event.data.event.ctrlKey && event.data.event.key === 's') {
mupdf.document.download();
}
});
document.download(config?: { fileName?: string; includeAnnotations?: boolean })
Downloads the PDF file.
fileName
(optional): Name of the file to downloadincludeAnnotations
(optional; default: true): Whether to include annotationsdocument.getPages(config?: { pageRange?: string })
Gets PDF page information.
pageRange
(optional; default: 'all'): Page index range (e.g., "1-5, 7, 9-12", "all")Returns:
{
pages: {
pageIndex: number;
read: boolean;
isVisible: boolean;
bbox: {
width: number;
height: number;
x: number;
y: number;
}
}[]
}
document.getPageCount()
Gets the total number of pages in the PDF.
Returns:
{ pageCount: number }
document.open(config: { url: string; filename: string })
Opens a PDF document.
document.close()
Closes the currently opened PDF document.
document.print(config: { pageRange: string })
Prints the PDF.
pageRange
(required): Page index range to print (e.g., "1-5, 7, 9-12", "all")Returns:
{ status: 'PRINTED' | 'CANCELLED' }
document.rotatePage(config: { pageRange: string; degree: 0 | 90 | 180 | 270 | 360 })
Rotates pages.
pageRange
(required): Page index range to rotate (e.g., "1-5, 7, 9-12", "all")degree
(required): Rotation angle (0, 90, 180, 270, 360)document.getText(config?: { pageRange?: string })
Extracts text from the PDF.
pageRange
(optional; default: 'all'): Page index range to extract text from (e.g., "1-5, 7, 9-12", "all")Returns:
{
pageIndex: number;
text: string;
}[]
document.export(config?: { includeAnnotations?: boolean })
Exports the PDF.
includeAnnotations
(optional; default: true): Whether to include annotationsReturns: PDF data in Uint8Array format
viewer.toggleDialog(config: { dialogType: refs.dialog.type; visibility?: boolean })
Shows or hides a dialog.
dialogType
(required): Dialog type (refs.dialog.type
: 'PRINT' | 'SEARCH_TOOL')visibility
(optional): Whether to show or hideviewer.getScale()
Gets the current zoom scale.
Returns:
{ scale: number }
viewer.setScale(config: { scale: number })
Sets the zoom scale.
scale
(required): Zoom scale valueviewer.zoomIn(config?: { increment: number })
Zooms in.
increment
(required): Zoom increment valueviewer.zoomOut(config?: { decrement: number })
Zooms out.
decrement
(required): Zoom decrement valueviewer.getCurrentPageIndex()
Gets the current page index.
Returns:
{ currentPageIndex: number }
viewer.getRotation()
Gets the current rotation angle.
Returns:
{ degree: 0 | 90 | 180 | 270 }
viewer.setRotation(config: { degree: 0 | 90 | 180 | 270 | 360 })
Sets the rotation angle.
degree
(required): Rotation angle (0, 90, 180, 270, 360)viewer.rotateClockwise()
Rotates clockwise.
viewer.rotateCounterClockwise()
Rotates counter-clockwise.
viewer.setViewMode(config: { viewMode: refs.viewMode; })
Sets the view mode.
viewMode
(required): View mode (refs.viewMode
: 'SINGLE' | 'SINGLE_SCROLL' | 'DOUBLE' | 'DOUBLE_SCROLL')viewer.fitTo(config: { to: refs.fit.to })
Sets page fitting.
to
(required): Fit mode (refs.fit.to
: 'WIDTH' | 'HEIGHT' | 'PAGE' | 'READ')viewer.scrollTo(config: { type: refs.scroll.type; value: number; centerPoint?: { x: number; y: number }; select?: boolean; name?: string; pageIndex?: number })
Scrolls to a specific position.
{
type: 'PAGE';
value: number;
centerPoint?: { x: number; y: number };
}
| {
type: 'ANNOTATION';
value: number;
select?: boolean;
}
| {
type: 'ANNOTATION';
name: string;
pageIndex: number;
select?: boolean;
}
type
(required): Scroll type (refs.scroll.type
: 'PAGE' | 'ANNOTATION')value
(required): Scroll value ('PAGE': Page index, 'ANNOTATION': Annotation oid)centerPoint
(optional): Center point of the pageselect
(optional): Whether to select the annotationname
(optional): Annotation namepageIndex
(optional): Page indexviewer.scrollToNextPage()
Scrolls to the next page.
viewer.scrollToPreviousPage()
Scrolls to the previous page.
viewer.selectAnnotationTool(config: AnnotationTool | AnnotationStampTool)
Selects an annotation tool.
tool
(required): Annotation tool (refs.annotation.tool
: 'HIGHLIGHT' | 'STRIKE' | 'UNDERLINE' | ...)viewer.toggleAnnotationTool(config: AnnotationTool | AnnotationStampTool)
Toggles an annotation tool.
tool
(required): Annotation tool (refs.annotation.tool
: 'HIGHLIGHT' | 'STRIKE' | 'UNDERLINE' | ...)viewer.openSideView(config: { type: refs.panel.open })
Opens a side view.
type
(required): Side view type (refs.panel.open
: 'THUMBNAIL' | 'BOOKMARK' | 'ANNOTATION' | 'REDACTION' | 'ANNOTATION_PROPERTY' | 'TEXT_SEARCH')viewer.closeSideView(config: { type: refs.panel.close })
Closes a side view.
type
(required): Side view type (refs.panel.close
: 'LEFT' | 'RIGHT')viewer.togglePanel(config: { type: refs.panel.open })
Toggles a panel.
type
(required): Panel type (refs.panel.open
: 'THUMBNAIL' | 'BOOKMARK' | 'ANNOTATION' | 'REDACTION' | 'ANNOTATION_PROPERTY' | 'TEXT_SEARCH')viewer.highlight(config: { rects: Array<{ color: string; pageIndex: number; opacity?: number; rect: { top: number; left: number; bottom: number; right: number } }> })
viewer.highlight(config: { keywords: Array<{ keyword: string; color: string; opacity?: number; caseSensitive?: boolean; useRegex?: boolean }> })
Highlights text.
rects
(required): Array of highlight area information
color
(required): Highlight colorpageIndex
(required): Page indexopacity
(optional): Highlight opacityrect
(required): Highlight area (top > bottom, right > left)keywords
(required): Array of keyword information
keyword
(required): Keyword to highlightcolor
(required): Highlight coloropacity
(optional; default: 0.5): Highlight opacitycaseSensitive
(optional; default: true): Whether to be case sensitiveuseRegex
(optional; default: false): Whether to use regular expressionsExample:
mupdf.viewer.highlight({ rects: [ { color: '#FF0000', pageIndex: 0, rect: { left: 100, top: 200, right: 200, bottom: 100 } } ] });
mupdf.viewer.highlight({ keywords: [ { keyword: 'keyword', color: '#FF0000' } ] });
Returns:
{
rects: { id: number }[]
}
viewer.unhighlight(config: { rects: { id: number }[] })
Removes highlights.
rects
(required): Array of highlight areas to removeviewer.searchText(config: { keyword: string; caseSensitive?: boolean; useRegex?: boolean; emitEvent?: boolean })
Searches for text in the viewer right panel.
keyword
(required): Search keywordcaseSensitive
(optional): Whether to be case sensitiveuseRegex
(optional): Whether to use regular expressionsemitEvent
(optional): Whether to emit eventsviewer.setViewVisibility(config: { view: refs.visibility.view; visibility: boolean })
Sets view visibility.
view
(required): View type (refs.visibility.view
: 'TOOLBAR' | 'FLOATING_NAV' | 'SIDE_VIEW' | 'CONTEXT_MENU' | 'INDICATOR' | ...)visibility
(required): Whether to show or hideviewer.addButton(config: { buttons: Array<{ position: 'TOOLBAR.LEFT_SECTION.FIRST' | 'TOOLBAR.LEFT_SECTION.LAST'; icon: refs.icon; label: string; onclick: Function }> })
Adds a button to the toolbar.
buttons
(required): Array of button information
position
(required): Button positionicon
(required): Button icon (refs.icon
: 'SHARE' | 'PENCIL' | 'MAIL' | ...)label
(required): Button labelonclick
(required): Click handlerviewer.addContextMenu(config: { menus: Array<{ type: 'MENU'; position: 'FIRST' | 'LAST'; icon?: refs.icon; label?: string; onclick?: Function }> })
Adds a context menu.
menus
(required): Array of menu information
type
(required): Menu typeposition
(required): Menu positionicon
(optional): Menu icon (refs.icon
: 'SHARE' | 'PENCIL' | 'MAIL' | ...)label
(optional): Menu labelonclick
(optional): Click handlerviewer.defineDocumentPanel(config: { items: Array<{ label: string; onclick: Function; icon?: refs.icon }> })
Defines document panel at the left side of the viewer toolbar.
items
(required): Array of menu item information
label
(required): Menu labelonclick
(required): Click handlericon
(optional): Menu icon (refs.icon
: 'SHARE' | 'PENCIL' | 'MAIL' | ...)viewer.defineAnnotSelectMenu(config: { html: string; style?: string; script?: string; tool?: refs.annotation.tool})
Defines a menu when selecting an annotation.
html
(required): HTML content of the menustyle
(optional): CSS content of the menuscript
(optional): JavaScript content of the menutool
(optional): Annotation tool that the menu is displayed for (refs.annotation.tool
: 'HIGHLIGHT' | 'STRIKE' | 'UNDERLINE' | ...)NOTE: When using style or script, please consider the following:
viewer.setBackgroundColor(config: { color: string })
Sets the background color.
color
(required): Background color hex code (e.g., '#000000')viewer.setPageBorderColor(config: { color: string })
Sets the page border color.
color
(required): Border color hex code (e.g., '#000000')viewer.setColor(config: { mainColor: string; subColor: string })
Sets main and sub colors.
mainColor
(required): Main color hex code (e.g., '#000000')subColor
(required): Sub color hex code (e.g., '#000000')viewer.setTheme(config: { type: refs.theme })
Sets the theme.
type
(required): Theme type (refs.theme
: 'LIGHT_MODE' | 'DARK_MODE' | 'SYSTEM_SYNCHRONIZATION')viewer.setLanguage(config: { key: refs.language })
Sets the language.
key
(required): Language key (refs.language
: 'ko' | 'en' | 'ja')viewer.getSize()
Gets the viewer size.
Returns:
{ width: number; height: number }
viewer.setLogo(config: { url: string })
Sets the brand logo (maximum size: 100x24px).
It displays the logo in the top center of the viewer.
url
(required): Logo URLwatermark.create(config: { watermarks: Array<TextWatermark | ImageWatermark> })
Creates watermarks.
watermarks
(required): Array of text or image watermarkstext.search(config: { keyword: string; caseSensitive?: boolean; useRegex?: boolean; pageRange?: string })
Searches for text in code.
keyword
(required): Search keywordcaseSensitive
(optional): Whether to be case sensitiveuseRegex
(optional): Whether to use regular expressionspageRange
(optional): Page index range to search (e.g., "1-5, 7, 9-12", "all")Returns:
{
results: {
words: {
prefix: string;
keyword: string;
suffix: string;
rects: {
top: number;
left: number;
bottom: number;
right: number;
}[];
}[];
}[];
}
text.getSelected()
Gets selected text.
Returns:
{
text: string;
}
annotation.remove(config: { annotations: Array<{ name: string; pageIndex: number } | { oid: number; pageIndex: number }>; emitEvent?: boolean })
Removes annotations.
annotations
(required): Array of annotation information to removeemitEvent
(optional): Whether to emit eventsannotation.get(config?: { pageIndex: number })
Gets annotations.
pageIndex
(optional): Page indexannotation.add(config: { annotations: Annotation[]; emitEvent?: boolean })
Adds annotations.
annotations
(required): Array of annotations to addemitEvent
(optional): Whether to emit eventsannotation.undo()
Undoes annotation operations.
annotation.redo()
Redoes undone annotation operations.
toast.show(config: { type: 'success' | 'fail' | 'notification'; content: string; header?: string; timeout?: number })
Shows a toast message.
type
(required): Toast type ('success' | 'fail' | 'notification')content
(required): Toast contentheader
(optional): Toast headertimeout
(optional): Display duration in millisecondsFAQs
The web viewer SDK using mupdf.js
The npm package mupdf-webviewer receives a total of 73 weekly downloads. As such, mupdf-webviewer popularity was classified as not popular.
We found that mupdf-webviewer demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
/Security News
Threat actors hijacked Toptal’s GitHub org, publishing npm packages with malicious payloads that steal tokens and attempt to wipe victim systems.
Research
/Security News
Socket researchers investigate 4 malicious npm and PyPI packages with 56,000+ downloads that install surveillance malware.
Security News
The ongoing npm phishing campaign escalates as attackers hijack the popular 'is' package, embedding malware in multiple versions.