├── .gitignore ├── LICENSE ├── README.md ├── barcode.gif ├── package-lock.json ├── package.json ├── public ├── favicon.ico ├── index.html ├── logo192.png ├── logo512.png ├── manifest.json ├── price.svg └── robots.txt ├── src ├── App.css ├── App.js ├── components │ ├── Barcode │ │ ├── barcode.css │ │ └── index.js │ └── WebViewerPDFTron │ │ ├── index.js │ │ └── webviewer.css ├── index.css ├── index.js └── logo.svg └── tools └── copy-webviewer-files.js /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /public/webviewer 6 | /.pnp 7 | .pnp.js 8 | 9 | # testing 10 | /coverage 11 | 12 | # production 13 | /build 14 | 15 | # misc 16 | .DS_Store 17 | .env.local 18 | .env.development.local 19 | .env.test.local 20 | .env.production.local 21 | 22 | npm-debug.log* 23 | yarn-debug.log* 24 | yarn-error.log* 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2024 Apryse Software Inc. All rights reserved. 2 | WebViewer React UI project/codebase or any derived works is only permitted in solutions with an active commercial Apryse WebViewer license. For exact licensing terms refer to your commercial WebViewer license. For use in other scenario, contact sales@apryse.com. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WebViewer Barcode 2 | 3 | ⚠️ This sample has been moved to the [webviewer-samples repo](https://github.com/ApryseSDK/webviewer-samples/tree/main/webviewer-barcode). ⚠️ -------------------------------------------------------------------------------- /barcode.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ApryseSDK/webviewer-barcode/e73f63ab193cd42037ac79e3763f80ab2f14d901/barcode.gif -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webviewer-barcode", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@pdftron/webviewer": "^11.0.0", 7 | "javascript-barcode-reader": "^0.6.9", 8 | "jsbarcode": "^3.11.6", 9 | "jsqr": "^1.4.0", 10 | "qrcode": "^1.5.4", 11 | "react": "^16.13.1", 12 | "react-dom": "^16.13.1", 13 | "react-scripts": "3.4.1" 14 | }, 15 | "devDependencies": { 16 | "download": "^8.0.0", 17 | "fs-extra": "^11.2.0" 18 | }, 19 | "scripts": { 20 | "start": "react-scripts start", 21 | "build": "react-scripts build", 22 | "test": "react-scripts test", 23 | "eject": "react-scripts eject", 24 | "postinstall": "node tools/copy-webviewer-files.js" 25 | }, 26 | "eslintConfig": { 27 | "extends": "react-app" 28 | }, 29 | "browserslist": { 30 | "production": [ 31 | ">0.2%", 32 | "not dead", 33 | "not op_mini all" 34 | ], 35 | "development": [ 36 | "last 1 chrome version", 37 | "last 1 firefox version", 38 | "last 1 safari version" 39 | ] 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ApryseSDK/webviewer-barcode/e73f63ab193cd42037ac79e3763f80ab2f14d901/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | WebViewer Barcode 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ApryseSDK/webviewer-barcode/e73f63ab193cd42037ac79e3763f80ab2f14d901/public/logo192.png -------------------------------------------------------------------------------- /public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ApryseSDK/webviewer-barcode/e73f63ab193cd42037ac79e3763f80ab2f14d901/public/logo512.png -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /public/price.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | 2 | .App { 3 | width: 100%; 4 | height: 100%; 5 | display: flex; 6 | flex-direction: row; 7 | } -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import WebViewerPDFTron from './components/WebViewerPDFTron'; 3 | 4 | import './App.css'; 5 | 6 | const App = () => { 7 | 8 | return ( 9 |
10 | 11 |
12 | ); 13 | }; 14 | 15 | export default App; 16 | -------------------------------------------------------------------------------- /src/components/Barcode/barcode.css: -------------------------------------------------------------------------------- 1 | .barcodeContainer { 2 | width: 300px; 3 | display: flex; 4 | flex-direction: column; 5 | padding: 10px; 6 | } 7 | 8 | .barcodeCanvas { 9 | width: 300px; 10 | height: 175px; 11 | } 12 | 13 | .qrCanvas { 14 | width: 200px; 15 | height: 200px; 16 | } 17 | 18 | h2 { 19 | margin-bottom: 0px; 20 | } 21 | 22 | 23 | input, select, button, text { 24 | margin: 8px 0px; 25 | height: 30px; 26 | } 27 | 28 | .error { 29 | color: red; 30 | } 31 | -------------------------------------------------------------------------------- /src/components/Barcode/index.js: -------------------------------------------------------------------------------- 1 | import React, { useRef, useState } from 'react'; 2 | import JsBarcode from 'jsbarcode'; 3 | import QRCode from 'qrcode'; 4 | import './barcode.css'; 5 | 6 | const Barcode = ({ instance }) => { 7 | const barcodeRef = useRef(null); 8 | const qrRef = useRef(null); 9 | const formatRef = useRef(null); 10 | 11 | const [errText, setErrText] = useState(''); 12 | const [errQrText, setErrQrText] = useState(''); 13 | const [qrInput, setQrInput] = useState(''); 14 | 15 | 16 | const stampBarcode = (e, type) => { 17 | e.preventDefault(); 18 | const { Annotations, annotationManager, documentViewer } = instance.Core; 19 | const stampAnnot = new Annotations.StampAnnotation(); 20 | stampAnnot.PageNumber = documentViewer.getCurrentPage(); 21 | stampAnnot.X = 100; 22 | stampAnnot.Y = 250; 23 | stampAnnot.Width = 300; 24 | 25 | if (type === '2d') { 26 | stampAnnot.setImageData(barcodeRef.current.toDataURL()); 27 | stampAnnot.Height = 200; 28 | } else { 29 | stampAnnot.setImageData(qrRef.current.toDataURL()); 30 | stampAnnot.Height = 300; 31 | } 32 | 33 | stampAnnot.Author = annotationManager.getCurrentUser(); 34 | annotationManager.addAnnotation(stampAnnot); 35 | annotationManager.redrawAnnotation(stampAnnot); 36 | }; 37 | 38 | return ( 39 |
40 |

Barcode Generator

41 |

2D Barcode

42 | 60 | { 62 | try { 63 | setErrText(''); 64 | JsBarcode(barcodeRef.current, e.currentTarget.value, { 65 | format: formatRef.current.value, 66 | }); 67 | } catch (err) { 68 | setErrText(err); 69 | } 70 | }} 71 | type="text" 72 | > 73 | 80 |
{errText}
81 | 82 | 83 |

QR Code

84 | { 86 | setErrQrText(''); 87 | setQrInput(e.currentTarget.value); 88 | }} 89 | type="text" 90 | > 91 | 104 | 111 |
{errQrText}
112 | 113 |
114 | ); 115 | }; 116 | 117 | export default Barcode; 118 | -------------------------------------------------------------------------------- /src/components/WebViewerPDFTron/index.js: -------------------------------------------------------------------------------- 1 | import React, { useRef, useEffect, useState } from 'react'; 2 | import WebViewer from '@pdftron/webviewer'; 3 | import Barcode from '../Barcode'; 4 | import javascriptBarcodeReader from 'javascript-barcode-reader'; 5 | import jsQR from "jsqr"; 6 | import './webviewer.css'; 7 | 8 | const 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 | '', 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 |
135 |
136 | 137 |
138 | ); 139 | }; 140 | 141 | export default WebViewerPDFTron; 142 | -------------------------------------------------------------------------------- /src/components/WebViewerPDFTron/webviewer.css: -------------------------------------------------------------------------------- 1 | .container { 2 | display: flex; 3 | flex-direction: row; 4 | width:100%; 5 | } 6 | 7 | .webviewer { 8 | height: 100vh; 9 | width: 100%; 10 | } -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | 6 | ReactDOM.render( 7 | 8 | 9 | , 10 | document.getElementById('root') 11 | ); 12 | 13 | -------------------------------------------------------------------------------- /src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /tools/copy-webviewer-files.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs-extra'); 2 | 3 | const copyFiles = async () => { 4 | try { 5 | await fs.copy('./node_modules/@pdftron/webviewer/public', './public/webviewer/lib'); 6 | console.log('WebViewer files copied over successfully'); 7 | } catch (err) { 8 | console.error(err); 9 | } 10 | }; 11 | 12 | copyFiles(); --------------------------------------------------------------------------------