kopia lustrzana https://github.com/zhengkyl/qrframe
camo preset + update circle and minimal preset
rodzic
7aab323bcd
commit
60b4a76d60
|
@ -355,7 +355,19 @@ ctx.canvas.height = qr.matrixHeight * pixelSize;
|
|||
ctx.fillStyle = "rgb(255, 255, 255)";
|
||||
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
|
||||
|
||||
ctx.fillStyle = "rgb(0, 0, 0)";
|
||||
const gradient = ctx.createRadialGradient(
|
||||
ctx.canvas.width / 2,
|
||||
ctx.canvas.height / 2,
|
||||
2 * pixelSize,
|
||||
ctx.canvas.width / 2,
|
||||
ctx.canvas.height / 2,
|
||||
20 * pixelSize,
|
||||
);
|
||||
|
||||
gradient.addColorStop(0, "red");
|
||||
gradient.addColorStop(1, "blue");
|
||||
|
||||
ctx.fillStyle = gradient;
|
||||
|
||||
const radius = pixelSize / 2;
|
||||
|
||||
|
@ -375,24 +387,166 @@ for (const [x, y] of finderPos) {
|
|||
ctx.arc((x + 3.5) * pixelSize, (y + 3.5) * pixelSize, 2.5 * pixelSize, 0, 2 * Math.PI);
|
||||
ctx.fill();
|
||||
|
||||
ctx.fillStyle = "rgb(0, 0, 0)";
|
||||
ctx.fillStyle = gradient;
|
||||
ctx.beginPath();
|
||||
ctx.arc((x + 3.5) * pixelSize, (y + 3.5) * pixelSize, 1.5 * pixelSize, 0, 2 * Math.PI);
|
||||
ctx.fill();
|
||||
}
|
||||
|
||||
const xMid = qr.matrixWidth / 2;
|
||||
const yMid = qr.matrixHeight / 2;
|
||||
const maxDist = Math.sqrt(xMid * xMid + yMid + yMid);
|
||||
|
||||
for (let y = 0; y < qr.matrixHeight; y++) {
|
||||
for (let x = 0; x < qr.matrixWidth; x++) {
|
||||
const module = qr.matrix[y * qr.matrixWidth + x];
|
||||
|
||||
if (module & 1) {
|
||||
if (module === Module.FinderON) continue;
|
||||
|
||||
if (module === Module.AlignmentON) {
|
||||
// Find top left corner of alignment square
|
||||
if (qr.matrix[(y - 1) * qr.matrixWidth + x] !== Module.AlignmentON &&
|
||||
qr.matrix[y * qr.matrixWidth + x - 1] !== Module.AlignmentON &&
|
||||
qr.matrix[y * qr.matrixWidth + x + 1] === Module.AlignmentON
|
||||
) {
|
||||
ctx.beginPath();
|
||||
ctx.arc((x + 2.5) * pixelSize, (y + 2.5) * pixelSize, 2.5 * pixelSize, 0, 2 * Math.PI);
|
||||
ctx.fill();
|
||||
|
||||
ctx.fillStyle = "rgb(255, 255, 255)";
|
||||
ctx.beginPath();
|
||||
ctx.arc((x + 2.5) * pixelSize, (y + 2.5) * pixelSize, 1.5 * pixelSize, 0, 2 * Math.PI);
|
||||
ctx.fill();
|
||||
|
||||
ctx.fillStyle = gradient;
|
||||
ctx.beginPath();
|
||||
ctx.arc((x + 2.5) * pixelSize, (y + 2.5) * pixelSize, 0.5 * pixelSize, 0, 2 * Math.PI);
|
||||
ctx.fill();
|
||||
}
|
||||
continue;
|
||||
};
|
||||
|
||||
const xCenter = x * pixelSize + radius;
|
||||
const yCenter = y * pixelSize + radius;
|
||||
|
||||
const xDist = Math.abs(xMid - x);
|
||||
const yDist = Math.abs(yMid - y);
|
||||
const scale = Math.sqrt(xDist * xDist + yDist * yDist) / maxDist * 0.7 + 0.5;
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.arc(xCenter, yCenter, radius, 0, 2 * Math.PI);
|
||||
ctx.arc(xCenter, yCenter, radius * scale, 0, 2 * Math.PI);
|
||||
ctx.fill();
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
"Camouflage": `// qr, ctx are args
|
||||
const Module = {
|
||||
DataOFF: 0,
|
||||
DataON: 1,
|
||||
FinderOFF: 2,
|
||||
FinderON: 3,
|
||||
AlignmentOFF: 4,
|
||||
AlignmentON: 5,
|
||||
TimingOFF: 6,
|
||||
TimingON: 7,
|
||||
FormatOFF: 8,
|
||||
FormatON: 9,
|
||||
VersionOFF: 10,
|
||||
VersionON: 11,
|
||||
Unset: 12,
|
||||
}
|
||||
|
||||
function splitmix32(a) {
|
||||
return function() {
|
||||
a |= 0;
|
||||
a = a + 0x9e3779b9 | 0;
|
||||
let t = a ^ a >>> 16;
|
||||
t = Math.imul(t, 0x21f0aaad);
|
||||
t = t ^ t >>> 15;
|
||||
t = Math.imul(t, 0x735a2d97);
|
||||
return ((t = t ^ t >>> 15) >>> 0) / 4294967296;
|
||||
}
|
||||
}
|
||||
|
||||
const seededRand = splitmix32(1 /* change seed to change pattern */);
|
||||
|
||||
// Randomly set pixels in margin
|
||||
for (let y = 0; y < qr.matrixHeight; y++) {
|
||||
for (let x = 0; x < qr.matrixWidth; x++) {
|
||||
if (y > qr.margin.top - 2 &&
|
||||
y < qr.matrixHeight - qr.margin.bottom + 1 &&
|
||||
x > qr.margin.left - 2 &&
|
||||
x < qr.matrixWidth - qr.margin.right + 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (seededRand() > 0.5) qr.matrix[y * qr.matrixWidth + x] = Module.DataON;
|
||||
}
|
||||
}
|
||||
|
||||
const pixelSize = 20;
|
||||
const radius = pixelSize / 2;
|
||||
ctx.canvas.width = qr.matrixWidth * pixelSize;
|
||||
ctx.canvas.height = qr.matrixHeight * pixelSize;
|
||||
|
||||
const fg = "rgb(40, 70, 10)";
|
||||
const bg = "rgb(200, 200, 100)";
|
||||
|
||||
ctx.fillStyle = bg;
|
||||
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
|
||||
|
||||
const xMax = qr.matrixWidth - 1;
|
||||
const yMax = qr.matrixHeight - 1;
|
||||
|
||||
for (let y = 0; y < qr.matrixHeight; y++) {
|
||||
for (let x = 0; x < qr.matrixWidth; x++) {
|
||||
const module = qr.matrix[y * qr.matrixWidth + x];
|
||||
|
||||
const top = y > 0 && (qr.matrix[(y - 1) * qr.matrixWidth + x] & 1);
|
||||
const bottom = y < yMax && (qr.matrix[(y + 1) * qr.matrixWidth + x] & 1);
|
||||
const left = x > 0 && (qr.matrix[y * qr.matrixWidth + x - 1] & 1);
|
||||
const right = x < xMax && (qr.matrix[y * qr.matrixWidth + x + 1] & 1);
|
||||
|
||||
ctx.fillStyle = fg;
|
||||
|
||||
if (module & 1) {
|
||||
ctx.beginPath();
|
||||
ctx.roundRect(
|
||||
x * pixelSize,
|
||||
y * pixelSize,
|
||||
pixelSize,
|
||||
pixelSize,
|
||||
[
|
||||
!left && !top && radius,
|
||||
!top && !right && radius,
|
||||
!right && !bottom && radius,
|
||||
!bottom && !left && radius,
|
||||
]
|
||||
);
|
||||
ctx.fill();
|
||||
} else {
|
||||
// Draw rounded concave corners
|
||||
const topLeft = y > 0 && x > 0 && (qr.matrix[(y - 1) * qr.matrixWidth + x - 1] & 1);
|
||||
const topRight = y > 0 && x < xMax && (qr.matrix[(y - 1) * qr.matrixWidth + x + 1] & 1);
|
||||
const bottomRight = y < yMax && x < xMax && (qr.matrix[(y + 1) * qr.matrixWidth + x + 1] & 1);
|
||||
const bottomLeft = y < yMax && x > 0 && (qr.matrix[(y + 1) * qr.matrixWidth + x - 1] & 1);
|
||||
ctx.fillRect(x * pixelSize, y * pixelSize, pixelSize, pixelSize);
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.fillStyle = bg;
|
||||
ctx.roundRect(
|
||||
x * pixelSize,
|
||||
y * pixelSize,
|
||||
pixelSize,
|
||||
pixelSize,
|
||||
[
|
||||
left && top && topLeft && radius,
|
||||
top && right && topRight && radius,
|
||||
right && bottom && bottomRight && radius,
|
||||
bottom && left && bottomLeft && radius,
|
||||
]
|
||||
);
|
||||
ctx.fill();
|
||||
}
|
||||
}
|
||||
|
@ -419,17 +573,14 @@ const pixelSize = 12;
|
|||
ctx.canvas.width = qr.matrixWidth * pixelSize;
|
||||
ctx.canvas.height = qr.matrixHeight * pixelSize;
|
||||
|
||||
ctx.fillStyle = "rgb(255, 255, 255)";
|
||||
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
|
||||
|
||||
ctx.fillStyle = "rgb(0, 0, 0)";
|
||||
|
||||
const finderPos = [
|
||||
[qr.margin.left, qr.margin.top],
|
||||
[qr.matrixWidth - qr.margin.right - 7, qr.margin.top],
|
||||
[qr.margin.left, qr.matrixHeight - qr.margin.bottom - 7],
|
||||
];
|
||||
|
||||
ctx.fillStyle = "rgb(0, 0, 0)";
|
||||
|
||||
for (const [x, y] of finderPos) {
|
||||
ctx.fillRect((x + 3) * pixelSize, y * pixelSize, pixelSize, pixelSize);
|
||||
ctx.fillRect((x + 3) * pixelSize, (y + 6) * pixelSize, pixelSize, pixelSize);
|
||||
|
|
|
@ -1,6 +1,13 @@
|
|||
import { QrError } from "fuqr";
|
||||
|
||||
import { Match, Show, Switch, createEffect, createSignal, untrack } from "solid-js";
|
||||
import {
|
||||
Match,
|
||||
Show,
|
||||
Switch,
|
||||
createEffect,
|
||||
createSignal,
|
||||
untrack,
|
||||
} from "solid-js";
|
||||
import { useQrContext, type OutputQr } from "~/lib/QrContext";
|
||||
import {
|
||||
ECL_LABELS,
|
||||
|
@ -82,8 +89,8 @@ function RenderedQrCode() {
|
|||
const [canvasDims, setCanvasDims] = createSignal({ width: 0, height: 0 });
|
||||
|
||||
let cleanupFunc: void | (() => void);
|
||||
let cleanupFuncKey = ""
|
||||
let prevFuncKey = ""
|
||||
let cleanupFuncKey = "";
|
||||
let prevFuncKey = "";
|
||||
|
||||
createEffect(() => {
|
||||
try {
|
||||
|
@ -93,20 +100,25 @@ function RenderedQrCode() {
|
|||
setCleanupError(null);
|
||||
} catch (e) {
|
||||
setCleanupError(e!.toString());
|
||||
cleanupFuncKey = prevFuncKey
|
||||
console.error(`${cleanupFuncKey} cleanup:`, e)
|
||||
cleanupFuncKey = prevFuncKey;
|
||||
console.error(`${cleanupFuncKey} cleanup:`, e);
|
||||
}
|
||||
|
||||
const ctx = qrCanvas.getContext("2d")!;
|
||||
ctx.clearRect(0, 0, qrCanvas.width, qrCanvas.height);
|
||||
|
||||
prevFuncKey = untrack(renderFuncKey)
|
||||
prevFuncKey = untrack(renderFuncKey);
|
||||
try {
|
||||
cleanupFunc = renderFunc()(outputQr(), ctx);
|
||||
// matrix isn't cloned without this line... this disables some optimization i think
|
||||
const output = {...outputQr()};
|
||||
// Allow renderFunc to modify matrix with reset between renders
|
||||
output.matrix = [...output.matrix]
|
||||
|
||||
cleanupFunc = renderFunc()(output, ctx);
|
||||
setRuntimeError(null);
|
||||
} catch (e) {
|
||||
setRuntimeError(e!.toString());
|
||||
console.error(`${prevFuncKey} render:`, e)
|
||||
console.error(`${prevFuncKey} render:`, e);
|
||||
}
|
||||
|
||||
setCanvasDims({ width: qrCanvas.width, height: qrCanvas.height });
|
||||
|
|
|
@ -4,4 +4,4 @@ export function debounce(func: any, delay: number) {
|
|||
clearTimeout(timer);
|
||||
timer = setTimeout(() => func(...args), delay);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
Ładowanie…
Reference in New Issue