Please bookmark this page to avoid losing your image tool!

Image Ancient Scroll Parchment Frame Enhancer

(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 = 50, baseColorStr = "245,222,179", noiseIntensity = 20, stainOpacity = 0.08, edgeRoughness = 25, edgeDarkness = 0.5, imageShadowOpacity = 0.3) {
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');

    // Ensure parameters are numbers
    frameSize = Number(frameSize);
    noiseIntensity = Number(noiseIntensity);
    stainOpacity = Number(stainOpacity);
    edgeRoughness = Number(edgeRoughness);
    edgeDarkness = Number(edgeDarkness);
    imageShadowOpacity = Number(imageShadowOpacity);

    // Parse baseColorStr
    const colorParts = baseColorStr.split(',');
    const baseR = parseInt(colorParts[0].trim(), 10);
    const baseG = parseInt(colorParts[1].trim(), 10);
    const baseB = parseInt(colorParts[2].trim(), 10);

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

    ctx.save(); // Save initial clean state

    // Helper function to define the irregular parchment shape
    function defineParchmentShape(currentCtx, x, y, width, height, roughness, segmentLength = 30) {
        currentCtx.beginPath();
        const r = () => (Math.random() - 0.5) * roughness * 2; // Main perpendicular offset
        const rs = () => (Math.random() - 0.5) * roughness * 0.5; // Smaller tangential offset

        // Top-left corner
        currentCtx.moveTo(x + r(), y + r());

        // Top edge
        for (let curX = x + segmentLength; curX < x + width; curX += segmentLength) {
            currentCtx.lineTo(curX + rs(), y + r());
        }
        currentCtx.lineTo(x + width - r(), y + r()); // Top-right corner

        // Right edge
        for (let curY = y + segmentLength; curY < y + height; curY += segmentLength) {
            currentCtx.lineTo(x + width - r(), curY + rs());
        }
        currentCtx.lineTo(x + width - r(), y + height - r()); // Bottom-right corner

        // Bottom edge
        for (let curX = x + width - segmentLength; curX > x; curX -= segmentLength) {
            currentCtx.lineTo(curX + rs(), y + height - r());
        }
        currentCtx.lineTo(x + r(), y + height - r()); // Bottom-left corner

        // Left edge
        for (let curY = y + height - segmentLength; curY > y; curY -= segmentLength) {
            currentCtx.lineTo(x + r(), curY + rs());
        }
        currentCtx.closePath();
    }

    // 1. Define and fill the parchment shape
    defineParchmentShape(ctx, 0, 0, canvas.width, canvas.height, edgeRoughness);
    ctx.fillStyle = `rgb(${baseR},${baseG},${baseB})`;
    ctx.fill();

    // 2. Clip to this shape for subsequent effects
    ctx.clip();

    // 3. Noise Texture (Clipped)
    if (noiseIntensity > 0) {
        const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
        const data = imageData.data;
        for (let i = 0; i < data.length; i += 4) {
            // Only apply noise to opaque pixels (i.e., inside the clipped parchment shape)
            if (data[i + 3] > 0) { 
                const rand = (Math.random() - 0.5) * noiseIntensity;
                data[i]   = Math.max(0, Math.min(255, data[i]   + rand));
                data[i+1] = Math.max(0, Math.min(255, data[i+1] + rand));
                data[i+2] = Math.max(0, Math.min(255, data[i+2] + rand));
            }
        }
        ctx.putImageData(imageData, 0, 0);
    }

    // 4. Mottled Stains (Clipped)
    if (stainOpacity > 0) {
        const stainR = Math.max(0, baseR - 40); // Darker shade of base color
        const stainG = Math.max(0, baseG - 40);
        const stainB = Math.max(0, baseB - 40);
        ctx.fillStyle = `rgba(${stainR}, ${stainG}, ${stainB}, ${stainOpacity})`;
        
        const numStains = Math.floor((canvas.width * canvas.height) / 50000) + 5; // Scale stains with size
        for (let i = 0; i < numStains; i++) {
            const sx = Math.random() * canvas.width;
            const sy = Math.random() * canvas.height;
            const sRadiusX = (Math.random() * 0.2 + 0.15) * canvas.width; // Large, soft stains
            const sRadiusY = (Math.random() * 0.2 + 0.15) * canvas.height;
            ctx.beginPath();
            ctx.ellipse(sx, sy, sRadiusX, sRadiusY, Math.random() * Math.PI * 2, 0, Math.PI * 2);
            ctx.fill();
        }
    }

    // 5. Edge Darkening/Vignette (Clipped)
    if (edgeDarkness > 0) {
        const gradientCenterX = canvas.width / 2;
        const gradientCenterY = canvas.height / 2;
        // Make inner radius proportional to the smallest dimension, ensuring some central brightness
        const innerRadius = Math.min(canvas.width, canvas.height) * 0.15; 
        // Outer radius should reach the corners
        const outerRadius = Math.sqrt(Math.pow(canvas.width / 2, 2) + Math.pow(canvas.height / 2, 2));

        const gradient = ctx.createRadialGradient(gradientCenterX, gradientCenterY, innerRadius, gradientCenterX, gradientCenterY, outerRadius);
        gradient.addColorStop(0, 'rgba(0,0,0,0)'); // Transparent center
        gradient.addColorStop(1, `rgba(0,0,0,${edgeDarkness})`); // Darker edges
        
        ctx.fillStyle = gradient;
        ctx.fillRect(0, 0, canvas.width, canvas.height);
    }

    ctx.restore(); // Remove clipping, parchment is fully rendered.

    // 6. Draw the Original Image
    const imgX = frameSize;
    const imgY = frameSize;
    const imgWidth = originalImg.width;
    const imgHeight = originalImg.height;

    if (imageShadowOpacity > 0) {
        ctx.save();
        ctx.shadowColor = `rgba(0, 0, 0, ${imageShadowOpacity})`;
        ctx.shadowBlur = Math.max(5, frameSize * 0.25); 
        ctx.shadowOffsetX = Math.max(2, frameSize * 0.1);
        ctx.shadowOffsetY = Math.max(2, frameSize * 0.1);
        ctx.drawImage(originalImg, imgX, imgY, imgWidth, imgHeight);
        ctx.restore();
    } else {
        ctx.drawImage(originalImg, imgX, imgY, imgWidth, imgHeight);
    }
    
    // Optional: Draw a very thin, dark line around the image to make it "sit" better
    ctx.strokeStyle = 'rgba(0,0,0,0.15)';
    ctx.lineWidth = 1;
    ctx.strokeRect(imgX - 0.5, imgY - 0.5, imgWidth + 1, imgHeight + 1);

    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 Ancient Scroll Parchment Frame Enhancer is a tool designed to transform images by framing them within an aesthetically pleasing parchment-style border. This tool enhances visual content by adding an aged, scroll-like effect that is perfect for enhancing historical themes, storytelling, or artistic presentations. Users can customize various parameters such as frame size, base color, noise intensity, stain opacity, edge roughness, and shadow effects to achieve the desired look for their images. It is ideal for use in creative projects, digital scrapbooking, artistic portfolios, or any situation where a vintage or classical appearance is sought.

Leave a Reply

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