freeptcha/routes.js

93 lines
2.8 KiB
JavaScript
Raw Normal View History

2023-06-23 15:11:59 +02:00
const sharp = require('sharp');
const canvas = require('canvas');
2023-06-23 18:14:01 +02:00
const crypto = require('crypto');
const randint = (min, max) => { return crypto.randomInt(max) + min };
/** @param {import('fastify').FastifyRequest} req */
const getSettings = (req) => {
const q = req.query;
const settings = {
// Width and height are ratio numbers; actual width & height is calculated from text length & padding
width: q.width ?? 3,
height: q.height ?? 1,
padding: q.padding ?? 20,
format: q.format ?? 'png',
dpi: q.dpi ?? 250
};
for (const key in settings) {
if (['format'].indexOf(key) !== -1) continue;
settings[key] = parseInt(settings[key]);
}
return settings;
}
const get_size = (ratio, dpi, txtlen, padding) => {
return {
width: Math.floor((ratio[0] * dpi * 0.12) + (txtlen * dpi * 0.08)) + (padding * 2),
height: Math.floor(ratio[1] * dpi * 0.2) + (padding * 2)
}
}
2023-06-23 15:11:59 +02:00
2023-06-23 19:12:57 +02:00
const createImage = async (width, height, bg = 'white', options = {}) => {
return sharp({
create: {
width: width,
height: height,
channels: 3,
background: bg,
...options
}
})
}
const drawText = (pic, text, dpi, blend, options = {}) => {
return pic.composite([{
input: {
text: {
text,
font: 'Open Sans',
dpi,
rgba: true,
...options
}
},
blend
}])
}
2023-06-23 15:11:59 +02:00
/** @param {import('fastify').FastifyInstance} fastify */
module.exports = (fastify) => {
fastify.get('/captcha/v1/:text', async (req, res) => {
2023-06-23 18:14:01 +02:00
const text = req.params.text;
const settings = getSettings(req);
const size = get_size([settings.width, settings.height], settings.dpi, text.length, settings.padding);
console.log(size)
console.log(settings)
2023-06-23 19:12:57 +02:00
let pic = await createImage(size.width, size.height);
2023-06-23 15:11:59 +02:00
2023-06-23 19:12:57 +02:00
drawText(pic, text, settings.dpi, 'over');
2023-06-23 15:11:59 +02:00
const textpic = await pic
.ensureAlpha()
2023-06-23 19:12:57 +02:00
.toFormat('png', { compressionLevel: 0 })
2023-06-23 15:11:59 +02:00
.toBuffer();
2023-06-23 18:14:01 +02:00
const draw = canvas.createCanvas(size.width, size.height);
2023-06-23 15:11:59 +02:00
const ctx = draw.getContext('2d');
2023-06-23 18:14:01 +02:00
ctx.drawImage(await canvas.loadImage(textpic), 0, 0, size.width, size.height);
2023-06-23 15:11:59 +02:00
2023-06-23 18:14:01 +02:00
const strokes = randint(25, 40);
2023-06-23 19:12:57 +02:00
for (let i = 0; i < strokes; i++) {
2023-06-23 15:11:59 +02:00
ctx.strokeStyle = `rgba(0,0,0,${10})`;
ctx.beginPath();
2023-06-23 18:14:01 +02:00
ctx.bezierCurveTo(randint(0, size.width), randint(0, size.height), randint(0, size.width), randint(0, size.height), randint(0, size.width), randint(0, size.height));
2023-06-23 15:11:59 +02:00
ctx.stroke();
}
res.header('Content-Type', 'png');
return draw.toBuffer();
})
}