kopia lustrzana https://github.com/zhengkyl/qrframe
198 wiersze
5.2 KiB
JavaScript
198 wiersze
5.2 KiB
JavaScript
// Based on QRBTF's DSJ style
|
|
// https://github.com/CPunisher/react-qrbtf/blob/master/src/components/QRDsj.tsx
|
|
import { Module } from "https://qrframe.kylezhe.ng/utils.js";
|
|
|
|
export const paramsSchema = {
|
|
Margin: {
|
|
type: "number",
|
|
min: 0,
|
|
max: 10,
|
|
step: 0.1,
|
|
default: 2,
|
|
},
|
|
Background: {
|
|
type: "color",
|
|
default: "#ffffff",
|
|
},
|
|
Finder: {
|
|
type: "color",
|
|
default: "#131d87",
|
|
},
|
|
Horizontal: {
|
|
type: "color",
|
|
default: "#dc9c07",
|
|
},
|
|
Vertical: {
|
|
type: "color",
|
|
default: "#d21313",
|
|
},
|
|
Cross: {
|
|
type: "color",
|
|
default: "#131d87",
|
|
},
|
|
"Horizontal thickness": {
|
|
type: "number",
|
|
min: 0,
|
|
max: 1,
|
|
step: 0.1,
|
|
default: 0.7,
|
|
},
|
|
"Vertical thickness": {
|
|
type: "number",
|
|
min: 0,
|
|
max: 1,
|
|
step: 0.1,
|
|
default: 0.7,
|
|
},
|
|
"Cross thickness": {
|
|
type: "number",
|
|
min: 0,
|
|
max: 1,
|
|
step: 0.1,
|
|
default: 0.7,
|
|
},
|
|
};
|
|
|
|
export function renderSVG(qr, params) {
|
|
const matrixWidth = qr.version * 4 + 17;
|
|
const margin = params["Margin"];
|
|
const bg = params["Background"];
|
|
const fc = params["Finder"];
|
|
|
|
const hc = params["Horizontal"];
|
|
const ht = params["Horizontal thickness"];
|
|
const ho = (1 - ht) / 2;
|
|
|
|
const vc = params["Vertical"];
|
|
const vt = params["Vertical thickness"];
|
|
const vo = (1 - vt) / 2;
|
|
|
|
const cc = params["Cross"];
|
|
const ct = params["Cross thickness"];
|
|
const co = ct / Math.sqrt(8); // offset
|
|
|
|
const size = matrixWidth + 2 * margin;
|
|
let svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="${-margin} ${-margin} ${size} ${size}">`;
|
|
svg += `<rect x="${-margin}" y="${-margin}" width="${size}" height="${size}" fill="${bg}"/>`;
|
|
|
|
let crossLayer = `<g stroke-width="${ct}" stroke="${cc}">`;
|
|
let vLayer = `<g fill="${vc}">`;
|
|
let hLayer = `<g fill="${hc}">`;
|
|
|
|
function matrix(x, y) {
|
|
return qr.matrix[y * matrixWidth + x];
|
|
}
|
|
|
|
const visitedMatrix = Array(matrixWidth * matrixWidth).fill(false);
|
|
function visited(x, y) {
|
|
return visitedMatrix[y * matrixWidth + x];
|
|
}
|
|
function setVisited(x, y) {
|
|
visitedMatrix[y * matrixWidth + x] = true;
|
|
}
|
|
|
|
svg += `<g fill="${fc}">`;
|
|
for (const [x, y] of [
|
|
[0, 0],
|
|
[matrixWidth - 7, 0],
|
|
[0, matrixWidth - 7],
|
|
]) {
|
|
svg += `<rect x="${x + 2}" y="${y}" width="3" height="1"/>`;
|
|
svg += `<rect x="${x + 2}" y="${y + 2}" width="3" height="3"/>`;
|
|
svg += `<rect x="${x}" y="${y + 2}" width="1" height="3"/>`;
|
|
svg += `<rect x="${x + 6}" y="${y + 2}" width="1" height="3"/>`;
|
|
svg += `<rect x="${x + 2}" y="${y + 6}" width="3" height="1"/>`;
|
|
}
|
|
svg += `</g>`;
|
|
|
|
for (let y = 0; y < matrixWidth; y++) {
|
|
for (let x = 0; x < matrixWidth; x++) {
|
|
const module = matrix(x, y);
|
|
if (module & Module.FINDER) continue;
|
|
if (!(module & Module.ON)) continue;
|
|
if (visited(x, y)) continue;
|
|
setVisited(x, y);
|
|
|
|
if (
|
|
y < matrixWidth - 2 &&
|
|
x < matrixWidth - 2 &&
|
|
matrix(x + 2, y) &
|
|
matrix(x, y + 2) &
|
|
matrix(x + 1, y + 1) &
|
|
matrix(x + 2, y + 2) &
|
|
1
|
|
) {
|
|
if (
|
|
!visited(x + 1, y) &&
|
|
!visited(x + 2, y) &&
|
|
!visited(x, y + 1) &&
|
|
!visited(x + 2, y + 1)
|
|
) {
|
|
crossLayer += `<g>`;
|
|
crossLayer += `<line x1="${x + co}" y1="${y + co}" x2="${x + 3 - co}" y2="${y + 3 - co}"/>`;
|
|
crossLayer += `<line x1="${x + 3 - co}" y1="${y + co}" x2="${x + co}" y2="${y + 3 - co}"/>`;
|
|
crossLayer += `</g>`;
|
|
|
|
setVisited(x + 2, y);
|
|
setVisited(x, y + 2);
|
|
setVisited(x + 1, y + 1);
|
|
setVisited(x + 2, y + 2);
|
|
continue;
|
|
}
|
|
}
|
|
if (
|
|
y < matrixWidth - 1 &&
|
|
x < matrixWidth - 1 &&
|
|
matrix(x + 1, y) & matrix(x, y + 1) & matrix(x + 1, y + 1) & Module.ON
|
|
) {
|
|
if (
|
|
!visited(x + 1, y) &&
|
|
!visited(x + 1, y + 1) &&
|
|
!visited(x, y + 1)
|
|
) {
|
|
crossLayer += `<g>`;
|
|
crossLayer += `<line x1="${x + co}" y1="${y + co}" x2="${x + 2 - co}" y2="${y + 2 - co}"/>`;
|
|
crossLayer += `<line x1="${x + 2 - co}" y1="${y + co}" x2="${x + co}" y2="${y + 2 - co}"/>`;
|
|
crossLayer += `</g>`;
|
|
|
|
setVisited(x + 1, y);
|
|
setVisited(x, y + 1);
|
|
setVisited(x + 1, y + 1);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
let ny = y + 1;
|
|
while (ny < matrixWidth && matrix(x, ny) & Module.ON && !visited(x, ny)) {
|
|
ny++;
|
|
}
|
|
if (ny - y > 2) {
|
|
vLayer += `<rect x="${x + vo}" y="${y + vo}" width="${vt}" height="${ny - y - 1 - 2 * vo}" fill="${vc}"/>`;
|
|
vLayer += `<rect x="${x + vo}" y="${ny - 1 + vo}" width="${vt}" height="${1 - 2 * vo}" fill="${vc}"/>`;
|
|
for (let i = y + 1; i < ny; i++) {
|
|
setVisited(x, i);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
let nx = x + 1;
|
|
while (nx < matrixWidth && matrix(nx, y) & Module.ON && !visited(nx, y)) {
|
|
setVisited(nx, y);
|
|
nx++;
|
|
}
|
|
hLayer += `<rect x="${x + ho}" y="${y + ho}" width="${nx - x - 2 * ho}" height="${ht}" fill="${hc}"/>`;
|
|
}
|
|
}
|
|
|
|
vLayer += `</g>`;
|
|
svg += vLayer;
|
|
hLayer += `</g>`;
|
|
svg += hLayer;
|
|
crossLayer += `</g>`;
|
|
svg += crossLayer;
|
|
|
|
svg += `</svg>`;
|
|
|
|
return svg;
|
|
}
|