Skip to content

Commit

Permalink
Support for other image formats (#95)
Browse files Browse the repository at this point in the history
* Upgrade packages (#86)

Co-authored-by: Marvin Sextro <[email protected]>

* 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 <[email protected]>

* Upgrade packages

Co-authored-by: Marvin Sextro <[email protected]>
Co-authored-by: iBobo <[email protected]>
  • Loading branch information
3 people authored Sep 3, 2021
1 parent de82c49 commit cc7fddb
Show file tree
Hide file tree
Showing 5 changed files with 942 additions and 869 deletions.
2 changes: 1 addition & 1 deletion components/Form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ function Form(): JSX.Element {
className={`${isCameraOpen ? undefined : "hidden"} rounded-md w-full`}/>
<input type='file'
id='file'
accept="application/pdf,image/png"
accept="application/pdf,image/png,image/jpeg,image/webp,image/gif"
ref={inputFile}
style={{display: 'none'}}
/>
Expand Down
3 changes: 3 additions & 0 deletions next-env.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
/// <reference types="next" />
/// <reference types="next/types/global" />
/// <reference types="next/image-types/global" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.
4 changes: 1 addition & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": "latest",
"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",
Expand Down
63 changes: 47 additions & 16 deletions src/process.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -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<PayloadBody> {
// 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')
Expand Down Expand Up @@ -81,18 +82,48 @@ export async function getPayloadBodyFromQR(qrCodeResult: Result, color: COLORS):
}
}

async function getImageDataFromPng(fileBuffer: ArrayBuffer): Promise<ImageData> {
return new Promise(async (resolve, reject) => {
let png = new PNG({filterType: 4})

png.parse(fileBuffer, (error, data) => {
if (error) {
reject();
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;
}

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<ImageData> {
Expand Down
Loading

0 comments on commit cc7fddb

Please sign in to comment.