Skip to content

Instantly share code, notes, and snippets.

@maxammann
Created January 6, 2022 14:09
Show Gist options
  • Save maxammann/2e1c616d17800eeb045488efd7932e46 to your computer and use it in GitHub Desktop.
Save maxammann/2e1c616d17800eeb045488efd7932e46 to your computer and use it in GitHub Desktop.
Generate QR-codes and embed them in PDFs
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.0/jspdf.umd.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@zxing/library@0.18.6/umd/index.min.js"></script>
</head>
</html>
const {
jsPDF
} = window.jspdf;
const {
EncodeHintType,
IllegalStateException,
QRCodeDecoderErrorCorrectionLevel,
QRCodeEncoder,
QRCodeEncoderQRCode
} = window.ZXing;
const QRCode = QRCodeEncoderQRCode
const ErrorCorrectionLevel = QRCodeDecoderErrorCorrectionLevel
const DEFAULT_QUIET_ZONE_SIZE = 10
// Adapted from https://github.com/zxing-js/library/blob/d1a270cb8ef3c4dba72966845991f5c876338aac/src/browser/BrowserQRCodeSvgWriter.ts#L91
const createQRCode = (text,
renderRect,
renderBoundary,
size, hints) => {
let errorCorrectionLevel = ErrorCorrectionLevel.L;
let quietZone = DEFAULT_QUIET_ZONE_SIZE;
const {
width,
height
} = {
width: size,
height: size
}
if (hints) {
if (hints.get(EncodeHintType.ERROR_CORRECTION)) {
errorCorrectionLevel = ErrorCorrectionLevel.fromString(hints.get(EncodeHintType.ERROR_CORRECTION).toString());
}
if (hints.get(EncodeHintType.MARGIN) !== undefined) {
quietZone = Number.parseInt(hints.get(EncodeHintType.MARGIN).toString(), 10);
}
}
const code = QRCodeEncoder.encode(text, errorCorrectionLevel, hints);
const input = code.getMatrix();
if (input === null) {
throw new IllegalStateException();
}
const inputWidth = input.getWidth();
const inputHeight = input.getHeight();
const qrWidth = inputWidth + (quietZone * 2);
const qrHeight = inputHeight + (quietZone * 2);
const outputWidth = Math.max(width, qrWidth);
const outputHeight = Math.max(height, qrHeight);
const multiple = Math.min(Math.floor(outputWidth / qrWidth), Math.floor(outputHeight / qrHeight));
// Padding includes both the quiet zone and the extra white pixels to accommodate the requested
// dimensions. For example, if input is 25x25 the QR will be 33x33 including the quiet zone.
// If the requested size is 200x160, the multiple will be 4, for a QR of 132x132. These will
// handle all the padding from 100x100 (the actual QR) up to 200x160.
const leftPadding = Math.floor((outputWidth - (inputWidth * multiple)) / 2);
const topPadding = Math.floor((outputHeight - (inputHeight * multiple)) / 2);
renderBoundary(0, 0, outputWidth, outputHeight)
for (let inputY = 0; inputY < inputHeight; inputY++) {
// Write the contents of this row of the barcode
for (let inputX = 0; inputX < inputWidth; inputX++) {
if (input.get(inputX, inputY) === 1) {
let outputX = leftPadding + inputX * multiple;
let outputY = topPadding + inputY * multiple;
renderRect(outputX, outputY, multiple)
}
}
}
}
const drawjsPDF = (text, x, y, size, pdfDocument, border = true, version = 7) => {
const hints = new Map()
hints.set(EncodeHintType.MARGIN, 0)
hints.set(EncodeHintType.QR_VERSION, version)
createQRCode(text, (rectX, rectY, rectSize) => {
pdfDocument.rect(x + rectX, y + rectY, rectSize, rectSize, "FD");
},
(rectX, rectY, rectWidth, rectHeight) => {
if (border) {
pdfDocument.setLineWidth(.4)
pdfDocument.roundedRect(x + rectX, y + rectY, rectWidth, rectHeight, 10, 10, "D");
pdfDocument.setLineWidth(0)
}
}, size, hints)
}
var doc = new jsPDF();
drawjsPDF("test", 0, 0, 100, doc)
doc.save('Test.pdf');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment