Please bookmark this page to avoid losing your image tool!

Baroque Portrait Frame Creator Tool

(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, frameWidth = 50, mainGoldColor = "#DAA520", shadowAccentColor = "#8B4513", highlightAccentColor = "#FFD700") {
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');

    const imgWidth = originalImg.width;
    const imgHeight = originalImg.height;

    canvas.width = imgWidth + 2 * frameWidth;
    canvas.height = imgHeight + 2 * frameWidth;

    // Helper to darken or lighten a hex color
    // factor < 1 to darken, factor > 1 to lighten
    function multiplyHexColor(hex, factor) {
        if (!hex || typeof hex !== 'string' || !hex.startsWith('#')) return hex; // Return original if not valid hex
        let r = parseInt(hex.slice(1, 3), 16);
        let g = parseInt(hex.slice(3, 5), 16);
        let b = parseInt(hex.slice(5, 7), 16);
        
        r = Math.min(255, Math.max(0, Math.round(r * factor)));
        g = Math.min(255, Math.max(0, Math.round(g * factor)));
        b = Math.min(255, Math.max(0, Math.round(b * factor)));
        
        return `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`;
    }

    // Helper function for drawing acanthus-like ornament
    function drawAcanthusElement(cx, cy, size, rotation, color) {
        ctx.save();
        ctx.translate(cx, cy);
        ctx.rotate(rotation);
        ctx.fillStyle = color;
        
        ctx.shadowColor = 'rgba(0,0,0,0.3)';
        ctx.shadowBlur = Math.max(1, Math.floor(size * 0.08));
        ctx.shadowOffsetX = Math.max(1, Math.floor(size * 0.03));
        ctx.shadowOffsetY = Math.max(1, Math.floor(size * 0.03));

        // Simplified acanthus scroll/leaf shape
        ctx.beginPath();
        ctx.moveTo(0, -size * 0.5); // Tip of the leaf

        // Right side of the leaf
        ctx.bezierCurveTo(size * 0.3, -size * 0.5, size * 0.4, -size * 0.25, size * 0.35, 0); // Outer curve to mid-point horizontal
        ctx.bezierCurveTo(size * 0.5,  size * 0.1, size * 0.2,  size * 0.35, 0, size * 0.5);  // Inner curve from mid-point to base center

        // Left side of the leaf (mirrored)
        ctx.bezierCurveTo(-size * 0.2,  size * 0.35, -size * 0.5,  size * 0.1, -size * 0.35, 0); // Base center to mid-point horizontal (inner)
        ctx.bezierCurveTo(-size * 0.4, -size * 0.25, -size * 0.3, -size * 0.5, 0, -size * 0.5); // Mid-point horizontal to tip (outer)
        
        ctx.closePath();
        ctx.fill();

        // Clear shadow for subsequent drawings
        ctx.shadowColor = 'transparent';
        ctx.shadowBlur = 0;
        ctx.shadowOffsetX = 0;
        ctx.shadowOffsetY = 0;
        ctx.restore();
    }
    
    // Proportions for frame features
    const outerEdgeRatio = 0.05;
    const profileRatio = 0.10;
    const bevelDepthRatio = 0.20;

    const outerEdgeSize = Math.max(1, Math.floor(frameWidth * outerEdgeRatio));
    const profileThickness = Math.max(1, Math.floor(frameWidth * profileRatio));
    const bevelDepthActual = Math.max(2, Math.floor(frameWidth * bevelDepthRatio));
    
    // Layer 1: Outer edge/shadow
    ctx.fillStyle = shadowAccentColor;
    ctx.fillRect(0, 0, canvas.width, canvas.height);

    // Layer 2: Main Frame Body
    ctx.fillStyle = mainGoldColor;
    ctx.fillRect(outerEdgeSize, outerEdgeSize,
                 canvas.width - 2 * outerEdgeSize, canvas.height - 2 * outerEdgeSize);

    // Layer 2a: Highlight/Shadow on Main Frame Body for 3D profile
    ctx.fillStyle = highlightAccentColor;
    ctx.fillRect(outerEdgeSize, outerEdgeSize, 
                 canvas.width - 2 * outerEdgeSize, profileThickness); // Top highlight
    ctx.fillRect(outerEdgeSize, outerEdgeSize + profileThickness, 
                 profileThickness, canvas.height - 2 * outerEdgeSize - profileThickness); // Left highlight
    
    ctx.fillStyle = shadowAccentColor;
    ctx.fillRect(outerEdgeSize + profileThickness, canvas.height - outerEdgeSize - profileThickness, 
                 canvas.width - 2 * outerEdgeSize - profileThickness, profileThickness); // Bottom shadow
    ctx.fillRect(canvas.width - outerEdgeSize - profileThickness, outerEdgeSize + profileThickness,
                 profileThickness, canvas.height - 2 * outerEdgeSize - profileThickness * 2); // Right shadow (adjust height to not overlap top/bottom shadows)


    // Layer 3: Inner Bevel leading to the image
    const bevelStartOffset = outerEdgeSize + profileThickness;

    ctx.fillStyle = highlightAccentColor;
    ctx.beginPath(); // Top bevel
    ctx.moveTo(bevelStartOffset, bevelStartOffset);
    ctx.lineTo(canvas.width - bevelStartOffset, bevelStartOffset);
    ctx.lineTo(canvas.width - bevelStartOffset - bevelDepthActual, bevelStartOffset + bevelDepthActual);
    ctx.lineTo(bevelStartOffset + bevelDepthActual, bevelStartOffset + bevelDepthActual);
    ctx.closePath();
    ctx.fill();

    ctx.beginPath(); // Left bevel
    ctx.moveTo(bevelStartOffset, bevelStartOffset);
    ctx.lineTo(bevelStartOffset, canvas.height - bevelStartOffset);
    ctx.lineTo(bevelStartOffset + bevelDepthActual, canvas.height - bevelStartOffset - bevelDepthActual);
    ctx.lineTo(bevelStartOffset + bevelDepthActual, bevelStartOffset + bevelDepthActual);
    ctx.closePath();
    ctx.fill();

    ctx.fillStyle = shadowAccentColor;
    ctx.beginPath(); // Bottom bevel
    ctx.moveTo(bevelStartOffset + bevelDepthActual, canvas.height - bevelStartOffset - bevelDepthActual);
    ctx.lineTo(canvas.width - bevelStartOffset - bevelDepthActual, canvas.height - bevelStartOffset - bevelDepthActual);
    ctx.lineTo(canvas.width - bevelStartOffset, canvas.height - bevelStartOffset);
    ctx.lineTo(bevelStartOffset, canvas.height - bevelStartOffset);
    ctx.closePath();
    ctx.fill();

    ctx.beginPath(); // Right bevel
    ctx.moveTo(canvas.width - bevelStartOffset - bevelDepthActual, bevelStartOffset + bevelDepthActual);
    ctx.lineTo(canvas.width - bevelStartOffset - bevelDepthActual, canvas.height - bevelStartOffset - bevelDepthActual);
    ctx.lineTo(canvas.width - bevelStartOffset, canvas.height - bevelStartOffset);
    ctx.lineTo(canvas.width - bevelStartOffset, bevelStartOffset);
    ctx.closePath();
    ctx.fill();
    
    // Layer 4: Ornaments
    const flatPartXStart = outerEdgeSize + profileThickness;
    const flatBandThickness = frameWidth - (outerEdgeSize + profileThickness + bevelDepthActual);

    if (flatBandThickness >= Math.max(5, frameWidth * 0.1)) {
        const ornamentPlacementOffset = flatPartXStart + flatBandThickness / 2;
        const ornamentSizeMax = flatBandThickness * 0.85; // Ornament size fills most of the band

        const ornamentColor = multiplyHexColor(mainGoldColor, 0.80); // Darker gold for carved look

        if (ornamentSizeMax >= 3) { // Min practical size
            drawAcanthusElement(ornamentPlacementOffset, ornamentPlacementOffset, ornamentSizeMax, -Math.PI / 4, ornamentColor); // TL
            drawAcanthusElement(canvas.width - ornamentPlacementOffset, ornamentPlacementOffset, ornamentSizeMax, Math.PI / 4, ornamentColor); // TR
            drawAcanthusElement(ornamentPlacementOffset, canvas.height - ornamentPlacementOffset, ornamentSizeMax, -3 * Math.PI / 4, ornamentColor); // BL
            drawAcanthusElement(canvas.width - ornamentPlacementOffset, canvas.height - ornamentPlacementOffset, ornamentSizeMax, 3 * Math.PI / 4, ornamentColor); // BR

            const midOrnamentSize = ornamentSizeMax * 0.7;
            if (midOrnamentSize >= 3) {
                if (imgWidth > midOrnamentSize * 2) { // Image wide enough for side ornaments
                     drawAcanthusElement(canvas.width / 2, ornamentPlacementOffset, midOrnamentSize, 0, ornamentColor); // Top mid
                     drawAcanthusElement(canvas.width / 2, canvas.height - ornamentPlacementOffset, midOrnamentSize, Math.PI, ornamentColor); // Bottom mid
                }
                if (imgHeight > midOrnamentSize * 2) { // Image tall enough for side ornaments
                    drawAcanthusElement(ornamentPlacementOffset, canvas.height / 2, midOrnamentSize, -Math.PI / 2, ornamentColor); // Left mid
                    drawAcanthusElement(canvas.width - ornamentPlacementOffset, canvas.height / 2, midOrnamentSize, Math.PI / 2, ornamentColor); // Right mid
                }
            }
        }
    }

    // --- Draw the image ---
    ctx.drawImage(originalImg, frameWidth, frameWidth, imgWidth, imgHeight);

    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

The Baroque Portrait Frame Creator Tool allows users to enhance their images by adding an ornate Baroque-style frame. Users can customize the frame width and colors, making it suitable for various applications such as displaying portraits, art pieces, or personal photos in a more elegant manner. This tool is ideal for artists, photographers, and anyone looking to give their images a classic and sophisticated look.

Leave a Reply

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