From 1949060709524eebff12f1908e52cd3e0891cce8 Mon Sep 17 00:00:00 2001 From: iBobo Date: Fri, 3 Sep 2021 14:05:18 +0200 Subject: [PATCH] Support JPEG and other image formats; remove pngjs dependency (#93) * Support JPEG and other image formats; remove pngjs By using native Canvas to render images it was possible to remove dependency on external libraries to support image formats while supporting more formats like JPEG, GIF and WEBP for the QR image * Constrain images to 2 Mpx Co-authored-by: Marvin Sextro --- components/Form.tsx | 2 +- package.json | 2 -- src/process.ts | 61 ++++++++++++++++++++++++++++++++++----------- yarn.lock | 10 -------- 4 files changed, 47 insertions(+), 28 deletions(-) diff --git a/components/Form.tsx b/components/Form.tsx index be9206b..5f30517 100644 --- a/components/Form.tsx +++ b/components/Form.tsx @@ -186,7 +186,7 @@ function Form(): JSX.Element { className={`${isCameraOpen ? undefined : "hidden"} rounded-md w-full`}/> diff --git a/package.json b/package.json index adcfebe..f7288a9 100644 --- a/package.json +++ b/package.json @@ -16,14 +16,12 @@ "cbor-js": "^0.1.0", "do-not-zip": "^1.0.0", "file-saver": "^2.0.5", - "jpeg-js": "^0.4.3", "jsqr": "^1.4.0", "next": "^11.1.0", "next-i18next": "^8.5.1", "next-seo": "^4.26.0", "node-fetch": "^2.6.1", "pdfjs-dist": "^2.5.207", - "pngjs": "^6.0.0", "react": "^17.0.2", "react-dom": "^17.0.2", "uuid": "^8.3.2", diff --git a/src/process.ts b/src/process.ts index b2a253d..a38c61e 100644 --- a/src/process.ts +++ b/src/process.ts @@ -1,5 +1,4 @@ import {PayloadBody} from "./payload"; -import {PNG} from 'pngjs' import * as PdfJS from 'pdfjs-dist' import jsQR, {QRCode} from "jsqr"; import {decodeData} from "./decode"; @@ -9,19 +8,21 @@ 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 { - // Read file - const fileBuffer = await file.arrayBuffer(); - let imageData: ImageData; switch (file.type) { case 'application/pdf': console.log('pdf') + // Read file + const fileBuffer = await file.arrayBuffer(); imageData = await getImageDataFromPdf(fileBuffer) break case 'image/png': - console.log('png') - imageData = await getImageDataFromPng(fileBuffer) + case 'image/jpeg': + case 'image/webp': + case 'image/gif': + console.log(`image ${file.type}`) + imageData = await getImageDataFromImage(file) break default: throw Error('invalidFileType') @@ -81,18 +82,48 @@ export async function getPayloadBodyFromQR(qrCodeResult: Result, color: COLORS): } } -async function getImageDataFromPng(fileBuffer: ArrayBuffer): Promise { - return new Promise(async (resolve, reject) => { - let png = new PNG({filterType: 4}) +function getImageDataFromImage(file: File): Promise { + return new Promise((resolve, reject) => { + const canvas = document.getElementById('canvas'); + const canvasContext = canvas.getContext('2d'); - png.parse(fileBuffer, (error, data) => { - if (error) { - reject(); + // 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; } - resolve(data); - }) - }) + // 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 { diff --git a/yarn.lock b/yarn.lock index f962123..90b098e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1699,11 +1699,6 @@ jest-worker@^27.0.2: merge-stream "^2.0.0" supports-color "^8.0.0" -jpeg-js@^0.4.3: - version "0.4.3" - resolved "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.3.tgz" - integrity sha512-ru1HWKek8octvUHFHvE5ZzQ1yAsJmIvRdGWvSoKV52XKyuyYA437QWDttXT8eZXDSbuMpHlLzPDZUPd6idIz+Q== - "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -2227,11 +2222,6 @@ platform@1.3.6: resolved "https://registry.yarnpkg.com/platform/-/platform-1.3.6.tgz#48b4ce983164b209c2d45a107adb31f473a6e7a7" integrity sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg== -pngjs@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/pngjs/-/pngjs-6.0.0.tgz" - integrity sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg== - pnp-webpack-plugin@1.6.4: version "1.6.4" resolved "https://registry.yarnpkg.com/pnp-webpack-plugin/-/pnp-webpack-plugin-1.6.4.tgz#c9711ac4dc48a685dabafc86f8b6dd9f8df84149"