158 lines
4.3 KiB
TypeScript
158 lines
4.3 KiB
TypeScript
import {PayloadBody} from "./payload";
|
|
import * as PdfJS from 'pdfjs-dist'
|
|
import jsQR, {QRCode} from "jsqr";
|
|
import {decodeData} from "./decode";
|
|
import {Result} from "@zxing/library";
|
|
import {COLORS} from "./colors";
|
|
|
|
PdfJS.GlobalWorkerOptions.workerSrc = `https://cdnjs.cloudflare.com/ajax/libs/pdf.js/${PdfJS.version}/pdf.worker.js`
|
|
|
|
export async function getPayloadBodyFromFile(file: File, color: COLORS): Promise<PayloadBody> {
|
|
let imageData: ImageData;
|
|
|
|
switch (file.type) {
|
|
case 'application/pdf':
|
|
// Read file
|
|
const fileBuffer = await file.arrayBuffer();
|
|
imageData = await getImageDataFromPdf(fileBuffer)
|
|
break
|
|
case 'image/png':
|
|
case 'image/jpeg':
|
|
case 'image/webp':
|
|
case 'image/gif':
|
|
imageData = await getImageDataFromImage(file)
|
|
break
|
|
default:
|
|
throw Error('invalidFileType')
|
|
}
|
|
|
|
let code: QRCode;
|
|
|
|
try {
|
|
code = jsQR(imageData.data, imageData.width, imageData.height, {
|
|
inversionAttempts: "dontInvert",
|
|
});
|
|
} catch (e) {
|
|
throw Error('couldNotDecode');
|
|
}
|
|
|
|
if (code == undefined) {
|
|
throw Error('couldNotFindQrCode')
|
|
}
|
|
|
|
// Get raw data
|
|
let rawData = code.data;
|
|
|
|
// Decode Data
|
|
let decodedData;
|
|
|
|
try {
|
|
decodedData = decodeData(rawData);
|
|
} catch (e) {
|
|
throw Error('invalidQrCode')
|
|
}
|
|
|
|
return {
|
|
rawData: rawData,
|
|
decodedData: decodedData,
|
|
color: color,
|
|
}
|
|
}
|
|
|
|
export async function getPayloadBodyFromQR(qrCodeResult: Result, color: COLORS): Promise<PayloadBody> {
|
|
|
|
// Get raw data
|
|
let rawData = qrCodeResult.getText();
|
|
|
|
// Decode Data
|
|
let decodedData;
|
|
|
|
try {
|
|
decodedData = decodeData(rawData);
|
|
} catch (e) {
|
|
throw Error("invalidQrCode")
|
|
}
|
|
|
|
return {
|
|
rawData: rawData,
|
|
decodedData: decodedData,
|
|
color: color,
|
|
}
|
|
}
|
|
|
|
function getImageDataFromImage(file: File): Promise<ImageData> {
|
|
return new Promise((resolve, reject) => {
|
|
const canvas = <HTMLCanvasElement>document.getElementById('canvas');
|
|
const canvasContext = canvas.getContext('2d');
|
|
|
|
// create Image object
|
|
const img = new Image();
|
|
|
|
img.onload = () => {
|
|
// constrain image to 2 Mpx
|
|
const maxPx = 2000000;
|
|
let width: number;
|
|
let height: number;
|
|
if (img.naturalWidth * img.naturalHeight > maxPx) {
|
|
const ratio = img.naturalHeight / img.naturalWidth;
|
|
width = Math.sqrt(maxPx / ratio);
|
|
height = Math.floor(width * ratio);
|
|
width = Math.floor(width);
|
|
} else {
|
|
width = img.naturalWidth;
|
|
height = img.naturalHeight;
|
|
}
|
|
|
|
// Set correct canvas width / height
|
|
canvas.width = width;
|
|
canvas.height = height;
|
|
|
|
// draw image into canvas
|
|
canvasContext.clearRect(0, 0, width, height);
|
|
canvasContext.drawImage(img, 0, 0, width, height);
|
|
|
|
// Obtain image data
|
|
resolve(canvasContext.getImageData(0, 0, width, height));
|
|
};
|
|
|
|
img.onerror = (e) => {
|
|
reject(e);
|
|
};
|
|
|
|
// start loading image from file
|
|
img.src = URL.createObjectURL(file);
|
|
});
|
|
}
|
|
|
|
async function getImageDataFromPdf(fileBuffer: ArrayBuffer): Promise<ImageData> {
|
|
const typedArray = new Uint8Array(fileBuffer);
|
|
const pdfScale = 2;
|
|
|
|
const canvas = <HTMLCanvasElement>document.getElementById('canvas');
|
|
const canvasContext = canvas.getContext('2d');
|
|
|
|
let loadingTask = PdfJS.getDocument(typedArray);
|
|
|
|
await loadingTask.promise.then(async function (pdfDocument) {
|
|
// Load last PDF page
|
|
const pageNumber = pdfDocument.numPages;
|
|
|
|
const pdfPage = await pdfDocument.getPage(pageNumber)
|
|
const viewport = pdfPage.getViewport({scale: pdfScale})
|
|
|
|
// Set correct canvas width / height
|
|
canvas.width = viewport.width
|
|
canvas.height = viewport.height
|
|
|
|
// render PDF
|
|
const renderTask = pdfPage.render({
|
|
canvasContext: canvasContext,
|
|
viewport,
|
|
})
|
|
|
|
return await renderTask.promise
|
|
});
|
|
|
|
// Return PDF Image Data
|
|
return canvasContext.getImageData(0, 0, canvas.width, canvas.height)
|
|
} |