Files
graphfx/src/nodes/QRCodeGenerator.ts
2024-03-28 16:54:13 +01:00

94 lines
2.8 KiB
TypeScript

import {
ImageVar,
NumberVar,
StringVar,
} from './io/AbstractIOSet';
import Node from './Node';
import {canvasPool2D} from '../canvas/CanvasPool';
import {BrowserQRCodeSvgWriter} from '@zxing/browser';
import {EncodeHintType, QRCodeDecoderErrorCorrectionLevel} from '@zxing/library';
const inputs = {
text: {
type: 'String'
} as StringVar,
size: {
type: 'Number',
min: 1,
} as NumberVar,
correction: {
type: 'String',
default: 'L',
enum: [
'L', /** L = ~7% correction */
'M', /** M = ~15% correction */
'Q', /** Q = ~25% correction */
'H', /** H = ~30% correction */
],
} as StringVar,
margin: {
type: 'Number',
min: 0,
} as NumberVar,
}
const outputs = {
image: {
type: 'Image'
} as ImageVar,
size: {
type: 'Number',
} as NumberVar,
margin: {
type: 'Number',
} as NumberVar,
};
export default class QRCodeGenerator extends Node<typeof inputs, typeof outputs> {
writer: BrowserQRCodeSvgWriter;
constructor(options = {}) {
super('QRCodeGenerator', inputs, outputs);
this.writer = new BrowserQRCodeSvgWriter();
}
async _update() {
if (!this.in.text.value || !this.in.size.value) {
return;
}
const encodeHintTypeMap = new Map<EncodeHintType, any>();
encodeHintTypeMap.set(EncodeHintType.MARGIN, this.in.margin.value);
encodeHintTypeMap.set(EncodeHintType.ERROR_CORRECTION, QRCodeDecoderErrorCorrectionLevel[this.in.correction.value]);
const svgElement = this.writer.write(this.in.text.value, this.in.size.value, this.in.size.value, encodeHintTypeMap);
const canvas = canvasPool2D.createCanvas();
canvas.width = this.in.size.value;
canvas.height = this.in.size.value;
canvas.acquire();
const canvasContext = canvas.getContext('2d');
await new Promise((resolve, reject) => {
const serializer = new XMLSerializer();
const svgString = serializer.serializeToString(svgElement);
const svgDataUrl = "data:image/svg+xml;base64," + btoa(unescape(encodeURIComponent(svgString)));
const img = new Image();
img.onload = () => {
canvasContext.drawImage(img, 0, 0);
resolve(img);
};
img.onerror = () => {
reject(new Error('Failed to load image'));
};
img.src = svgDataUrl;
img.width = this.in.size.value;
img.height = this.in.size.value;
});
this.out.margin.value = this.in.margin.value;
this.out.size.value = this.in.size.value;
this.out.image.value = canvas;
}
}