Enable Barcode Scanning and Writing with React

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 createSnipTool = ({ docViewer, Tools, Annotations }) => {
9 class SnipTool extends Tools.RectangleCreateTool {
10 constructor(viewer) {
11 super(viewer, 'SnipTool');
12 this.defaults.StrokeColor = new Annotations.Color('#ff0000');
13 this.defaults.StrokeThickness = 2;
14 }
15 }
16
17 return new SnipTool(docViewer);
18};
19
20const readBarcode = async (copyCanvas) => {
21 try {
22 const result = await javascriptBarcodeReader({
23 image: copyCanvas,
24 barcode: 'code-128',
25 });
26 alert(`Barcode: ${result}`);
27 } catch (error) {
28 console.log(error);
29 }
30};
31
32const flattenAllAnnotations = async ({ annotationManager, PDFNet, documentViewer }) => {
33 const annots = await annotationManager.exportAnnotations();
34 const fdf_doc = await PDFNet.FDFDoc.createFromXFDF(annots);
35 const doc = await documentViewer.getDocument().getPDFDoc();
36 await doc.fdfUpdate(fdf_doc);
37 await doc.flattenAnnotations();
38 annotationManager.deleteAnnotations(annotationManager.getAnnotationsList());
39 documentViewer.refreshAll();
40 documentViewer.updateView();
41 documentViewer.getDocument().refreshTextData();
42};
43
44const handleSnipAnnotation = async ({ annotation, annotationManager, documentViewer, getCanvasMultiplier }) => {
45 const pageIndex = annotation.PageNumber;
46 const rootElement = document.getElementsByTagName('apryse-webviewer')[0].shadowRoot;
47 const canvasMultiplier = getCanvasMultiplier();
48 const pageContainer = rootElement.getElementById('pageContainer' + pageIndex);
49 const pageCanvas = pageContainer.querySelector('.canvas' + pageIndex);
50 const topOffset = Number.parseFloat(pageContainer.style.top) || 0;
51 const leftOffset = Number.parseFloat(pageContainer.style.left) || 0;
52
53 const zoom = documentViewer.getZoomLevel();
54 const x = annotation.X * zoom - leftOffset;
55 const y = annotation.Y * zoom - topOffset;
56 const width = annotation.Width * zoom * canvasMultiplier;
57 const height = annotation.Height * zoom * canvasMultiplier;
58
59 const copyCanvas = document.createElement('canvas');
60 copyCanvas.width = width;
61 copyCanvas.height = height;
62 const ctx = copyCanvas.getContext('2d');
63 ctx.drawImage(pageCanvas, x, y, width, height, 0, 0, width, height);
64
65 const imageData = ctx.getImageData(0, 0, width, height);
66 const code = jsQR(imageData.data, imageData.width, imageData.height);
67
68 if (code) {
69 alert(`QR Code: ${code.data}`);
70 } else {
71 await readBarcode(copyCanvas);
72 }
73
74 annotationManager.deleteAnnotation(annotation);
75};
76
77const registerToolbar = ({ instance, customSnipTool, onFlatten }) => {
78 instance.UI.setToolbarGroup('toolbarGroup-Edit');
79
80 instance.UI.registerTool({
81 toolName: 'SnipTool',
82 toolObject: customSnipTool,
83 buttonImage: '../../../price.svg',
84 buttonName: 'snipToolButton',
85 tooltip: 'Snipping Tool',
86 });
87
88 const editGroup = instance.UI.getGroupedItems('editGroupedItems');
89 editGroup.setItems([
90 {
91 type: 'toolButton',
92 toolName: 'SnipTool'
93 },
94 new instance.UI.Components.CustomButton({
95 dataElement: 'customButton',
96 className: 'custom-button-class',
97 onClick: onFlatten,
98 img: '<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>',
99 title: 'Flatten Annotations',
100 })
101 ]);
102};
103
104const WebViewerPDFTron = () => {
105 const viewer = useRef(null);
106 const [viewerInstance, setViewerInstance] = useState(null);
107
108 // if using a class, equivalent of componentDidMount
109 useEffect(() => {
110 const initializeViewer = async () => {
111 const instance = await WebViewer(
112 {
113 path: '/webviewer/lib',
114 initialDoc:
115 'https://pdftron.s3.amazonaws.com/downloads/pl/webviewer-demo.pdf',
116 fullAPI: true,
117 disabledElements: ['ribbons', 'cropToolButton', 'snippingToolButton']
118 },
119 viewer.current,
120 );
121
122 setViewerInstance(instance);
123 const {
124 documentViewer,
125 annotationManager,
126 Annotations,
127 Tools,
128 PDFNet,
129 getCanvasMultiplier,
130 } = instance.Core;
131 await PDFNet.initialize();
132
133 const customSnipTool = createSnipTool({
134 docViewer: documentViewer,
135 Tools,
136 Annotations,
137 });
138
139 registerToolbar({
140 instance,
141 customSnipTool,
142 onFlatten: () => flattenAllAnnotations({ annotationManager, PDFNet, documentViewer }),
143 });
144
145 customSnipTool.addEventListener('annotationAdded', (annotation) =>
146 handleSnipAnnotation({ annotation, annotationManager, documentViewer, getCanvasMultiplier })
147 );
148 };
149
150 initializeViewer();
151 }, []);
152
153 return (
154 <div className="container">
155 <div className="webviewer" ref={viewer}></div>
156 <Barcode instance={viewerInstance} />
157 </div>
158 );
159};
160
161export default WebViewerPDFTron;
162

Did you find this helpful?

Trial setup questions?

Ask experts on Discord

Need other help?

Contact Support

Pricing or product questions?

Contact Sales