Mask the puzzle piece

This commit is contained in:
Alex Gleason 2024-10-03 20:15:16 -05:00
parent 707674db7c
commit 03c9340eb2
No known key found for this signature in database
GPG key ID: 7211D1F99744FBB7
2 changed files with 27 additions and 3 deletions

BIN
captcha/puzzle.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

View file

@ -8,12 +8,13 @@ import { aesEncrypt } from '@/utils/aes.ts';
export const captchaController: AppController = async (c) => {
const { puzzle, piece, solution } = await generateCaptcha(
await Deno.readFile(new URL('../../../captcha/tj-holowaychuk.jpg', import.meta.url)),
await Deno.readFile(new URL('../../../captcha/puzzle.png', import.meta.url)),
{
cw: 300,
ch: 300,
pw: 50,
ph: 50,
alpha: 0.6,
alpha: 0.8,
},
);
@ -41,6 +42,7 @@ interface Point {
async function generateCaptcha(
from: Uint8Array,
mask: Uint8Array,
opts: {
pw: number;
ph: number;
@ -54,12 +56,34 @@ async function generateCaptcha(
const ctx = puzzle.getContext('2d');
const image = await loadImage(from);
ctx.drawImage(image, 0, 0, image.width(), image.height(), 0, 0, cw, ch);
const piece = createCanvas(pw, ph);
const pctx = piece.getContext('2d');
const solution = getPieceCoords(puzzle.width, puzzle.height, pw, ph);
// Draw the piece onto the puzzle piece canvas but only where the mask allows
const maskImage = await loadImage(mask);
pctx.globalCompositeOperation = 'source-over';
pctx.drawImage(maskImage, 0, 0, pw, ph);
pctx.globalCompositeOperation = 'source-in';
pctx.drawImage(puzzle, solution.x, solution.y, pw, ph, 0, 0, pw, ph);
ctx.fillStyle = `rgba(0, 0, 0, ${alpha})`;
ctx.fillRect(solution.x, solution.y, pw, ph);
// Reset composite operation
pctx.globalCompositeOperation = 'source-over';
// Create a temporary canvas to draw the darkened shape
const tempCanvas = createCanvas(pw, ph);
const tempCtx = tempCanvas.getContext('2d');
// Draw the darkened shape onto the temporary canvas but only where the mask allows
tempCtx.fillStyle = `rgba(0, 0, 0, ${alpha})`;
tempCtx.fillRect(0, 0, pw, ph);
tempCtx.globalCompositeOperation = 'destination-in';
tempCtx.drawImage(maskImage, 0, 0, pw, ph);
// Draw the temporary canvas onto the puzzle at the piece's location
ctx.drawImage(tempCanvas, solution.x, solution.y, pw, ph);
return {
puzzle,