ts-pdf 📄
A PDF.js-based PDF viewer written in TypeScript.
Features
- opening and viewing PDF files
- comparing two PDF files and visualizing differences
- adding and editing PDF annotations (supported annotation types are listed below)
- custom parsing and rendering for the supported annotation types
- annotation import/export to/from data-transfer objects that can be effortlessly serialized to JSON (useful for storing annotations in the separate database)
- compliance to the official PDF specification (v1.7)
- encrypted PDF-files support (supported encryption algorithms are listed below)
- responsive UI, friendly for touch devices
- easy color scheme customization using CSS variables to override the default values
- using Shadow DOM to minimize conflicts with outer HTML
- page and annotation parsing is run in background threads using web workers to minimize interface lags
How it works in a nutshell
PDF file source data (decrypted if needed) is parsed using the custom parser written from scratch.
Annotations of all the supported types are extracted from the source file.
The resulting PDF file (without the supported annotations) is handled by the PDF.js worker, which is used to render the file contents and build a text layer.
The extracted annotations are rendered to SVG on top of the pages by the custom PDF appearance stream renderer.
User can modify or delete any supported annotation or add new annotations of the supported types by using provided UI. The annotations can be imported or exported at any time using corresponding methods.
All changes are made can be saved to a new PDF file, which can be downloaded or returned to the caller as a byte array.
Currently supported annotation types
- Ink annotation
- Stamp annotation
- Line annotation
- Square annotation
- Circle annotation
- Polygon annotation
- Polyline annotation
- Highlight annotation
- Underline annotation
- Squiggly annotation
- Strikeout annotation
- Text annotation (only note icon)
- Free text annotation
Currently supported PDF encryption algorithms
- V1R2 (RC4 with 40-bit key)
- V2R3 (RC4 with 128-bit key)
- V4R4 (RC4 or AES with 128-bit key)
Yet to be implemented
- V5R5 (AES with 256-bit key)
- V5R6 (AES with 256-bit key, PDF 2.0)
Currently supported PDF stream encoding algorithms
Not implemented yet
- LZW
- ASCII base-85
- ASCII hexadecimal
- CCITT
- Run-length
Getting started
Installation into your project
npm install ts-pdf
Running the simplest example
import { TsPdfViewer, TsPdfViewerOptions } from "ts-pdf";
async function run(): Promise<void> {
const options: TsPdfViewerOptions = {
containerSelector: "#your-html-container-selector",
workerSource: "assets/pdf.worker.min.mjs", // path to the PDF.js worker script
userName: "your_username",
// you can check other properties using your editor hints
};
const viewer = new TsPdfViewer(options);
await viewer.openPdfAsync("your_file.pdf");
}
run();
⚠️for viewer to function properly its container element must have relative, absolute or fixed position!
⚠️the PDF.js worker version must match the version of the pdfjs-dist module. When you have the module installed, you can find the default worker file in your node_modules folder: './node_modules/pdfjs-dist/build/pdf.worker.min.mjs'.
Changing the color scheme
To apply a custom color scheme to the viewer, assign color values to the following CSS variables. Default values are used for omitted variables.
:root {
--tspdf-color-primary: rgba(77, 88, 115, 1);
--tspdf-color-primary-tr: rgba(77, 88, 115, 0.9);
--tspdf-color-secondary: rgb(113, 133, 150);
--tspdf-color-secondary-tr: rgba(113, 133, 150, 0.9);
--tspdf-color-accent: rgba(64, 72, 95, 1);
--tspdf-color-shadow: rgba(0, 0, 0, 0.75);
--tspdf-color-bg: rgba(128, 128, 128,1);
--tspdf-color-fg-primary: rgba(255, 255, 255, 1);
--tspdf-color-fg-secondary:rgba(187, 187, 187, 1);
--tspdf-color-fg-accent: rgb(255, 204, 0);
--tspdf-color-text-selection: rgba(104, 104, 128, 0.3);
}
Keyboard shortcuts
- alt + ctrl + o => open file (if the corresponding button is allowed in options)
- alt + ctrl + s => save file (if the corresponding button is allowed in options)
- alt + ctrl + x => close file (if the corresponding button is allowed in options)
- alt + ctrl + t => toggle preview panel visibility
- alt + ctrl + 1 => text selection mode
- alt + ctrl + 2 => hand drag mode
- alt + ctrl + 3 => annotation mode
- alt + ctrl + 4 => comparison mode
- escape => clear annotation (in annotation add mode)
- backspace => undo last action (in annotation add mode)
- enter => save annotation (in annotation add mode)
- ctrz + z => undo last annotation edit
- ↑ => zoom in
- ↓ => zoom out
- ← => previous page
- → => next page
- < => rotate left
- > => rotate right
Solving Angular app compilation issue
When using this module inside an Angular app you can face the problem that your project is not compiling because of 'SyntaxError: Unexpected token'. The cause of such behavior is that Angular 11.x and lower use Webpack v4.x that does not support fluent null-check syntax ('?.'), which is present in 'pdfjs-dist' build.
The easy solution is to replace
"main": "build/pdf.js"
with
"main": "es5/build/pdf.js"
inside
"/node_modules/pdfjs-dist/package.json"
The other one is to make your own build of PDF.js.
TODO list
add ink annotations support added in 0.1.0
add geometric annotations (line, polyline, polygon, square, circle) support added in 0.2.0
add text markup annotations (underline, strikeout, highlight, squiggly) support added in 0.4.0
add text annotations (note) support added in 0.4.0
add page rotation support added in 0.5.0
add annotation blending modes support added in 0.5.2
add custom stamp annotations support added in 0.6.0
optimize loading and saving files some optimizations were made in 0.6.2
add text caption support for line annotations added in 0.6.6
add free text annotations support added in 0.7.0
add 'undo' button and corresponding logic added in 0.7.0
move parser to background thread using web workers added in 0.9.0
add keyboard shortcutsadded in 0.10.0
add document comparison modeadded in 0.11.0
- add tooltips to buttons
- add user-frienly error messages on failed file opening
- make error messages more informative
- add proper support for linearized PDF files
- add more options for line annotations
- add more options for free text annotations
- add watermark tool (with watermark generator)
- add localizations
- add tests
- limit users to editing their own annotations only (optionally)
- further optimization of the parser and the renderer
- support for PDF 2.0 features (requires purchasing the specification)
- support for the rest of encryption algorithms (on request only)
- support for the rest of encoding algorithms (on request only)
External dependencies:
Running the demo
- Clone the repository to your local machine
- (optional) Change the host/port if needed in the 'ls-config.json' file
- Run the 'npm run start' command from the project folder
- Open the demo page in your web browser
Additional information