captcha: refactor canvas calls

This commit is contained in:
Alex Gleason 2024-10-04 15:32:12 -05:00
parent cdf727e5c7
commit 71873997e5
No known key found for this signature in database
GPG key ID: 7211D1F99744FBB7

View file

@ -24,12 +24,8 @@ export const captchaController: AppController = async (c) => {
await Deno.readFile(new URL('../../../captcha/tj-holowaychuk.jpg', import.meta.url)), await Deno.readFile(new URL('../../../captcha/tj-holowaychuk.jpg', import.meta.url)),
await Deno.readFile(new URL('../../../captcha/puzzle-mask.png', import.meta.url)), await Deno.readFile(new URL('../../../captcha/puzzle-mask.png', import.meta.url)),
await Deno.readFile(new URL('../../../captcha/puzzle-hole.png', import.meta.url)), await Deno.readFile(new URL('../../../captcha/puzzle-hole.png', import.meta.url)),
{ { w: 370, h: 400 },
cw: 370, { w: 65, h: 65 },
ch: 400,
pw: 65,
ph: 65,
},
); );
const id = crypto.randomUUID(); const id = crypto.randomUUID();
@ -53,33 +49,30 @@ async function generateCaptcha(
from: Uint8Array, from: Uint8Array,
mask: Uint8Array, mask: Uint8Array,
hole: Uint8Array, hole: Uint8Array,
opts: { bgSize: Dimensions,
pw: number; puzzleSize: Dimensions,
ph: number;
cw: number;
ch: number;
},
) { ) {
const { pw, ph, cw, ch } = opts; const bg = createCanvas(bgSize.w, bgSize.h);
const bg = createCanvas(cw, ch); const puzzle = createCanvas(puzzleSize.w, puzzleSize.h);
const ctx = bg.getContext('2d');
const image = await loadImage(from);
ctx.drawImage(image, 0, 0, image.width(), image.height(), 0, 0, cw, ch);
const puzzle = createCanvas(pw, ph); const ctx = bg.getContext('2d');
const pctx = puzzle.getContext('2d'); const pctx = puzzle.getContext('2d');
const solution = getPieceCoords(bg.width, bg.height, pw, ph); const bgImage = await loadImage(from);
const maskImage = await loadImage(mask); const maskImage = await loadImage(mask);
const holeImage = await loadImage(hole); const holeImage = await loadImage(hole);
pctx.drawImage(maskImage, 0, 0, pw, ph); const solution = generateSolution(bgSize, puzzleSize);
pctx.globalCompositeOperation = 'source-in';
pctx.drawImage(bg, solution.x, solution.y, pw, ph, 0, 0, pw, ph);
// Draw the background image.
ctx.drawImage(bgImage, 0, 0, bg.width, bg.height);
ctx.globalCompositeOperation = 'source-atop'; ctx.globalCompositeOperation = 'source-atop';
ctx.drawImage(holeImage, solution.x, solution.y, pw, ph); ctx.drawImage(holeImage, solution.x, solution.y, puzzle.width, puzzle.height);
// Draw the puzzle piece.
pctx.drawImage(maskImage, 0, 0, puzzle.width, puzzle.height);
pctx.globalCompositeOperation = 'source-in';
pctx.drawImage(bgImage, solution.x, solution.y, puzzle.width, puzzle.height, 0, 0, puzzle.width, puzzle.height);
return { return {
bg, bg,
@ -88,14 +81,12 @@ async function generateCaptcha(
}; };
} }
function getPieceCoords(cw: number, ch: number, pw: number, ph: number): Point { /** Random coordinates such that the piece fits within the canvas. */
// Random x coordinate such that the piece fits within the canvas horizontally function generateSolution(bgSize: Dimensions, puzzleSize: Dimensions): Point {
const x = Math.floor(Math.random() * (cw - pw)); return {
x: Math.floor(Math.random() * (bgSize.w - puzzleSize.w)),
// Random y coordinate such that the piece fits within the canvas vertically y: Math.floor(Math.random() * (bgSize.h - puzzleSize.h)),
const y = Math.floor(Math.random() * (ch - ph)); };
return { x, y };
} }
const pointSchema = z.object({ const pointSchema = z.object({