Please bookmark this page to avoid losing your image tool!

Image Of A Hero In Shiny Armor Generator

(Free & Supports Bulk Upload)

Drag & drop your images here or

The result will appear here...
You can edit the below JavaScript code to customize the image tool.
function processImage(originalImg, titleText = "ГЕРОЙ В ДОСПЕХАХ", armorColor = "silver") {
    const canvas = document.createElement('canvas');
    const w = originalImg.width;
    const h = originalImg.height;
    canvas.width = w;
    canvas.height = h;
    const ctx = canvas.getContext('2d');

    // 1. Draw original image and apply a 'heroic' cinematic effect (contrast & saturation)
    ctx.filter = "contrast(1.15) saturate(1.2) brightness(1.05)";
    ctx.drawImage(originalImg, 0, 0, w, h);
    ctx.filter = "none";

    // 2. Add an epic vignette to draw focus to the center subject (the hero)
    let minDim = Math.min(w, h);
    let vigGrad = ctx.createRadialGradient(w / 2, h / 2, minDim * 0.2, w / 2, h / 2, Math.max(w, h) * 0.75);
    vigGrad.addColorStop(0, "rgba(0,0,0,0)");
    vigGrad.addColorStop(1, "rgba(0,0,0,0.85)");
    ctx.fillStyle = vigGrad;
    ctx.fillRect(0, 0, w, h);

    // Dynamic scale parameters based on image size
    let fw = minDim * 0.08; // Main metallic frame width
    let chw = minDim * 0.04; // Chainmail frame width
    let trimWidth = fw * 0.15;

    // 3. Define Shiny Metallic Armor Gradients
    let mainColorPalette = armorColor.toLowerCase().includes("gold") ? "gold" : "silver";
    let armorGrad = ctx.createLinearGradient(0, 0, w, h);
    let trimGrad = ctx.createLinearGradient(w, 0, 0, h);

    if (mainColorPalette === "gold") {
        // Gold Armor
        armorGrad.addColorStop(0, "#cc9900");
        armorGrad.addColorStop(0.2, "#fff2b3");
        armorGrad.addColorStop(0.35, "#e6b800");
        armorGrad.addColorStop(0.48, "#664d00");
        armorGrad.addColorStop(0.5, "#332600"); // Sharp reflection horizon for max "shiny"
        armorGrad.addColorStop(0.52, "#b38f00");
        armorGrad.addColorStop(0.75, "#ffcc00");
        armorGrad.addColorStop(1, "#cc9900");

        // Silver Trim
        trimGrad.addColorStop(0, "#d4d4d4");
        trimGrad.addColorStop(0.5, "#4a4a4a");
        trimGrad.addColorStop(1, "#fcfcfc");
    } else {
        // Silver/Steel Armor (Default)
        armorGrad.addColorStop(0, "#8a8a8a");
        armorGrad.addColorStop(0.2, "#ffffff");
        armorGrad.addColorStop(0.35, "#cccccc");
        armorGrad.addColorStop(0.48, "#555555");
        armorGrad.addColorStop(0.5, "#151515"); // Sharp reflection horizon
        armorGrad.addColorStop(0.52, "#999999");
        armorGrad.addColorStop(0.75, "#e0e0e0");
        armorGrad.addColorStop(1, "#8a8a8a");

        // Gold Trim
        trimGrad.addColorStop(0, "#ffb900");
        trimGrad.addColorStop(0.3, "#ffe066");
        trimGrad.addColorStop(0.5, "#805a00");
        trimGrad.addColorStop(0.6, "#ffcc00");
        trimGrad.addColorStop(1, "#fff2b3");
    }

    // 4. Generate Chainmail Pattern for inner lining
    let chainCanvas = document.createElement("canvas");
    let cwP = Math.max(12, minDim * 0.025); // Dynamic pattern density
    chainCanvas.width = cwP;
    chainCanvas.height = cwP;
    let cCtx = chainCanvas.getContext("2d");
    
    // Chainmail rings design
    cCtx.fillStyle = "#111"; // Backing shadow
    cCtx.fillRect(0, 0, cwP, cwP);
    cCtx.lineWidth = cwP * 0.15;
    
    // First ring layer
    cCtx.beginPath();
    cCtx.arc(0, 0, cwP * 0.4, 0, Math.PI * 2);
    cCtx.arc(cwP, 0, cwP * 0.4, 0, Math.PI * 2);
    cCtx.arc(0, cwP, cwP * 0.4, 0, Math.PI * 2);
    cCtx.arc(cwP, cwP, cwP * 0.4, 0, Math.PI * 2);
    cCtx.strokeStyle = "#444";
    cCtx.stroke();
    // Overlapping ring
    cCtx.beginPath();
    cCtx.arc(cwP / 2, cwP / 2, cwP * 0.4, 0, Math.PI * 2);
    cCtx.strokeStyle = "#888";
    cCtx.stroke();
    // Little shine on the ring
    cCtx.beginPath();
    cCtx.arc(cwP / 2, cwP / 2, cwP * 0.4, Math.PI * 1.1, Math.PI * 1.6);
    cCtx.strokeStyle = "#eee";
    cCtx.stroke();

    let chainPattern = ctx.createPattern(chainCanvas, "repeat");

    // Draw Chainmail inner frame
    ctx.fillStyle = chainPattern;
    ctx.beginPath();
    ctx.rect(fw, fw, w - 2 * fw, h - 2 * fw); // Outer boundary of chain
    ctx.rect(fw + chw, fw + chw, w - 2 * (fw + chw), h - 2 * (fw + chw)); // Inner cutout
    ctx.fill("evenodd");

    // Bevel shading for chainmail depth
    ctx.strokeStyle = "rgba(0,0,0,0.9)";
    ctx.lineWidth = chw * 0.3;
    ctx.strokeRect(fw + chw, fw + chw, w - 2 * (fw + chw), h - 2 * (fw + chw));

    // 5. Draw Main Shiny Body Frame Outer Layer 
    ctx.fillStyle = armorGrad;
    ctx.shadowColor = "rgba(0,0,0,0.9)";
    ctx.shadowBlur = minDim * 0.02;
    ctx.beginPath();
    ctx.rect(0, 0, w, h);
    ctx.rect(fw, fw, w - 2 * fw, h - 2 * fw);
    ctx.fill("evenodd");
    ctx.shadowBlur = 0; // reset shadow

    // 6. Draw Trim Boundary Border
    ctx.fillStyle = trimGrad;
    ctx.beginPath();
    ctx.rect(fw - trimWidth, fw - trimWidth, (w - 2 * fw) + trimWidth * 2, (h - 2 * fw) + trimWidth * 2);
    ctx.rect(fw, fw, w - 2 * fw, h - 2 * fw);
    ctx.fill("evenodd");

    // Add precise 3D bevel lines to the trim
    ctx.strokeStyle = "rgba(255,255,255,0.6)";
    ctx.lineWidth = Math.max(1, minDim * 0.003);
    ctx.strokeRect(fw - trimWidth, fw - trimWidth, (w - 2 * fw) + trimWidth * 2, (h - 2 * fw) + trimWidth * 2);
    ctx.strokeStyle = "rgba(0,0,0,0.6)";
    ctx.strokeRect(fw, fw, w - 2 * fw, h - 2 * fw);

    // 7. Render Layered Armor Corners Function
    function drawCornerPlate(x, y, scaleX, scaleY) {
        ctx.save();
        ctx.translate(x, y);
        ctx.scale(scaleX, scaleY);

        ctx.beginPath();
        ctx.moveTo(0, 0);
        ctx.lineTo(fw * 2.5, 0);
        ctx.lineTo(fw * 1.5, fw * 1.5);
        ctx.lineTo(0, fw * 2.5);
        ctx.closePath();

        let plateGrad = ctx.createLinearGradient(0, 0, fw * 2.5, fw * 2.5);
        if (mainColorPalette === "gold") {
            plateGrad.addColorStop(0, "#fff2b3");
            plateGrad.addColorStop(0.5, "#cca300");
            plateGrad.addColorStop(1, "#332600");
        } else {
            plateGrad.addColorStop(0, "#ffffff");
            plateGrad.addColorStop(0.5, "#999999");
            plateGrad.addColorStop(1, "#222222");
        }

        ctx.shadowColor = "rgba(0,0,0,0.8)";
        ctx.shadowBlur = fw * 0.2;
        // Adjust shadow direction to remain strictly uniform bottom-right globally despite scaling
        ctx.shadowOffsetX = scaleX * fw * 0.1;
        ctx.shadowOffsetY = scaleY * fw * 0.1;

        ctx.fillStyle = plateGrad;
        ctx.fill();

        ctx.shadowBlur = 0;
        ctx.shadowOffsetX = 0;
        ctx.shadowOffsetY = 0;

        // Embossed trim matching plate geometry
        ctx.lineWidth = fw * 0.05;
        ctx.strokeStyle = trimGrad; 
        ctx.stroke();

        ctx.restore();
    }

    // Apply corner reinforcements
    drawCornerPlate(0, 0, 1, 1);       // Top-Left
    drawCornerPlate(w, 0, -1, 1);      // Top-Right
    drawCornerPlate(0, h, 1, -1);      // Bottom-Left
    drawCornerPlate(w, h, -1, -1);     // Bottom-Right

    // 8. Rivets Implementation
    function drawRivet(rx, ry, rScale) {
        let rs = rScale || minDim * 0.008;
        ctx.beginPath();
        ctx.arc(rx, ry, rs, 0, Math.PI * 2);
        let rGrad = ctx.createRadialGradient(rx - rs * 0.4, ry - rs * 0.4, rs * 0.1, rx, ry, rs);
        rGrad.addColorStop(0, "#fff");
        rGrad.addColorStop(0.6, "#777");
        rGrad.addColorStop(1, "#222");
        ctx.fillStyle = rGrad;
        ctx.fill();

        ctx.strokeStyle = "rgba(0,0,0,0.8)";
        ctx.lineWidth = rs * 0.3;
        ctx.stroke();
    }

    let pw = Math.min(w * 0.6, 600); // Plaque width allocation for spacing checks
    let px = w / 2 - pw / 2;
    let rivetSteps = 10;
    
    // Construct rivet grid avoiding corners and bottom plaque area
    for (let i = 1; i < rivetSteps; i++) {
        let rxPos = w * (i / rivetSteps);
        if (rxPos > fw * 2.5 && rxPos < w - fw * 2.5) {
            drawRivet(rxPos, fw * 0.5); // Top Edge
            // Bottom Edge (skip plaque overlap area)
            if (!(rxPos > px - fw * 0.8 && rxPos < px + pw + fw * 0.8)) {
                drawRivet(rxPos, h - fw * 0.5);
            }
        }
    }
    for (let i = 1; i < rivetSteps; i++) {
        let ryPos = h * (i / rivetSteps);
        if (ryPos > fw * 2.5 && ryPos < h - fw * 2.5) {
            drawRivet(fw * 0.5, ryPos); // Left Edge
            drawRivet(w - fw * 0.5, ryPos); // Right Edge
        }
    }

    // 9. "Hero" Plaque Construction Bottom Center
    let ph = fw * 1.6;
    let py = h - fw * 0.5 - ph * 0.5;

    // Base Plaque Polished Outline Structure
    ctx.shadowColor = "rgba(0,0,0,0.9)";
    ctx.shadowBlur = minDim * 0.02;
    ctx.shadowOffsetY = minDim * 0.01;
    ctx.beginPath();
    let chamfer = ph * 0.25;
    ctx.moveTo(px + chamfer, py);
    ctx.lineTo(px + pw - chamfer, py);
    ctx.lineTo(px + pw, py + chamfer);
    ctx.lineTo(px + pw, py + ph - chamfer);
    ctx.lineTo(px + pw - chamfer, py + ph);
    ctx.lineTo(px + chamfer, py + ph);
    ctx.lineTo(px, py + ph - chamfer);
    ctx.lineTo(px, py + chamfer);
    ctx.closePath();

    ctx.fillStyle = trimGrad; // Plaque body utilizes opposite trim color metal
    ctx.fill();
    ctx.shadowBlur = 0;
    ctx.shadowOffsetY = 0;

    // Inner Dark Emblazoned Recess
    let inM = ph * 0.12;
    ctx.beginPath();
    ctx.moveTo(px + chamfer + inM, py + inM);
    ctx.lineTo(px + pw - chamfer - inM, py + inM);
    ctx.lineTo(px + pw - inM, py + chamfer + inM * 0.5);
    ctx.lineTo(px + pw - inM, py + ph - chamfer - inM * 0.5);
    ctx.lineTo(px + pw - chamfer - inM, py + ph - inM);
    ctx.lineTo(px + chamfer + inM, py + ph - inM);
    ctx.lineTo(px + inM, py + ph - chamfer - inM * 0.5);
    ctx.lineTo(px + inM, py + chamfer + inM * 0.5);
    ctx.closePath();

    let darkGrad = ctx.createLinearGradient(0, py, 0, py + ph);
    darkGrad.addColorStop(0, "#111");
    darkGrad.addColorStop(0.5, "#3d3d3d");
    darkGrad.addColorStop(1, "#050505");
    ctx.fillStyle = darkGrad;
    ctx.fill();

    // Rivet joints fastening inner plaque
    drawRivet(px + chamfer + inM * 1.6, py + ph / 2, minDim * 0.01);
    drawRivet(px + pw - chamfer - inM * 1.6, py + ph / 2, minDim * 0.01);

    // Render Text (e.g. ГЕРОЙ В ДОСПЕХАХ)
    ctx.textAlign = "center";
    ctx.textBaseline = "middle";
    let fontSize = ph * 0.45;
    ctx.font = `bold ${fontSize}px "Impact", "Arial Black", sans-serif`;

    // Dynamic scale text font if it is too wide
    let textWidthLimit = pw - (chamfer + inM * 3) * 2;
    let textWidth = ctx.measureText(titleText).width;
    if (textWidth > textWidthLimit) {
        fontSize *= textWidthLimit / textWidth;
        ctx.font = `bold ${fontSize}px "Impact", "Arial Black", sans-serif`;
    }

    ctx.fillStyle = armorGrad; // Blend metal gradient into phrase texture mapping
    
    // Drop shadow simulation making phrase look embossed out of iron block
    ctx.shadowColor = "black";
    ctx.shadowOffsetX = 2;
    ctx.shadowOffsetY = 2;
    ctx.shadowBlur = 3;
    ctx.fillText(titleText, w / 2, py + ph / 2 + fontSize * 0.05);

    // Front high-light mapping
    ctx.shadowColor = "rgba(255,255,255,0.7)";
    ctx.shadowOffsetX = -1;
    ctx.shadowOffsetY = -1;
    ctx.shadowBlur = 1;
    ctx.fillText(titleText, w / 2, py + ph / 2 + fontSize * 0.05);

    ctx.shadowBlur = 0;
    ctx.shadowColor = "transparent";
    ctx.shadowOffsetX = 0;
    ctx.shadowOffsetY = 0;

    // 10. Starburst & Shiny Lens Flare Functions purely emphasizing "Shiny Armor"
    function drawSparkle(cx, cy, size) {
        ctx.save();
        ctx.translate(cx, cy);
        
        let grad = ctx.createRadialGradient(0, 0, 0, 0, 0, size);
        grad.addColorStop(0, "rgba(255,255,255,1)");
        grad.addColorStop(0.2, "rgba(255,255,255,0.9)");
        grad.addColorStop(1, "rgba(255,255,255,0)");

        ctx.fillStyle = grad;
        ctx.beginPath();
        ctx.arc(0, 0, size, 0, Math.PI * 2);
        ctx.fill();

        // Thick ray burst
        ctx.beginPath();
        ctx.moveTo(-size * 2, 0); ctx.lineTo(size * 2, 0);
        ctx.moveTo(0, -size * 2); ctx.lineTo(0, size * 2);
        ctx.lineWidth = size * 0.15;
        ctx.strokeStyle = "rgba(255,255,255,0.8)";
        ctx.stroke();

        // Thin sharp interior cross
        ctx.beginPath();
        ctx.moveTo(-size * 2, 0); ctx.lineTo(size * 2, 0);
        ctx.moveTo(0, -size * 2); ctx.lineTo(0, size * 2);
        ctx.lineWidth = Math.max(1, size * 0.04);
        ctx.strokeStyle = "#fff";
        ctx.stroke();

        ctx.restore();
    }

    let sparkSize = minDim * 0.05;
    drawSparkle(fw * 1.5, fw * 1.5, sparkSize);             // Top-Left glare
    drawSparkle(w - fw * 1.5, fw * 1.5, sparkSize * 0.6);   // Top-Right tiny glare
    drawSparkle(w - fw * 1.5, h - fw * 1.5, sparkSize);     // Bottom-Right glare

    // Final plaque magical sparkles
    drawSparkle(px + chamfer, py + chamfer, sparkSize * 0.5);
    drawSparkle(px + pw - chamfer, py + ph - chamfer, sparkSize * 0.4);

    return canvas;
}

Free Image Tool Creator

Can't find the image tool you're looking for?
Create one based on your own needs now!

Description

This tool transforms your uploaded images into epic, cinematic portraits by applying a stylized ‘heroic’ frame. It adds a sophisticated metallic border—available in gold or silver finishes—featuring intricate details like chainmail patterns, 3D beveling, corner plates, and rivets. The generator also enhances the original image with increased contrast and saturation, applies a dramatic vignette to focus on the subject, and adds sparkling lens flares for a high-shine effect. Additionally, it features a customizable decorative plaque at the bottom to display custom titles. This tool is ideal for creating fantasy-themed profile pictures, gaming avatars, or dramatic character art for storytelling and social media.

Leave a Reply

Your email address will not be published. Required fields are marked *