{"version":3,"file":"index.module.mjs","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","scanFile","FileHandle","uploadedFile","Response","type","arrayBuffer","pdfTypedArray","Uint8Array","getDocument","promise","loadedPDF","qrResult","pageToRender","numPages","getPage","page","canvas","document","createElement","height","width","unscaledViewport","getViewport","scale","Math","min","viewport","renderContext","canvasContext","getContext","render","extractQRCode","renderPDF","blob","imageBlob","Promise","resolve","reject","image","Image","onload","onerror","src","URL","createObjectURL","generateImageObject","drawImage","result","renderImage","pdfLib","imageData","getImageData","qrData","jsQR","data","inversionAttempts","GlobalWorkerOptions","workerSrc","version"],"mappings":"wEA+CQ,iBAESA,2BAWTC,OAAa,aATnBC,+NA5CW,2HAoBXC,EAAMC,MAEO,mCAKb,2EAdoBC,WAASC,OAE9B,IAAMC,EAAe,IAAIC,SAASF,GAElC,MAAwB,oBAApBA,EAAWG,qBAE6BF,EAAaG,gCAAxD,IAAMC,EAAgB,IAAIC,cAFgB,uBAGlBC,EAAYF,GAAeG,uBAA7CC,mCAiBiBJ,aACpBK,EAA0B,KACrBC,EAAe,orBAAGA,GAAgBN,EAAcO,4BAAUD,uCAC/CN,EAAcQ,QAAQF,kBAAnCG,GAEN,IAAMC,EAASC,SAASC,cAAc,UAEtCF,EAAOG,OAAS,KAChBH,EAAOI,MAAQ,KAEf,IAAMC,EAAmBN,EAAKO,YAAY,CAAEC,MAAO,IAE7CA,EAAQC,KAAKC,IAAIT,EAAOG,OAASE,EAAiBF,OAAQH,EAAOI,MAAQC,EAAiBD,OAE1FM,EAAWX,EAAKO,YAAY,CAAEC,MAAAA,IAE9BI,EAAgB,CACrBC,cAAeZ,EAAOa,WAAW,MACjCH,SAAUA,GAhBuE,uBAmB5EX,EAAKe,OAAOH,GAAelB,yBAnBiD,GAuBjE,QADjBE,EAAWoB,EAAcf,eAEjBL,uEAGF,WAAA,yCA5COqB,CAAUtB,wBAGCR,EAAa+B,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,IAAMtB,EAA4BC,SAASC,cAAc,gBAGrC,CAAC,GAAK,EAAG,oBAAO,CAA/B,IAAMK,OACVP,EAAOG,OAASmB,EAAMnB,OAASI,EAC/BP,EAAOI,MAAQkB,EAAMlB,MAAQG,EAEbP,EAAOa,WAAW,MAC1BiB,UAAUR,EAAO,EAAG,EAAGtB,EAAOI,MAAOJ,EAAOG,QAEpD,IAAM4B,EAAShB,EAAcf,GAC7B,GAAI+B,EACH,OAAOA,EAGT,cApFcC,CAAYd,MAb3B,oCAXQ1B,EAA4DyC,EAA5DzC,YAsHR,SAASuB,EAAcf,GACtB,IACMkC,EADMlC,EAAOa,WAAW,MACRsB,aAAa,EAAG,EAAGnC,EAAOI,MAAOJ,EAAOG,QACxDiC,EAASC,EAAKH,EAAUI,KAAMtC,EAAOI,MAAOJ,EAAOG,OAAQ,CAChEoC,kBAAmB,gBAEpB,aAAOH,SAAAA,EAAQE,OAAQ,KA5H4CL,EAA/CO,oBACDC,2DADgDR,EAA1BS"}