You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(
originalImg,
caseNumber = "04-BM-2023",
batCount = "13",
suspectName = "Неизвестный фигурант",
detective = "инспектор А.В. Крылов"
) {
// Create and configure the canvas
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
canvas.width = 800;
canvas.height = 1100;
// 1. Draw Manila Folder Background
ctx.fillStyle = "#e0cfab";
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Add a slight radial gradient/vignette to simulate age/lighting
const grad = ctx.createRadialGradient(
canvas.width / 2, canvas.height / 2, 200,
canvas.width / 2, canvas.height / 2, 800
);
grad.addColorStop(0, "rgba(255,255,255,0.1)");
grad.addColorStop(1, "rgba(0,0,0,0.15)");
ctx.fillStyle = grad;
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Decorative folder line
ctx.strokeStyle = "#5a4b31";
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(30, 20);
ctx.lineTo(30, canvas.height - 20);
ctx.stroke();
// 2. Draw Header Text
ctx.font = "bold 24px 'Courier New', Courier, monospace";
ctx.fillStyle = "#111";
ctx.textAlign = "left";
const currentDate = new Date().toLocaleDateString("ru-RU");
ctx.fillText(`АРХИВ: СЕКРЕТНО`, 50, 50);
ctx.textAlign = "right";
ctx.fillText(`ДАТА: ${currentDate}`, canvas.width - 50, 50);
// Title
ctx.textAlign = "center";
ctx.font = "bold 32px 'Courier New', Courier, monospace";
ctx.fillText(`ДЕЛО № ${caseNumber}`, canvas.width / 2, 110);
ctx.font = "bold 28px 'Courier New', Courier, monospace";
ctx.fillText(`О ПОХИЩЕННЫХ ЛЕТУЧИХ МЫШАХ`, canvas.width / 2, 150);
// 3. Draw the Image (Evidence / Suspect)
const imgMaxW = 500;
const imgMaxH = 350;
const ratio = Math.min(imgMaxW / originalImg.width, imgMaxH / originalImg.height);
const drawW = originalImg.width * ratio;
const drawH = originalImg.height * ratio;
const imgX = (canvas.width - drawW) / 2;
const imgY = 220;
// Draw photo white border (polaroid effect)
ctx.save();
ctx.shadowColor = "rgba(0, 0, 0, 0.4)";
ctx.shadowBlur = 10;
ctx.shadowOffsetX = 3;
ctx.shadowOffsetY = 3;
ctx.fillStyle = "#fdfdfd";
ctx.fillRect(imgX - 15, imgY - 15, drawW + 30, drawH + 60); // Bottom padding for polaroid style
ctx.restore();
// Draw the actual image
ctx.drawImage(originalImg, imgX, imgY, drawW, drawH);
// Handwritten note on polaroid
ctx.font = "italic 16px 'Georgia', serif";
ctx.fillStyle = "#333";
ctx.textAlign = "center";
ctx.fillText("Вещдок №1 (Фото с места инцидента)", canvas.width / 2, imgY + drawH + 25);
// Draw masking tape holding the photo
ctx.save();
ctx.fillStyle = "rgba(225, 225, 215, 0.8)";
ctx.shadowColor = "rgba(0, 0, 0, 0.2)";
ctx.shadowBlur = 4;
ctx.translate(canvas.width / 2, imgY - 15);
ctx.rotate(-0.06);
ctx.fillRect(-70, -10, 140, 25);
ctx.restore();
// 4. Generate & Draw the Story (Case File Draft)
const storyTemplate = `ОБСТОЯТЕЛЬСТВА ИНЦИДЕНТА:
Под покровом ночи злоумышленники проникли в специализированный вольер. Было похищено как минимум ${batCount} редких особей, относящихся к подотряду летучих мышей. На месте преступления найдены лишь обрывки сети, надкушенный манго и странный высокочастотный локатор.
ПОДОЗРЕВАЕМЫЕ ЛИЦА И УЛИКИ:
К делу приобщен ${suspectName}, чей профиль/отпечаток зафиксирован на фотокарточке выше. Особые приметы подозреваемого: неестественная любовь к сумеркам, избегание чеснока и подозрительно острый слух. Соседи утверждают, что в последние недели подозреваемый скупал насекомых и фрукты оптовыми партиями.
ЗАКЛЮЧЕНИЕ СЛЕДСТВИЯ:
Ведущий дело ${detective} постановил, что целью похищения, вероятно, является создание подпольной ультразвуковой лаборатории или попытка вырастить гигантскую армию рукокрылых. Статус расследования переведён в режим максимальной срочности.`;
ctx.font = "18px 'Courier New', Courier, monospace";
ctx.fillStyle = "#1a1a1a";
ctx.textAlign = "left";
const textX = 60;
const textY = imgY + drawH + 90;
const maxTextWidth = canvas.width - 120;
const lineHeight = 28;
// Helper function to wrap text
function wrapText(context, text, x, y, maxWidth, lineHeight) {
const paragraphs = text.split('\n');
let currentY = y;
for (let p = 0; p < paragraphs.length; p++) {
const words = paragraphs[p].split(' ');
let line = '';
for (let n = 0; n < words.length; n++) {
const testLine = line + words[n] + ' ';
const metrics = context.measureText(testLine);
const testWidth = metrics.width;
if (testWidth > maxWidth && n > 0) {
context.fillText(line, x, currentY);
line = words[n] + ' ';
currentY += lineHeight;
} else {
line = testLine;
}
}
context.fillText(line, x, currentY);
currentY += lineHeight; // extra space between paragraphs
}
}
wrapText(ctx, storyTemplate, textX, textY, maxTextWidth, lineHeight);
// 5. Draw "Top Secret" Rubber Stamp
ctx.save();
ctx.translate(canvas.width / 2 + 150, canvas.height - 180);
ctx.rotate(-Math.PI / 8);
ctx.font = "bold 45px 'Courier New', Courier, monospace";
ctx.fillStyle = "rgba(180, 20, 20, 0.5)"; // Faded red ink
ctx.strokeStyle = "rgba(180, 20, 20, 0.5)";
ctx.lineWidth = 4;
ctx.textAlign = "center";
ctx.textBaseline = "middle";
// Stamp border
ctx.strokeRect(-220, -40, 440, 80);
// Inner border
ctx.lineWidth = 2;
ctx.strokeRect(-212, -32, 424, 64);
// Stamp text
ctx.fillText("СОВЕРШЕННО СЕКРЕТНО", 0, 0);
// Add some random "scratch" lines over the stamp to make it look gritty
for (let i = 0; i < 5; i++) {
ctx.beginPath();
ctx.moveTo(Math.random() * 400 - 200, Math.random() * 60 - 30);
ctx.lineTo(Math.random() * 400 - 200, Math.random() * 60 - 30);
ctx.strokeStyle = "rgba(224, 207, 171, 0.8)"; // Canvas background color
ctx.stroke();
}
ctx.restore();
// Signature
ctx.fillStyle = "rgba(0,0,100,0.8)";
ctx.font = "italic 26px 'Georgia', serif";
ctx.textAlign = "right";
ctx.fillText("Подпись: _________", canvas.width - 60, canvas.height - 50);
return canvas;
}
Apply Changes