You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, themeColor = "#00ff00", language = "RU", scanSpeed = 3) {
// Determine maximum dimensions to maintain performance
const MAX_DIM = 800;
let w = originalImg.width;
let h = originalImg.height;
if (w > MAX_DIM || h > MAX_DIM) {
const ratio = Math.min(MAX_DIM / w, MAX_DIM / h);
w = Math.floor(w * ratio);
h = Math.floor(h * ratio);
}
const canvas = document.createElement('canvas');
canvas.width = w;
canvas.height = h;
const ctx = canvas.getContext('2d', { willReadFrequently: true });
// Draw the image first to gather seed data
ctx.drawImage(originalImg, 0, 0, w, h);
// Generate a pseudo-random seed based on image contents (so the same face gets the same stats)
let seed = 0;
try {
const sampleSize = Math.min(w, 50);
const imgData = ctx.getImageData(Array.from({length: 10}, () => Math.random() * (w - sampleSize))[0] || 0, 0, sampleSize, Math.min(h, 50)).data;
for (let i = 0; i < imgData.length; i += 4) {
seed += (imgData[i] + imgData[i + 1] * 2 + imgData[i + 2] * 3) * (i + 1);
}
} catch(e) {
// Fallback if cross-origin image blocks getImageData
seed = Math.random() * 999999;
}
// Pseudo-random number generator
function random() {
let x = Math.sin(seed++) * 10000;
return x - Math.floor(x);
}
const isRU = language.toUpperCase() === "RU";
// Data tables for Hero Identity
const classesRU = ['ВОИН', 'МАГ', 'СНАЙПЕР', 'ПАЛАДИН', 'КИБЕР-НИНДЗЯ', 'БЕРСЕРК', 'ТЕХНОЖРЕЦ', 'АССАСИН', 'СТРАННИК'];
const classesEN = ['WARRIOR', 'MAGE', 'SNIPER', 'PALADIN', 'CYBER-NINJA', 'BERSERKER', 'TECHNOPRIEST', 'ASSASSIN', 'ROVER'];
const classes = isRU ? classesRU : classesEN;
const alignsRU = ['ЗАКОНОПОСЛУШНЫЙ ДОБРЫЙ', 'ИСТИННО НЕЙТРАЛЬНЫЙ', 'ХАОТИЧНО ДОБРЫЙ', 'ХАОТИЧНО ЗЛОЙ', 'АНТИГЕРОЙ'];
const alignsEN = ['LAWFUL GOOD', 'TRUE NEUTRAL', 'CHAOTIC GOOD', 'CHAOTIC EVIL', 'ANTIHERO'];
const aligns = isRU ? alignsRU : alignsEN;
// Assign stats
const charClass = classes[Math.floor(random() * classes.length)];
const align = aligns[Math.floor(random() * aligns.length)];
const powerLvl = Math.floor(random() * 9000) + 1000;
let threatLvl = "";
let threatColor = themeColor;
if (powerLvl >= 9000) {
threatLvl = isRU ? "КРИТИЧЕСКАЯ (УРОВЕНЬ БОГА)" : "CRITICAL (GOD LEVEL)";
threatColor = "#ff2222"; // Red
} else if (powerLvl > 5000) {
threatLvl = isRU ? "ВЫСОКАЯ" : "HIGH";
threatColor = "#ffaa00"; // Orange
} else {
threatLvl = isRU ? "СРЕДНЯЯ" : "MODERATE";
}
const statsArray = isRU ? [
"СИСТЕМА ИДЕНТИФИКАЦИИ ГЕРОЯ...",
"------------------------------",
`КЛАСС : ${charClass}`,
`МИРОВОЗЗР. : ${align}`,
`УРОВЕНЬ СИЛЫ: ${powerLvl}`,
`ВЕРОЯТ.УГРОЗ: ${threatLvl}`
] : [
"HERO IDENTITY SCANNER...",
"------------------------------",
`CLASS : ${charClass}`,
`ALIGNMENT : ${align}`,
`POWER LEVEL : ${powerLvl}`,
`THREAT COEFF: ${threatLvl}`
];
// Animation state
let scanY = 0;
let scanDir = 1;
let frame = 0;
let pConnected = false;
function draw() {
// Prevent memory leak if canvas is removed from the DOM
if (canvas.isConnected) {
pConnected = true;
} else if (pConnected) {
return;
}
frame++;
ctx.clearRect(0, 0, w, h);
// Draw original base image
ctx.drawImage(originalImg, 0, 0, w, h);
// Apply dark overlay
ctx.fillStyle = "rgba(0, 5, 0, 0.45)";
ctx.fillRect(0, 0, w, h);
// Animated grid background
ctx.lineWidth = 1;
ctx.strokeStyle = themeColor;
ctx.globalAlpha = 0.15;
const gridSize = 40;
const yOffset = (frame * 0.5) % gridSize;
ctx.beginPath();
for (let x = 0; x < w; x += gridSize) {
ctx.moveTo(x, 0); ctx.lineTo(x, h);
}
for (let y = 0; y < h + gridSize; y += gridSize) {
ctx.moveTo(0, y - yOffset); ctx.lineTo(w, y - yOffset);
}
ctx.stroke();
ctx.globalAlpha = 1.0;
// HUD Corner brackets
const cLen = Math.max(30, w * 0.05);
ctx.lineWidth = 4;
ctx.strokeStyle = themeColor;
ctx.shadowColor = themeColor;
ctx.shadowBlur = 8;
const m = 20; // margin
ctx.beginPath(); ctx.moveTo(m + cLen, m); ctx.lineTo(m, m); ctx.lineTo(m, m + cLen); ctx.stroke(); // Top Left
ctx.beginPath(); ctx.moveTo(w - m - cLen, m); ctx.lineTo(w - m, m); ctx.lineTo(w - m, m + cLen); ctx.stroke(); // Top Right
ctx.beginPath(); ctx.moveTo(m + cLen, h - m); ctx.lineTo(m, h - m); ctx.lineTo(m, h - m - cLen); ctx.stroke(); // Bottom Left
ctx.beginPath(); ctx.moveTo(w - m - cLen, h - m); ctx.lineTo(w - m, h - m); ctx.lineTo(w - m, h - m - cLen); ctx.stroke(); // Bottom Right
ctx.shadowBlur = 0;
// Moving central target box
const targetW = w * 0.4;
const targetH = h * 0.4;
const tX = (w - targetW) / 2 + Math.sin(frame * 0.04) * 8;
const tY = (h - targetH) / 2 + Math.cos(frame * 0.03) * 6;
ctx.lineWidth = 2;
ctx.strokeStyle = "rgba(255, 255, 255, 0.4)";
ctx.setLineDash([15, 10]);
ctx.strokeRect(tX, tY, targetW, targetH);
// Inner reticle crosshairs
ctx.beginPath();
ctx.moveTo(tX + targetW/2, tY - 10); ctx.lineTo(tX + targetW/2, tY + 10);
ctx.moveTo(tX + targetW/2, tY + targetH - 10); ctx.lineTo(tX + targetW/2, tY + targetH + 10);
ctx.moveTo(tX - 10, tY + targetH/2); ctx.lineTo(tX + 10, tY + targetH/2);
ctx.moveTo(tX + targetW - 10, tY + targetH/2); ctx.lineTo(tX + targetW + 10, tY + targetH/2);
ctx.stroke();
ctx.setLineDash([]);
// Main Sweep Scanline
const sH = 3;
ctx.fillStyle = themeColor;
ctx.shadowColor = themeColor;
ctx.shadowBlur = 10;
ctx.fillRect(0, scanY, w, sH);
// Scanline gradient trail
const gradient = ctx.createLinearGradient(0, scanY, 0, scanY - (40 * scanDir));
gradient.addColorStop(0, themeColor);
gradient.addColorStop(1, "transparent");
ctx.fillStyle = gradient;
ctx.globalAlpha = 0.25;
ctx.fillRect(0, scanDir === 1 ? scanY - 40 : scanY, w, 40);
ctx.globalAlpha = 1.0;
ctx.shadowBlur = 0;
// Move scanline
scanY += scanSpeed * scanDir;
if (scanY > h || scanY < 0) {
scanDir *= -1;
}
// Render Text / Stats with Typewriter effect
const fontSize = Math.max(14, Math.floor(Math.min(w, h) * 0.035));
ctx.font = `bold ${fontSize}px "Courier New", Courier, monospace`;
ctx.textAlign = "left";
ctx.textBaseline = "top";
const textX = m + 15;
let textY = m + 15 + (frame % 10 < 5 ? Math.random() : 0); // slight glitch shake on text
const charsPerFrame = 1.5;
const maxChars = Math.floor(frame * charsPerFrame);
let currentChars = 0;
for (let i = 0; i < statsArray.length; i++) {
const line = statsArray[i];
if (currentChars >= maxChars) break;
const charsToDraw = Math.min(line.length, maxChars - currentChars);
const subLine = line.substring(0, charsToDraw);
// Conditional styling for the "Threat" line
if (i === statsArray.length - 1 && charsToDraw === line.length) {
// Flash threat level if critical
ctx.fillStyle = (frame % 30 < 15) ? threatColor : "#ffffff";
ctx.shadowColor = threatColor;
ctx.shadowBlur = 8;
} else {
ctx.fillStyle = themeColor;
ctx.shadowColor = "#000000";
ctx.shadowBlur = 4;
}
// Draw text background to ensure readability over bright images
ctx.fillStyle = "rgba(0,0,0,0.4)";
ctx.shadowBlur = 0;
ctx.fillRect(textX - 5, textY - 2, ctx.measureText(subLine).width + 10, fontSize + 4);
// Draw actual text
ctx.fillStyle = (i === statsArray.length - 1 && charsToDraw === line.length) ? ((frame % 30 < 15) ? threatColor : "#ffffff") : themeColor;
ctx.shadowColor = (i === statsArray.length - 1 && charsToDraw === line.length) ? threatColor : "#000";
ctx.shadowBlur = (i === statsArray.length - 1 && charsToDraw === line.length) ? 8 : 4;
ctx.fillText(subLine, textX, textY);
textY += fontSize + 12;
currentChars += line.length;
}
// Right side scrolling decorative binary
ctx.shadowBlur = 0;
ctx.fillStyle = themeColor;
ctx.globalAlpha = 0.6;
ctx.font = `${Math.max(10, fontSize * 0.75)}px "Courier New", Courier, monospace`;
ctx.textAlign = "right";
for (let i = 0; i < Math.floor(h / 25); i++) {
if (Math.random() > 0.05) { // Occasional empty spots for glitchy look
const bin = Math.random().toString(2).substr(2, 8);
const yPos = h - m - 15 - (i * 20) + ((frame * 0.5) % 20);
if (yPos > m && yPos < h - m) {
ctx.fillText(bin, w - m - 15, yPos);
}
}
}
ctx.globalAlpha = 1.0;
requestAnimationFrame(draw);
}
draw();
return canvas;
}
Apply Changes