You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, text = "U.N. OWEN WAS X ?", style = "silhouette", threshold = "128", invert = "false", wingScale = "1.0", bgColor = "#a50000") {
const canvas = document.createElement('canvas');
canvas.width = originalImg.width;
canvas.height = originalImg.height;
const ctx = canvas.getContext('2d');
// 1. Draw solid background
ctx.fillStyle = bgColor;
ctx.fillRect(0, 0, canvas.width, canvas.height);
// 2. Draw striking sunburst effect (common in these parodies)
ctx.save();
ctx.translate(canvas.width / 2, canvas.height / 2);
ctx.fillStyle = "rgba(0, 0, 0, 0.25)";
const beams = 24;
for (let i = 0; i < beams; i++) {
ctx.beginPath();
ctx.moveTo(0, 0);
const angle1 = (i * Math.PI * 2) / beams;
const angle2 = ((i + 0.45) * Math.PI * 2) / beams; // Slightly thinner rays than gap
const radius = Math.max(canvas.width, canvas.height) * 1.5;
ctx.lineTo(Math.cos(angle1) * radius, Math.sin(angle1) * radius);
ctx.lineTo(Math.cos(angle2) * radius, Math.sin(angle2) * radius);
ctx.closePath();
ctx.fill();
}
ctx.restore();
// 3. Draw Flandre Scarlet Wings
const baseScale = (canvas.width / 800) * parseFloat(wingScale || "1.0");
const cx = canvas.width / 2;
const cy = canvas.height * 0.5;
const drawCrystal = (x, y, color, size) => {
ctx.save();
ctx.translate(x, y);
ctx.beginPath();
ctx.moveTo(0, -size);
ctx.lineTo(size * 0.6, 0);
ctx.lineTo(0, size);
ctx.lineTo(-size * 0.6, 0);
ctx.closePath();
ctx.fillStyle = color;
ctx.shadowColor = color;
ctx.shadowBlur = 15 * baseScale;
ctx.fill();
ctx.strokeStyle = '#ffffff';
ctx.lineWidth = Math.max(1, 2 * baseScale);
ctx.stroke();
ctx.restore();
};
const colorsLeft = ["#00FFFF", "#0000FF", "#800080", "#FF00FF"]; // Cyan, Blue, Purple, Pink
const colorsRight = ["#FFFF00", "#FFA500", "#FF0000", "#90EE90"]; // Yellow, Orange, Red, LightGreen
ctx.lineWidth = 6 * baseScale;
ctx.strokeStyle = '#1a1a1a';
const drawWingSide = (isLeft) => {
const dir = isLeft ? -1 : 1;
const colors = isLeft ? colorsLeft : colorsRight;
let startX = cx + (30 * dir * baseScale);
let startY = cy;
let midX = startX + (150 * dir * baseScale);
let midY = startY - (40 * baseScale);
let endX = startX + (300 * dir * baseScale);
let endY = startY - (180 * baseScale);
// Draw main structural branches
ctx.beginPath();
ctx.moveTo(startX, startY);
ctx.lineTo(midX, midY);
ctx.lineTo(endX, endY);
ctx.stroke();
// Populate with crystals
for (let i = 0; i < 4; i++) {
let t = (i + 1) / 4.5;
let ix, iy;
if (t <= 0.5) {
let localT = t / 0.5;
ix = startX + (150 * dir * baseScale) * localT;
iy = startY - (40 * baseScale) * localT;
} else {
let localT = (t - 0.5) / 0.5;
ix = midX + (endX - midX) * localT;
iy = midY + (endY - midY) * localT;
}
// Branch stems for crystals hanging down
ctx.beginPath();
ctx.moveTo(ix, iy);
ctx.lineTo(ix, iy + 30 * baseScale);
ctx.stroke();
drawCrystal(ix, iy + 30 * baseScale + 25 * baseScale, colors[i], 25 * baseScale);
}
};
drawWingSide(true);
drawWingSide(false);
ctx.shadowBlur = 0; // Reset shadow for future drawing
// 4. Process original image overlay
const tempCanvas = document.createElement('canvas');
tempCanvas.width = canvas.width;
tempCanvas.height = canvas.height;
const tCtx = tempCanvas.getContext('2d');
tCtx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);
let mode = style.toLowerCase();
if (mode === "silhouette" || mode === "color-cutout") {
const imgData = tCtx.getImageData(0, 0, canvas.width, canvas.height);
const data = imgData.data;
const threshVal = parseInt(threshold, 10);
const isInv = invert === "true";
const range = 5; // soft threshold bounds for basic anti-aliasing
for (let i = 0; i < data.length; i += 4) {
if (data[i+3] === 0) continue; // Skip already transparent pixels
const r = data[i];
const g = data[i+1];
const b = data[i+2];
// Standard luminance calculation
const brightness = 0.299*r + 0.587*g + 0.114*b;
let pAlpha = 255;
if (brightness < threshVal - range) {
pAlpha = 255;
} else if (brightness > threshVal + range) {
pAlpha = 0;
} else {
let t = (brightness - (threshVal - range)) / (range * 2);
pAlpha = Math.floor(255 * (1 - t));
}
if (isInv) pAlpha = 255 - pAlpha;
if (mode === "silhouette") {
// Flatten color to solid black in silhouette mode
data[i] = 0;
data[i+1] = 0;
data[i+2] = 0;
}
// Retain pixel colors for color-cutout mode
data[i+3] = Math.min(data[i+3], pAlpha);
}
tCtx.putImageData(imgData, 0, 0);
}
// Draw manipulated subject on top of background + wings
ctx.drawImage(tempCanvas, 0, 0);
// 5. Add a deep vignette to unify visually
const grad = ctx.createRadialGradient(
canvas.width/2, canvas.height/2, Math.min(canvas.width, canvas.height) * 0.2,
canvas.width/2, canvas.height/2, Math.max(canvas.width, canvas.height) * 0.95
);
grad.addColorStop(0, "rgba(0,0,0,0)");
grad.addColorStop(1, "rgba(0,0,0,0.85)");
ctx.fillStyle = grad;
ctx.fillRect(0, 0, canvas.width, canvas.height);
// 6. Draw recognizable bold Impact text
if (text && text.trim() !== "") {
ctx.save();
let fontSize = Math.floor(canvas.width * 0.1);
ctx.font = `bold ${fontSize}px Impact, sans-serif`;
// Scale down if text is too wide
let textWidth = ctx.measureText(text).width;
if (textWidth > canvas.width * 0.9) {
fontSize = fontSize * ((canvas.width * 0.9) / textWidth);
ctx.font = `bold ${fontSize}px Impact, sans-serif`;
}
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';
const textY = canvas.height * 0.96;
// Stroke
ctx.strokeStyle = '#000000';
ctx.lineWidth = fontSize * 0.15;
ctx.lineJoin = "round";
ctx.strokeText(text, canvas.width/2, textY);
// Fill
ctx.fillStyle = "#ffffff";
ctx.fillText(text, canvas.width/2, textY);
ctx.restore();
}
return canvas;
}
Apply Changes