Please bookmark this page to avoid losing your image tool!

Image Old Map Frame With Compass Rose Decorator

(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.
async function processImage(
    originalImg,
    frameBaseColor = '#654321', // Default: SaddleBrown-like color for the main frame
    parchmentBgColor = '#F5EACE', // Default: Light Parchment/Aged paper color
    compassMainColor = '#5C4033', // Default: Dark Brown for E,S,W compass points
    compassNorthColor = '#B22222', // Default: Firebrick Red for North compass point
    compassPosition = 'top-right', // Options: "top-left", "top-right", "bottom-left", "bottom-right"
    frameScaleFactor = 1.0 // Adjusts frame thickness, e.g., 0.5 (thinner) to 2.0 (thicker)
) {
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');

    // --- Validate & Sanitize Parameters ---
    const p_frameScaleFactor = Math.max(0.25, Math.min(3.0, Number(frameScaleFactor) || 1.0));

    // Basic color validation helper (accepts hex, common names, rgb/rgba)
    const isValidColor = (colorStr) => typeof colorStr === 'string' && (
        /^#([0-9A-Fa-f]{3,4}){1,2}$/.test(colorStr) || // hex, hexa
        /^[a-zA-Z]+$/.test(colorStr) || // named colors
        /^rgb\(\s*\d+%?\s*,\s*\d+%?\s*,\s*\d+%?\s*\)$/.test(colorStr) || // rgb
        /^rgba\(\s*\d+%?\s*,\s*\d+%?\s*,\s*\d+%?\s*,\s*(\d?.?\d+)\s*\)$/.test(colorStr) // rgba
    );
    
    const p_frameBaseColor = isValidColor(frameBaseColor) ? frameBaseColor : '#654321';
    const p_parchmentBgColor = isValidColor(parchmentBgColor) ? parchmentBgColor : '#F5EACE';
    const p_compassMainColor = isValidColor(compassMainColor) ? compassMainColor : '#5C4033';
    const p_compassNorthColor = isValidColor(compassNorthColor) ? compassNorthColor : '#B22222';
    const p_compassPosition = ['top-left', 'top-right', 'bottom-left', 'bottom-right'].includes(String(compassPosition).toLowerCase()) ? String(compassPosition).toLowerCase() : 'top-right';

    // --- Constants derived from parameters or fixed ---
    const baseFrameThicknessRatio = 0.1 * p_frameScaleFactor;
    const minFrameThickness = 25 * p_frameScaleFactor; // Adjusted min based on scale
    const maxFrameThickness = 150 * p_frameScaleFactor; // Adjusted max based on scale

    const frameInnerDetailColor = '#B08D57'; // Fixed: Old gold/brass detail for thematic consistency
    const compassLabelColor = '#2F1E1A';     // Fixed: Darker brown for compass labels

    // --- Calculate dimensions ---
    let frameThickness = Math.max(minFrameThickness,
                           Math.min(maxFrameThickness,
                                    Math.min(originalImg.width, originalImg.height) * baseFrameThicknessRatio));
    // Ensure frame thickness isn't excessively large compared to the image itself
    frameThickness = Math.min(frameThickness, originalImg.width / 2.5, originalImg.height / 2.5, 200); // Cap at 200 too


    canvas.width = originalImg.width + 2 * frameThickness;
    canvas.height = originalImg.height + 2 * frameThickness;

    // --- 1. Draw Parchment Background for the entire canvas ---
    ctx.fillStyle = p_parchmentBgColor;
    ctx.fillRect(0, 0, canvas.width, canvas.height);

    // Add subtle texture to parchment background
    ctx.save();
    const speckleAreaFactor = Math.min(canvas.width * canvas.height, 1000*800); // Cap area for speckle density
    const numSpeckles = Math.floor(speckleAreaFactor / 200); // Adjust density
    for (let i = 0; i < numSpeckles; i++) {
        const x = Math.random() * canvas.width;
        const y = Math.random() * canvas.height;
        const radius = Math.random() * 1.3 + 0.2;
        const alpha = Math.random() * 0.10 + 0.02; // Very faint speckles
        // Using faint black speckles for general applicability over any parchment color
        ctx.fillStyle = `rgba(0, 0, 0, ${alpha})`; 
        ctx.beginPath();
        ctx.arc(x, y, radius, 0, Math.PI * 2);
        ctx.fill();
    }
    ctx.restore();

    // --- 2. Draw the Frame ---
    // This frame is in the frameThickness area, around the image.
    ctx.fillStyle = p_frameBaseColor;
    ctx.fillRect(0, 0, canvas.width, frameThickness); // Top bar
    ctx.fillRect(0, canvas.height - frameThickness, canvas.width, frameThickness); // Bottom bar
    ctx.fillRect(0, frameThickness, frameThickness, canvas.height - 2 * frameThickness); // Left bar
    ctx.fillRect(canvas.width - frameThickness, frameThickness, frameThickness, canvas.height - 2 * frameThickness); // Right bar

    // Inner decorative line(s) for a bit of richness
    const detailLineWidth = Math.max(1, Math.min(6, frameThickness * 0.04));
    const detailInset1 = frameThickness * 0.2; // Inset from the outer edge of canvas

    ctx.strokeStyle = frameInnerDetailColor;
    ctx.lineWidth = detailLineWidth;
    ctx.strokeRect(detailInset1, detailInset1,
                   canvas.width - 2 * detailInset1, canvas.height - 2 * detailInset1);

    // Optional second inner line, closer to the image edge.
    const detailInset2 = frameThickness - (detailLineWidth * 1.8); // Closer to image edge
    if (detailInset2 > detailInset1 + detailLineWidth * 2.5) { // Ensure lines are distinct
        ctx.lineWidth = Math.max(1, detailLineWidth * 0.65); // Thinner line
        ctx.strokeRect(detailInset2, detailInset2,
                       canvas.width - 2 * detailInset2, canvas.height - 2 * detailInset2);
    }

    // --- 3. Draw the Original Image ---
    ctx.drawImage(originalImg, frameThickness, frameThickness, originalImg.width, originalImg.height);

    // --- 4. Draw the Compass Rose ---
    // Size calculation for compass rose
    const compassRoseOuterAllowRadius = frameThickness * 0.42; // Max space it could occupy
    const compassMarginFromFrameEdge = frameThickness * 0.08;  // Small margin

    // Actual radius for the main arms of the compass
    const finalCompassRadius = Math.max(12, // Min sensible radius
                                 Math.min(compassRoseOuterAllowRadius, (frameThickness / 2) - compassMarginFromFrameEdge));

    let compassCenterX, compassCenterY;
    // Center the compass within the width/height of the frame border
    const frameBorderCenterOffset = frameThickness / 2; 

    switch (p_compassPosition) {
        case 'top-left':
            compassCenterX = frameBorderCenterOffset;
            compassCenterY = frameBorderCenterOffset;
            break;
        case 'bottom-left':
            compassCenterX = frameBorderCenterOffset;
            compassCenterY = canvas.height - frameBorderCenterOffset;
            break;
        case 'bottom-right':
            compassCenterX = canvas.width - frameBorderCenterOffset;
            compassCenterY = canvas.height - frameBorderCenterOffset;
            break;
        case 'top-right': // Default
        default:
            compassCenterX = canvas.width - frameBorderCenterOffset;
            compassCenterY = frameBorderCenterOffset;
            break;
    }
    
    if (frameThickness >= 25 && finalCompassRadius >= 12) { // Only draw if frame is somewhat thick and radius is sensible
        _drawOldMapCompassRose(ctx,
                            compassCenterX, compassCenterY, finalCompassRadius,
                            p_compassMainColor,
                            p_compassNorthColor,
                            compassLabelColor
                           );
    }

    return canvas;
}

// Helper function to draw the compass rose (not directly part of the public API)
function _drawOldMapCompassRose(ctx, cx, cy, radius, primaryColor, northColor, labelColor) {
    const points = {
        N: { angle: -90, label: 'N', color: northColor, main: true },
        NE: { angle: -45, label: '', color: primaryColor, main: false },
        E: { angle: 0, label: 'E', color: primaryColor, main: true },
        SE: { angle: 45, label: '', color: primaryColor, main: false },
        S: { angle: 90, label: 'S', color: primaryColor, main: true },
        SW: { angle: 135, label: '', color: primaryColor, main: false },
        W: { angle: 180, label: 'W', color: primaryColor, main: true },
        NW: { angle: 225, label: '', color: primaryColor, main: false }
    };

    const mainArmLength = radius;
    const interArmLength = radius * 0.60; // Intercardinal arms are shorter
    const armBaseWidthRatio = 0.22;       // Relative width of the triangle base
    const armInnerFactorMain = 0.15;      // How close main arm bases are to center
    const armInnerFactorInter = 0.25;     // How close inter arm bases are to center

    ctx.save();
    ctx.translate(cx, cy);

    // Draw arms
    for (const key in points) {
        const p = points[key];
        const angleRad = p.angle * Math.PI / 180;
        const armLength = p.main ? mainArmLength : interArmLength;
        const baseHalfWidth = armLength * armBaseWidthRatio;
        const innerFactor = p.main ? armInnerFactorMain : armInnerFactorInter;

        if (armLength < 1) continue; // Skip if arm is too small

        ctx.save();
        ctx.rotate(angleRad); // Rotate grid for easier drawing of this arm

        const innerX = innerFactor * armLength; // X-coord of base points along arm's axis

        ctx.beginPath();
        ctx.moveTo(armLength, 0); // Tip of the arm
        ctx.lineTo(innerX, baseHalfWidth);  // Base point 1
        ctx.lineTo(innerX, -baseHalfWidth); // Base point 2
        ctx.closePath();

        ctx.fillStyle = p.color;
        ctx.fill();
        
        // Optional subtle outline for arms for better definition on similar backgrounds
        // ctx.strokeStyle = 'rgba(0,0,0,0.2)';
        // ctx.lineWidth = 0.5;
        // ctx.stroke();

        ctx.restore(); // Restore rotation context
    }

    // Decorative circles common in old compass roses
    ctx.strokeStyle = primaryColor; // Use primary color for circles for consistency
    ctx.lineWidth = Math.max(0.5, radius * 0.025); // Thin lines

    if (radius > 10) { // Outer guiding circle
        ctx.beginPath();
        ctx.arc(0, 0, mainArmLength * 0.92, 0, Math.PI * 2);
        ctx.stroke();
    }
    if (radius > 20) { // Inner guiding circle
        const innerCircleRadius = mainArmLength * Math.max(armInnerFactorMain, armInnerFactorInter) * 1.2;
        ctx.beginPath();
        ctx.arc(0, 0, innerCircleRadius , 0, Math.PI * 2);
        ctx.stroke();
    }

    // Center dot
    ctx.beginPath();
    ctx.arc(0, 0, Math.max(1, radius * 0.09), 0, Math.PI * 2);
    ctx.fillStyle = northColor; // Typically matches North or a contrast jewel color
    ctx.fill();
    if (radius > 8) { // Small border for center dot if large enough
         ctx.strokeStyle = 'rgba(0,0,0,0.4)';
         ctx.lineWidth = Math.max(0.5, radius * 0.015);
         ctx.stroke();
    }

    // Labels (N, E, S, W)
    const fontSize = Math.max(6, Math.min(16, Math.floor(radius * 0.26)));
    if (fontSize >= 6 && radius > 15) { // Check for minimum radius and font size for legibility
        ctx.fillStyle = labelColor;
        ctx.font = `bold ${fontSize}px serif`; // Serif font often used in old maps
        ctx.textAlign = 'center';
        ctx.textBaseline = 'middle';

        // Position labels slightly outside tips of main arms or adjust based on context
        const labelRadius = mainArmLength * 1.05 + fontSize * 0.3; 

        for (const key in points) {
            const p = points[key];
            if (p.label && p.main) { // Only for main points that have a label defined
                const angleRad = p.angle * Math.PI / 180;
                let lx = Math.cos(angleRad) * labelRadius;
                let ly = Math.sin(angleRad) * labelRadius;

                // Fine-tuning label positions for better aesthetic balance
                if (p.label === 'N') ly -= fontSize * 0.05;
                if (p.label === 'S') ly += fontSize * 0.1;
                if (p.label === 'E') lx += fontSize * 0.05;
                if (p.label === 'W') lx -= fontSize * 0.05;
                
                ctx.fillText(p.label, lx, ly);
            }
        }
    }
    ctx.restore(); // Restore from translate(cx, cy)
}

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 Old Map Frame With Compass Rose Decorator’ tool allows users to enhance images by adding a vintage-style frame resembling old maps, complete with decorative elements like a compass rose. This tool is particularly useful for creating themed visuals for presentations, artistic projects, or personal use, where a historical or adventurous aesthetic is desired. Users can customize the frame’s color, thickness, and the compass’s position and colors, enabling tailored designs that fit their artistic vision.

Leave a Reply

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

Other Image Tools:

Image Diploma and Degree Certificate Framer

Image Soviet Propaganda Poster Style Generator

Image Yu-Gi-Oh Card Template Creator

Image Ancient Roman Greek Tablet Frame Creator

Image Marriage Certificate Template Creator

Image Video Game Achievement Frame Creator

Image Newspaper Front Page Template Creator

Image Botanical Illustration Frame Creator

Image Vinyl Record Sleeve Template Creator

Vintage Photo Booth Strip Template Generator

Image Cyberpunk Interface Frame Designer

Image Detective Novel Cover Template

Image Achievement Certificate Framer

Image Illuminated Manuscript Frame Generator

Image Art Deco Poster Frame Creator

Image Egyptian Papyrus Scroll Frame Designer

Image Vintage Postage Stamp Frame Creator

Image Magic: The Gathering Card Frame Generator

Image Birth Certificate Template Generator

Image Driver’s License Template Creator

Image Scout Explorer Badge Template Creator

Image Steampunk Document Frame Creator

Image Vintage Scientific Illustration Frame Creator

Image Magazine Cover Template Creator

Image Album Cover Template Creator

Image Medieval Bestiary Page Template

Image Polaroid Instant Photo Frame

Image Pulp Fiction Book Cover Template

Image Medieval Manuscript Frame Creator

Image Vintage Advertisement Poster Generator

Victorian Image Calling Card Template

Image Award Certificate Template

Image Military Insignia Patch Template Creator

Image ID Card Template Creator

Image Film Strip Frame Creator

Image Sci-Fi Novel Cover Template

See All →