Integrate WebViewer into React and Enable Barcode Scanning and Writing

This sample demonstrates a PoC for generating barcodes, stamping them onto a PDF and then reading them after they have been flattened onto the document. Watch a demo video or read a blog for additional details.

WebViewer provides a slick out-of-the-box responsive UI that enables you to view, annotate and manipulate PDFs and other document types inside any web project.

Click the button below to view the full project in GitHub.

1import React, { useRef, useEffect, useState } from 'react';
2import WebViewer from '@pdftron/webviewer';
3import Barcode from '../Barcode';
4import javascriptBarcodeReader from 'javascript-barcode-reader';
5import jsQR from "jsqr";
6import './webviewer.css';
7
8const WebViewerPDFTron = () => {
9 const viewer = useRef(null);
10 const [viewerInstance, setViewerInstance] = useState(null);
11
12 // if using a class, equivalent of componentDidMount
13 useEffect(() => {
14 WebViewer(
15 {
16 path: '/webviewer/lib',
17 initialDoc:
18 'https://pdftron.s3.amazonaws.com/downloads/pl/webviewer-demo.pdf',
19 fullAPI: true,
20 ui: 'legacy',
21 disabledElements: ['ribbons', 'cropToolGroupButton', 'snippingToolGroupButton']
22 },
23 viewer.current,
24 ).then(async (instance) => {
25 setViewerInstance(instance);
26 const {
27 documentViewer,
28 annotationManager,
29 Annotations,
30 Tools,
31 PDFNet,
32 getCanvasMultiplier,
33 } = instance.Core;
34 await PDFNet.initialize();
35
36 const createSnipTool = docViewer => {
37 const SnipTool = function() {
38 Tools.RectangleCreateTool.apply(this, arguments);
39 this.defaults.StrokeColor = new Annotations.Color('#ff0000');
40 this.defaults.StrokeThickness = 2;
41 };
42 SnipTool.prototype = new Tools.RectangleCreateTool();
43
44 return new SnipTool(docViewer);
45 };
46
47 const customSnipTool = createSnipTool(documentViewer);
48
49 instance.UI.setToolbarGroup('toolbarGroup-Edit');
50
51 // Register tool
52 instance.UI.registerTool({
53 toolName: 'SnipTool',
54 toolObject: customSnipTool,
55 // Icon made by https://www.flaticon.com/authors/smalllikeart from https://www.flaticon.com/
56 buttonImage: '../../../price.svg',
57 buttonName: 'snipToolButton',
58 tooltip: 'Snipping Tool',
59 });
60
61 // Add tool button in header
62 instance.UI.setHeaderItems((header) => {
63 header
64 .getHeader('toolbarGroup-Edit')
65 .get('cropToolGroupButton')
66 .insertAfter({
67 type: 'toolButton',
68 toolName: 'SnipTool',
69 })
70 .insertAfter({
71 type: 'actionButton',
72 img:
73 '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M0 0h24v24H0z" fill="none"/><path d="M17 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V7l-4-4zm-5 16c-1.66 0-3-1.34-3-3s1.34-3 3-3 3 1.34 3 3-1.34 3-3 3zm3-10H5V5h10v4z"/></svg>',
74 onClick: async () => {
75 // flatten annotations
76 const annots = await annotationManager.exportAnnotations();
77 const fdf_doc = await PDFNet.FDFDoc.createFromXFDF(annots);
78 const doc = await documentViewer.getDocument().getPDFDoc();
79 await doc.fdfUpdate(fdf_doc);
80 await doc.flattenAnnotations();
81 annotationManager.deleteAnnotations(annotationManager.getAnnotationsList());
82 documentViewer.refreshAll();
83 documentViewer.updateView();
84 documentViewer.getDocument().refreshTextData();
85 },
86 title: 'Flatten Annotations',
87 });
88 });
89
90 customSnipTool.addEventListener('annotationAdded', annotation => {
91 const pageIndex = annotation.PageNumber;
92 // get the canvas for the page
93 const rootElement = document.getElementsByTagName('apryse-webviewer')[0].shadowRoot;
94 const canvasMultiplier = getCanvasMultiplier();
95 const pageContainer = rootElement.getElementById(
96 'pageContainer' + pageIndex,
97 );
98 const pageCanvas = pageContainer.querySelector('.canvas' + pageIndex);
99 const topOffset = parseFloat(pageContainer.style.top) || 0;
100 const leftOffset = parseFloat(pageContainer.style.left) || 0;
101
102 const zoom = documentViewer.getZoomLevel();
103 const x = annotation.X * zoom - leftOffset;
104 const y = annotation.Y * zoom - topOffset;
105 const width = annotation.Width * zoom * canvasMultiplier;
106 const height = annotation.Height * zoom * canvasMultiplier;
107
108 const copyCanvas = document.createElement('canvas');
109 copyCanvas.width = width;
110 copyCanvas.height = height;
111 const ctx = copyCanvas.getContext('2d');
112 // copy the image data from the page to a new canvas so we can get the data URL
113 ctx.drawImage(pageCanvas, x, y, width, height, 0, 0, width, height);
114 const imageData = ctx.getImageData(0, 0, width, height);
115 const code = jsQR(imageData.data, imageData.width, imageData.height);
116
117 if (code) {
118 alert(`QR Code: ${code.data}`);
119 } else {
120 javascriptBarcodeReader({
121 image: copyCanvas,
122 barcode: 'code-128',
123 }).then((result) => {
124 alert(`Barcode: ${result}`);
125 }).catch(console.log);
126 }
127
128 annotationManager.deleteAnnotation(annotation);
129 });
130 });
131 }, []);
132
133 return (
134 <div className="container">
135 <div className="webviewer" ref={viewer}></div>
136 <Barcode instance={viewerInstance} />
137 </div>
138 );
139};
140
141export default WebViewerPDFTron;
142

Did you find this helpful?

Trial setup questions?

Ask experts on Discord

Need other help?

Contact Support

Pricing or product questions?

Contact Sales