Skip to content

Commit

Permalink
feat: convert to typescript & export a binary
Browse files Browse the repository at this point in the history
  • Loading branch information
mattlubner committed Nov 3, 2020
1 parent d7a5477 commit c808c0b
Show file tree
Hide file tree
Showing 10 changed files with 389 additions and 42 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
node_modules
lib
*.log
22 changes: 0 additions & 22 deletions decode.js

This file was deleted.

13 changes: 0 additions & 13 deletions encode.js

This file was deleted.

23 changes: 18 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,30 @@
"name": "qr-decode-encode",
"description": "Shell scripts for decoding / encoding QR codes.",
"version": "0.0.0-unversioned",
"main": "decode.js",
"main": "lib/index.js",
"bin": "lib/bin.js",
"scripts": {
"decode": "node decode.js",
"encode": "node encode.js",
"test": "[ \"$(node decode.js \"$(node encode.js 'magic_test_string')\")\" == \"magic_test_string\" ]"
"start": "ts-node src/bin.ts",
"build": "tsc && chmod +x lib/bin.js",
"clean": "rimraf lib",
"test": "[ \"$(ts-node src/bin.ts decode \"$(ts-node src/bin.ts encode 'magic_test_string')\")\" == \"magic_test_string\" ]",
"type-check": "tsc --noEmit",
"decode": "yarn start decode",
"encode": "yarn start encode"
},
"license": "MIT",
"author": "Matt Lubner <matt@mattlubner.com>",
"dependencies": {
"jimp": "^0.14.0",
"jsqr": "^1.3.1",
"qrcode": "^1.4.4"
"qrcode": "^1.4.4",
"ts-node": "^9.0.0",
"typescript": "^4.0.5",
"yargs": "^16.1.0"
},
"devDependencies": {
"@types/qrcode": "^1.3.5",
"@types/yargs": "^15.0.9",
"rimraf": "^3.0.2"
}
}
11 changes: 11 additions & 0 deletions src/atoqr.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import * as QRCode from 'qrcode';

/**
* Encodes an ascii string into a data URL-embedded QR code.
*/
export const atoqr = async (ascii: string, output: 'dataUrl' | string = 'dataUrl'): Promise<string> => {
if (output === 'dataUrl') {
return QRCode.toDataURL(ascii);
}
return QRCode.toFile(output, ascii);
};
69 changes: 69 additions & 0 deletions src/bin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#!/usr/bin/env node
import yargs from 'yargs';
import { readFileSync } from 'fs';
import { normalize } from 'path';
import { atoqr, qrtoa } from './';

const argv = yargs(process.argv.slice(2))
.scriptName(require('../package.json').name)
.usage('Usage: $0 <command> [options]')
.command('decode <qr_code>', 'Decode qr_code back into an ascii string', _yargs => {
_yargs.positional('qr_code', {
describe: 'A data url or a path to an image file',
type: 'string',
});
})
.alias('qrtoa', 'decode')
.command('encode <ascii> [options]', 'Encode an ascii string into a qr code', _yargs => {
_yargs.positional('ascii', {
describe: 'An ascii string',
}).option('file', {
alias: 'f',
describe: 'Path to save output to (as *.{png,svg,txt})',
normalize: true,
type: 'string',
});
})
.alias('atoqr', 'encode')
.demandCommand(1, 'You must specify a command')
.option('clean', {
alias: 'c',
describe: 'Omit the trailing newline',
type: 'boolean',
})
.help('h')
.alias('h', 'help')
.argv;

const [command] = argv._;

const main = async () => {
switch (command) {
case 'decode': {
const dataUrlOrFile = argv.qr_code as string;
const [, content] = dataUrlOrFile.match(/^data:image\/(?:jpeg|png|bmp|tiff|gif);base64,(.+)$/) || [];
const isDataUrl = !!content;
const buffer = isDataUrl
? Buffer.from(content, 'base64')
: readFileSync(normalize(dataUrlOrFile));
const ascii = await qrtoa(buffer);
process.stdout.write(ascii);
break;
}
case 'encode': {
const ascii = argv.ascii as string;
const file = argv.file as string | undefined;
const qrCode = await atoqr(ascii, file);
process.stdout.write(qrCode);
break;
}
}
if (!argv.clean) {
process.stdout.write('\n');
}
};

main().catch(err => {
console.error(err);
process.exit(1);
});
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './atoqr';
export * from './qrtoa';
14 changes: 14 additions & 0 deletions src/qrtoa.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import Jimp from 'jimp';
import jsQR from 'jsqr';

/**
* Decodes a buffer containing a QR code into an ascii string.
*/
export const qrtoa = async (buffer: Buffer): Promise<string> => {
const image = await Jimp.read(buffer);
const result = jsQR(new Uint8ClampedArray(image.bitmap.data), image.bitmap.width, image.bitmap.height);
if (!result) {
return Promise.reject(new Error('Failed to parse qr_code'));
}
return result.data;
};
24 changes: 24 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"compilerOptions": {
"allowJs": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"lib": [
"es6"
],
"moduleResolution": "node",
"outDir": "lib",
"resolveJsonModule": true,
"rootDir": "src",
"skipLibCheck": true,
"strict": true,
"target": "es5"
},
"include": [
"src/*.ts"
],
"exclude": [
"node_modules",
"package.json"
]
}
Loading

0 comments on commit c808c0b

Please sign in to comment.