{"version":3,"file":"index.cjs","sources":["../src/index.ts"],"sourcesContent":["/**\n * pdf-image-qr-scanner\n * Library to scan user-uploaded PDF's or images locally and reliably for QR codes using jsQR.\n * @since 0.0.0\n */\n\nimport jsQR from 'jsqr';\nimport pdfLib from 'pdfjs-dist';\nimport type { PDFDocumentProxy } from 'pdfjs-dist';\nconst { getDocument, GlobalWorkerOptions, version: pdfjsVersion } = pdfLib;\nGlobalWorkerOptions.workerSrc = `https://cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjsVersion}/pdf.worker.min.js`;\n\n/**\n * Scan PDF file and return QR code data.\n *\n * @param {File} FileHandle - File handle of the PDF/Image file to scan.\n * @returns {Promise<string?>} QR Code Data.\n * @since 0.0.0\n */\n\nexport async function scanFile(FileHandle: File): Promise<string | null> {\n\t// async read of selected PDF file\n\tconst uploadedFile = new Response(FileHandle);\n\n\tif (FileHandle.type === 'application/pdf') {\n\t\t// PDF.js is used to parse the PDF file from the typed array.\n\t\tconst pdfTypedArray = new Uint8Array(await uploadedFile.arrayBuffer());\n\t\tconst loadedPDF = await getDocument(pdfTypedArray).promise;\n\n\t\treturn await renderPDF(loadedPDF);\n\t} else {\n\t\t// It's an image, so we use the canvas to render the image.\n\t\tconst imageBlob = await uploadedFile.blob();\n\t\treturn await renderImage(imageBlob);\n\t}\n}\n\n/**\n * Render PDF to canvas, and scans the QR code using the Canvas data.\n * @param {PDFDocumentProxy} pdfData PDF data to be scanned.\n * @return {string?} QR code data.\n * @since 0.0.0\n */\n\nasync function renderPDF(pdfTypedArray: PDFDocumentProxy): Promise<string | null> {\n\tlet qrResult: string | null = null;\n\tfor (let pageToRender = 1; pageToRender <= pdfTypedArray.numPages; pageToRender++) {\n\t\tconst page = await pdfTypedArray.getPage(pageToRender);\n\n\t\tconst canvas = document.createElement('canvas');\n\t\t// Simulation of A4 at 300dpi resolution\n\t\tcanvas.height = 3508;\n\t\tcanvas.width = 2480;\n\n\t\tconst unscaledViewport = page.getViewport({ scale: 1 });\n\n\t\tconst scale = Math.min(canvas.height / unscaledViewport.height, canvas.width / unscaledViewport.width);\n\n\t\tconst viewport = page.getViewport({ scale });\n\n\t\tconst renderContext = {\n\t\t\tcanvasContext: canvas.getContext('2d'),\n\t\t\tviewport: viewport,\n\t\t};\n\n\t\tawait page.render(renderContext).promise;\n\n\t\t// PDF Page is now fully rendered to canvas, so we can now extract the QR code.\n\t\tqrResult = extractQRCode(canvas);\n\t\tif (qrResult !== null) {\n\t\t\treturn qrResult;\n\t\t}\n\t}\n\treturn null;\n}\n\n/**\n * Wrapper for new Image() to load image from blob.\n * Needed to make it compatible with Async/Await.\n * @param {Blob} imageBlob\n * @returns {Promise<Image>}\n * @since 0.0.0\n */\n\nasync function generateImageObject(imageBlob: Blob): Promise<HTMLImageElement> {\n\treturn new Promise((resolve, reject) => {\n\t\tconst image = new Image();\n\t\timage.onload = () => resolve(image);\n\t\timage.onerror = reject;\n\t\timage.src = URL.createObjectURL(imageBlob);\n\t});\n}\n\n/**\n * Takes image file, creates Image, then renders it on a canvas, and finally extracts the QRCode data\n * @param {Blob} imageBlob\n * @return {string?} QR code data.\n * @since 0.0.0\n */\nasync function renderImage(imageBlob: Blob): Promise<string | null> {\n\tconst image = await generateImageObject(imageBlob);\n\n\tconst canvas: HTMLCanvasElement = document.createElement('canvas');\n\n\t// Try scanning for multiple scales, helps jsQR to find the QR code.\n\tfor (const scale of [0.5, 1, 0.25]) {\n\t\tcanvas.height = image.height * scale;\n\t\tcanvas.width = image.width * scale;\n\n\t\tconst context = canvas.getContext('2d');\n\t\tcontext.drawImage(image, 0, 0, canvas.width, canvas.height);\n\n\t\tconst result = extractQRCode(canvas);\n\t\tif (result) {\n\t\t\treturn result;\n\t\t}\n\t}\n\treturn null;\n}\n\n/**\n * Extracts QR code from canvas.\n * @param {HTMLCanvasElement} canvas Canvas element to extract QR code from.\n * @return {string?} QR code data.\n * @since 0.0.0\n */\n\nfunction extractQRCode(canvas: HTMLCanvasElement): string | null {\n\tconst ctx = canvas.getContext('2d');\n\tconst imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);\n\tconst qrData = jsQR(imageData.data, canvas.width, canvas.height, {\n\t\tinversionAttempts: 'attemptBoth',\n\t});\n\treturn qrData?.data || null;\n}\n"],"names":["_Pact","_settle","state","_this","s","getDocument","pdfLib","extractQRCode","canvas","imageData","getContext","getImageData","width","height","qrData","jsQR","data","inversionAttempts","GlobalWorkerOptions","workerSrc","version","FileHandle","uploadedFile","Response","type","arrayBuffer","pdfTypedArray","Uint8Array","promise","loadedPDF","qrResult","pageToRender","numPages","getPage","page","document","createElement","unscaledViewport","getViewport","scale","Math","min","viewport","renderContext","canvasContext","render","renderPDF","blob","imageBlob","Promise","resolve","reject","image","Image","onload","onerror","src","URL","createObjectURL","generateImageObject","drawImage","result","renderImage"],"mappings":"4LA+CQ,iBAESA,2BAWTC,OAAa,aATnBC,+NA5CW,2HAoBXC,EAAMC,MAEO,mCAKb,2EAzBMC,EAA4DC,UAA5DD,YAsHR,SAASE,EAAcC,GACtB,IACMC,EADMD,EAAOE,WAAW,MACRC,aAAa,EAAG,EAAGH,EAAOI,MAAOJ,EAAOK,QACxDC,EAASC,UAAKN,EAAUO,KAAMR,EAAOI,MAAOJ,EAAOK,OAAQ,CAChEI,kBAAmB,gBAEpB,aAAOH,SAAAA,EAAQE,OAAQ,KA5H4CV,UAA/CY,oBACDC,2DADgDb,UAA1Bc,uDAWXC,OAE9B,IAAMC,EAAe,IAAIC,SAASF,GAElC,MAAwB,oBAApBA,EAAWG,qBAE6BF,EAAaG,gCAAxD,IAAMC,EAAgB,IAAIC,cAFgB,uBAGlBtB,EAAYqB,GAAeE,uBAA7CC,mCAiBiBH,aACpBI,EAA0B,KACrBC,EAAe,orBAAGA,GAAgBL,EAAcM,4BAAUD,uCAC/CL,EAAcO,QAAQF,kBAAnCG,GAEN,IAAM1B,EAAS2B,SAASC,cAAc,UAEtC5B,EAAOK,OAAS,KAChBL,EAAOI,MAAQ,KAEf,IAAMyB,EAAmBH,EAAKI,YAAY,CAAEC,MAAO,IAE7CA,EAAQC,KAAKC,IAAIjC,EAAOK,OAASwB,EAAiBxB,OAAQL,EAAOI,MAAQyB,EAAiBzB,OAE1F8B,EAAWR,EAAKI,YAAY,CAAEC,MAAAA,IAE9BI,EAAgB,CACrBC,cAAepC,EAAOE,WAAW,MACjCgC,SAAUA,GAhBuE,uBAmB5ER,EAAKW,OAAOF,GAAef,yBAnBiD,GAuBjE,QADjBE,EAAWvB,EAAcC,eAEjBsB,uEAGF,WAAA,yCA5COgB,CAAUjB,wBAGCP,EAAayB,sBAA/BC,mCAmEmBA,mCAfQA,OAClC,uBAAO,IAAIC,QAAQ,SAACC,EAASC,GAC5B,IAAMC,EAAQ,IAAIC,MAClBD,EAAME,OAAS,kBAAMJ,EAAQE,IAC7BA,EAAMG,QAAUJ,EAChBC,EAAMI,IAAMC,IAAIC,gBAAgBV,yCAWbW,CAAoBX,kBAAlCI,GAKN,IAHA,IAAM5C,EAA4B2B,SAASC,cAAc,gBAGrC,CAAC,GAAK,EAAG,oBAAO,CAA/B,IAAMG,OACV/B,EAAOK,OAASuC,EAAMvC,OAAS0B,EAC/B/B,EAAOI,MAAQwC,EAAMxC,MAAQ2B,EAEb/B,EAAOE,WAAW,MAC1BkD,UAAUR,EAAO,EAAG,EAAG5C,EAAOI,MAAOJ,EAAOK,QAEpD,IAAMgD,EAAStD,EAAcC,GAC7B,GAAIqD,EACH,OAAOA,EAGT,cApFcC,CAAYd,MAb3B"}