Please bookmark this page to avoid losing your image tool!

Image 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, frameThicknessStr = "20", frameColor = "black", matThicknessStr = "10", matColor = "white", cornerRadiusStr = "0") {

    // Helper function to draw a rounded rectangle path.
    // Assumes width and height are non-negative.
    function _drawRoundedRect_internal(ctx, x, y, width, height, radius) {
        let r = Math.max(0, radius); // Ensure radius is not negative initially
        
        // If width or height is zero, radius must be zero.
        // Clamp radius to be at most half of the shorter side.
        if (width > 0 && height > 0) {
          r = Math.min(r, width / 2, height / 2);
        } else {
          r = 0; // For a line or point, radius is effectively 0.
        }

        ctx.beginPath();
        ctx.moveTo(x + r, y); // Start at top-left after the curve
        
        // Top edge and top-right corner
        ctx.lineTo(x + width - r, y);
        if (r > 0) { // Only draw arc if radius is positive
            ctx.arcTo(x + width, y, x + width, y + r, r);
        }
        
        // Right edge and bottom-right corner
        ctx.lineTo(x + width, y + height - r);
        if (r > 0) {
            ctx.arcTo(x + width, y + height, x + width - r, y + height, r);
        }
        
        // Bottom edge and bottom-left corner
        ctx.lineTo(x + r, y + height);
        if (r > 0) {
            ctx.arcTo(x, y + height, x, y + height - r, r);
        }
        
        // Left edge and top-left corner
        ctx.lineTo(x, y + r);
        if (r > 0) {
            ctx.arcTo(x, y, x + r, y, r);
        }
        
        ctx.closePath();
    }

    // Parse and validate parameters
    let frameThickness = parseInt(frameThicknessStr, 10);
    // Default to 20 if parsing fails or value is negative
    if (isNaN(frameThickness) || frameThickness < 0) frameThickness = 20;

    // Default to "black" if color is not a valid string or is empty/whitespace
    let currentFrameColor = (typeof frameColor === 'string' && frameColor.trim() !== "") ? frameColor : "black";

    let matThickness = parseInt(matThicknessStr, 10);
    if (isNaN(matThickness) || matThickness < 0) matThickness = 10;

    let currentMatColor = (typeof matColor === 'string' && matColor.trim() !== "") ? matColor : "white";
    
    let cornerRadius = parseInt(cornerRadiusStr, 10);
    if (isNaN(cornerRadius) || cornerRadius < 0) cornerRadius = 0;

    // Original image dimensions
    const imgWidth = originalImg.width;
    const imgHeight = originalImg.height;

    // Calculate final canvas dimensions, ensuring they are not negative
    const canvasWidth = Math.max(0, imgWidth + 2 * matThickness + 2 * frameThickness);
    const canvasHeight = Math.max(0, imgHeight + 2 * matThickness + 2 * frameThickness);

    // Create canvas and context
    const canvas = document.createElement('canvas');
    canvas.width = canvasWidth;
    canvas.height = canvasHeight;
    const ctx = canvas.getContext('2d');

    // If final canvas dimensions are zero, return an empty canvas
    if (canvasWidth === 0 || canvasHeight === 0) {
        return canvas;
    }

    // 1. Draw Frame Border
    // This is the outermost layer.
    ctx.fillStyle = currentFrameColor;
    _drawRoundedRect_internal(ctx, 0, 0, canvasWidth, canvasHeight, cornerRadius);
    ctx.fill();

    // 2. Draw Matting Area
    // This is drawn on top of the frame border.
    const matX = frameThickness;
    const matY = frameThickness;
    // Calculate matting area dimensions, ensuring non-negative
    const matWidth = Math.max(0, canvasWidth - 2 * frameThickness); // Effectively imgWidth + 2 * matThickness
    const matHeight = Math.max(0, canvasHeight - 2 * frameThickness); // Effectively imgHeight + 2 * matThickness
    
    // Matting area's outer corners are rounded based on the main cornerRadius and frameThickness
    const matOuterCornerRadius = Math.max(0, cornerRadius - frameThickness);

    // Only draw matting if it has positive dimensions
    if (matWidth > 0 && matHeight > 0) {
        ctx.fillStyle = currentMatColor;
        _drawRoundedRect_internal(ctx, matX, matY, matWidth, matHeight, matOuterCornerRadius);
        ctx.fill();
    }
    
    // 3. Draw The Image
    // The image is drawn on top of the matting area.
    // It needs to be clipped to the inner shape of the matting.
    const imgAreaX = frameThickness + matThickness; // Top-left X for image
    const imgAreaY = frameThickness + matThickness; // Top-left Y for image
    
    // Image clipping path radius, based on matting's inner curvature
    const imgClipRadius = Math.max(0, matOuterCornerRadius - matThickness);

    // Only draw image if its original dimensions are positive
    if (imgWidth > 0 && imgHeight > 0) {
        ctx.save(); // Save context state before clipping
        // Define clipping path for the image
        _drawRoundedRect_internal(ctx, imgAreaX, imgAreaY, imgWidth, imgHeight, imgClipRadius);
        ctx.clip(); // Apply clipping path
        
        // Draw the image
        ctx.drawImage(originalImg, imgAreaX, imgAreaY, imgWidth, imgHeight);
        
        ctx.restore(); // Restore context state (remove clipping path)
    }
    
    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 Frame Creator tool allows users to enhance their images by adding customizable frames and matting to them. Users can specify the thickness, color, and corner radius of the frame and mat, making it easy to create visually appealing presentations of their photos. This tool is useful for photographers looking to showcase their work in a professional manner, artists wanting to present their artwork, or anyone needing to prepare images for printing or display. The resulting framed image can be easily downloaded for sharing or printing.

Leave a Reply

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