Please bookmark this page to avoid losing your image tool!

Image Botanical Illustration Frame Creator

(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, frameSize = 30, frameColor = "saddlebrown", paddingSize = 15, matColor = "ivory", decorationSpread = 40, decorationColor = "darkgreen", leafSize = 15, leafDensity = 0.7) {

    // Coerce and validate numeric parameters
    frameSize = Number(frameSize);
    paddingSize = Number(paddingSize);
    decorationSpread = Number(decorationSpread);
    leafSize = Number(leafSize);
    leafDensity = Number(leafDensity);

    if (isNaN(frameSize) || frameSize < 0) frameSize = 30;
    if (isNaN(paddingSize) || paddingSize < 0) paddingSize = 15;
    if (isNaN(decorationSpread) || decorationSpread < 0) decorationSpread = 40;
    if (isNaN(leafSize) || leafSize <= 0) leafSize = 15; 
    if (isNaN(leafDensity) || leafDensity < 0) leafDensity = 0;
    if (leafDensity > 1) leafDensity = 1;

    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');

    const dW = originalImg.width;
    const dH = originalImg.height;

    // Handle cases where the original image has no valid dimensions
    if (dW <= 0 || dH <= 0) {
        canvas.width = Math.max(1, 2 * paddingSize + 2 * frameSize + 2 * decorationSpread);
        canvas.height = Math.max(1, 2 * paddingSize + 2 * frameSize + 2 * decorationSpread);
        ctx.fillStyle = matColor;
        ctx.fillRect(0, 0, canvas.width, canvas.height);
        if (typeof console !== 'undefined' && console.warn) { // Check for console existence
             console.warn("Original image has zero or invalid dimension. Returning empty framed canvas.");
        }
        return canvas;
    }

    canvas.width = dW + 2 * paddingSize + 2 * frameSize + 2 * decorationSpread;
    canvas.height = dH + 2 * paddingSize + 2 * frameSize + 2 * decorationSpread;

    // 1. Fill entire canvas with matColor (background for decoration area and padding)
    ctx.fillStyle = matColor;
    ctx.fillRect(0, 0, canvas.width, canvas.height);

    // 2. Draw the frame rectangle
    const frameRectX = decorationSpread;
    const frameRectY = decorationSpread;
    const frameRectW = dW + 2 * paddingSize + 2 * frameSize;
    const frameRectH = dH + 2 * paddingSize + 2 * frameSize;
    ctx.fillStyle = frameColor;
    ctx.fillRect(frameRectX, frameRectY, frameRectW, frameRectH);

    // 3. "Cut out" the center for padding area by drawing matColor over the frame
    const innerMatX = decorationSpread + frameSize;
    const innerMatY = decorationSpread + frameSize;
    const innerMatW = dW + 2 * paddingSize;
    const innerMatH = dH + 2 * paddingSize;
    ctx.fillStyle = matColor; 
    ctx.fillRect(innerMatX, innerMatY, innerMatW, innerMatH);

    // 4. Draw the original image
    const imgDrawX = decorationSpread + frameSize + paddingSize;
    const imgDrawY = decorationSpread + frameSize + paddingSize;
    ctx.drawImage(originalImg, imgDrawX, imgDrawY, dW, dH);

    // 5. Draw botanical decorations if conditions are met
    if (leafDensity > 0 && decorationSpread > 0 && leafSize > 0) {
        
        // Helper function to draw a single botanical leaf
        function drawBotanicalLeaf(pivotX, pivotY, lSize, angleDegrees, lColor) {
            ctx.save();
            ctx.translate(pivotX, pivotY);
            ctx.rotate(angleDegrees * Math.PI / 180);
            
            // Leaf shape: tip at (0, -lSize*0.6), base at (0, lSize*0.6) in local coords when angle=0
            // This means the leaf is drawn along its local Y-axis.
            const tipY = -lSize * 0.6; 
            const baseY = lSize * 0.6;
            const midBulgeX = lSize * 0.35; // Width of the leaf bulge
            const midBulgeYControl = lSize * 0.2; // Y position of control point for bulge
            const midNarrowX = lSize * 0.25; // Width at narrower part near tip
            const midNarrowYControl = -lSize * 0.2; // Y position of control point for narrow part

            ctx.beginPath();
            ctx.moveTo(0, tipY); 
            ctx.quadraticCurveTo(midNarrowX, midNarrowYControl, midBulgeX, midBulgeYControl); 
            ctx.quadraticCurveTo(lSize * 0.1, lSize * 0.5, 0, baseY); 
            ctx.quadraticCurveTo(-lSize * 0.1, lSize * 0.5, -midBulgeX, midBulgeYControl);
            ctx.quadraticCurveTo(-midNarrowX, midNarrowYControl, 0, tipY); 
            
            ctx.fillStyle = lColor;
            ctx.fill();

            // Simple vein for added detail
            ctx.strokeStyle = 'rgba(0,0,0,0.18)'; 
            ctx.lineWidth = Math.max(1, lSize / 18);
            ctx.beginPath();
            ctx.moveTo(0, tipY * 0.85); 
            ctx.lineTo(0, baseY * 0.65); 
            ctx.stroke();
            
            ctx.restore();
        }

        // Calculate step for leaf placement based on density
        // Smaller step = denser leaves
        const step = Math.max(leafSize * 0.4, leafSize * (1.8 - leafDensity * 1.4));

        // Function to process drawing leaves along one edge of the frame
        const processEdge = (iterStartX, iterStartY, edgeLength, edgeType) => {
            for (let i = 0; i < edgeLength; i += step) {
                const currentLeafSize = leafSize * (0.75 + Math.random() * 0.5); // Vary size
                const actual_S_base = currentLeafSize * 0.6; // Distance from pivot to leaf's local base point
                
                // How far from the frame's actual edge the leaf base should be.
                // Random value within decorationSpread.
                const randomOffsetFromEdge = Math.random() * decorationSpread * 0.8; 

                let angleDeg, targetBaseX, targetBaseY;
                const angleRadVariation = (Math.random() - 0.5) * 70; // +/- 35 degrees variation

                if (edgeType === "top") {
                    angleDeg = 0 + angleRadVariation; // Points towards canvas -Y (up)
                    targetBaseX = iterStartX + i + (Math.random() - 0.5) * step; // Jitter along edge
                    targetBaseY = iterStartY - randomOffsetFromEdge; 
                } else if (edgeType === "bottom") {
                    angleDeg = 180 + angleRadVariation; // Points towards canvas +Y (down)
                    targetBaseX = iterStartX + i + (Math.random() - 0.5) * step;
                    targetBaseY = iterStartY + randomOffsetFromEdge;
                } else if (edgeType === "left") {
                    angleDeg = 90 + angleRadVariation; // Points towards canvas -X (left)
                    targetBaseX = iterStartX - randomOffsetFromEdge;
                    targetBaseY = iterStartY + i + (Math.random() - 0.5) * step;
                } else { // edgeType === "right"
                    angleDeg = -90 + angleRadVariation; // Points towards canvas +X (right)
                    targetBaseX = iterStartX + randomOffsetFromEdge;
                    targetBaseY = iterStartY + i + (Math.random() - 0.5) * step;
                }
                
                const angleRad = angleDeg * Math.PI / 180;
                // Calculate pivot point for drawBotanicalLeaf based on where the base should be
                const pivotX = targetBaseX + actual_S_base * Math.sin(angleRad);
                const pivotY = targetBaseY - actual_S_base * Math.cos(angleRad);
                
                drawBotanicalLeaf(pivotX, pivotY, currentLeafSize, angleDeg, decorationColor);
            }
        };
        
        // Process each of the four edges for decoration
        // iterStartX, iterStartY are the coordinates of the frame edge itself.
        processEdge(frameRectX, frameRectY, frameRectW, "top");
        processEdge(frameRectX, frameRectY + frameRectH, frameRectW, "bottom");
        processEdge(frameRectX, frameRectY, frameRectH, "left");
        processEdge(frameRectX + frameRectW, frameRectY, frameRectH, "right");
    }

    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 Image Botanical Illustration Frame Creator allows users to enhance their images by adding a decorative botanical frame. This tool offers customization options such as frame size, color, and padding, as well as mat color and leaf decoration. It is ideal for creating visually appealing displays of artwork or photographs, making it suitable for artists, photographers, and anyone looking to present their images in a stylistic manner. Use cases include creating framed graphics for prints, invitations, or digital presentations where an elegant botanical aesthetic is desired.

Leave a Reply

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