Please bookmark this page to avoid losing your image tool!

Heartfelt Photo Filter 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, warmth = 0.3, softness = 0.5, vignetteStrength = 0.4) {

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

    // Ensure parameters are numbers, as they could be passed as strings
    const numWarmth = Number(warmth);
    const numSoftness = Number(softness);
    const numVignetteStrength = Number(vignetteStrength);

    // Use naturalWidth/Height for intrinsic image dimensions, fallback to width/height
    const imgWidth = originalImg.naturalWidth || originalImg.width;
    const imgHeight = originalImg.naturalHeight || originalImg.height;

    if (imgWidth === 0 || imgHeight === 0) {
        // This can happen if the image isn't loaded yet or is invalid.
        // Return a minimal canvas to avoid errors downstream.
        canvas.width = 1; // Avoid 0x0 canvas if it causes issues in some rendering contexts
        canvas.height = 1;
        console.warn("Original image has zero dimensions. Returning a 1x1 canvas. Ensure the image is loaded before processing.");
        return canvas;
    }

    canvas.width = imgWidth;
    canvas.height = imgHeight;

    // 1. Draw the original image onto the canvas
    ctx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);

    // 2. Apply Warmth (Pixel manipulation)
    // This effect increases red and green tones, and decreases blue tones, giving a warmer, "heartfelt" feel.
    if (numWarmth > 0) {
        try {
            const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
            const data = imageData.data;
            for (let i = 0; i < data.length; i += 4) {
                let r = data[i];
                let g = data[i+1];
                let b = data[i+2];

                // Apply warmth: increase red, slightly increase green, decrease blue
                // The factors (30, 5, 25) are chosen to give a pleasant warm tint.
                data[i]   = Math.min(255, r + 30 * numWarmth); // Red channel
                data[i+1] = Math.min(255, g + 5 * numWarmth);  // Green channel
                data[i+2] = Math.max(0, b - 25 * numWarmth);   // Blue channel
            }
            ctx.putImageData(imageData, 0, 0);
        } catch (e) {
            // This error can occur if the image is loaded from a different origin
            // without proper CORS headers, tainting the canvas.
            console.error("Could not apply warmth: Error accessing pixel data. This may be due to CORS policy.", e);
            // The function will continue, but warmth effect might be missing.
        }
    }

    // 3. Apply Softness (Blur)
    // This adds a gentle blur for a dreamy, soft focus effect often associated with heartfelt imagery.
    if (numSoftness > 0) {
        // To apply a filter like blur to the entire canvas, it's best to draw the current canvas
        // content to a temporary canvas (or itself if handled carefully) with the filter active.
        const snapshotCanvas = document.createElement('canvas');
        snapshotCanvas.width = canvas.width;
        snapshotCanvas.height = canvas.height;
        const snapshotCtx = snapshotCanvas.getContext('2d');

        if (snapshotCtx) {
            snapshotCtx.drawImage(canvas, 0, 0); // Copy current (warmed) canvas content to the snapshot

            ctx.clearRect(0, 0, canvas.width, canvas.height); // Clear the main canvas
            ctx.filter = `blur(${numSoftness}px)`;           // Set the blur filter on the main canvas context
            ctx.drawImage(snapshotCanvas, 0, 0);            // Draw the snapshot back to the main canvas, applying the blur
            ctx.filter = 'none';                            // Reset the filter to avoid affecting subsequent drawing operations
        } else {
            // This is unlikely in most browser environments but handled as a precaution.
            console.warn("Could not obtain 2D context for snapshot canvas during softness application.");
        }
    }

    // 4. Apply Vignette
    // This darkens the corners of the image, drawing the viewer's focus to the center.
    // A warm, dark brown color is used for the vignette to complement the "heartfelt" theme.
    if (numVignetteStrength > 0 && numVignetteStrength <= 1) { // Vignette strength expected 0 to 1
        ctx.globalCompositeOperation = 'source-over'; // Ensure default drawing mode

        const centerX = canvas.width / 2;
        const centerY = canvas.height / 2;
        // The outer radius of the vignette should typically cover the corners of the image.
        const outerRadius = Math.sqrt(Math.pow(centerX, 2) + Math.pow(centerY, 2));
        
        // Calculate the inner radius for the radial gradient.
        // A higher vignetteStrength means the dark effect starts closer to the center (smaller innerRadiusRatio).
        // innerRadiusRatio ranges from 1.0 (vignette fully transparent if strength is 0, effectively)
        // down to ~0.2 (for strength 1.0, vignette effect starts close to center).
        const innerRadiusRatio = 1.0 - (numVignetteStrength * 0.8); 
        // Ensure innerRadius is not excessively small, Math.max(0.1, ...) ensures it's at least 10% of outerRadius.
        const innerRadius = outerRadius * Math.max(0.1, innerRadiusRatio);

        const gradient = ctx.createRadialGradient(
            centerX, centerY, innerRadius,  // Inner circle (start of gradient)
            centerX, centerY, outerRadius   // Outer circle (end of gradient)
        );

        const vignetteBaseColor = '30,10,0'; // A dark, warm brown (RGB) for the vignette color

        // Define gradient color stops:
        // At the innerRadius (stop 0), the vignette is fully transparent.
        gradient.addColorStop(0, `rgba(${vignetteBaseColor}, 0)`);
        // Add an intermediate stop for a smoother falloff. Opacity here is 60% of numVignetteStrength.
        gradient.addColorStop(0.7, `rgba(${vignetteBaseColor}, ${numVignetteStrength * 0.6})`);
        // At the outerRadius (stop 1), the vignette reaches its maximum opacity (90% of numVignetteStrength).
        gradient.addColorStop(1, `rgba(${vignetteBaseColor}, ${numVignetteStrength * 0.9})`);

        ctx.fillStyle = gradient;
        ctx.fillRect(0, 0, canvas.width, canvas.height); // Apply the vignette gradient over the current image
    }
    
    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 Heartfelt Photo Filter Tool allows users to enhance their images with a warm, soft, and vignetted effect, ideal for adding a heartfelt touch to photos. Users can adjust warmth to create a cozy atmosphere, softness for a dreamy blur, and vignette strength to draw focus to the center of the image. This tool is perfect for personal photos, social media posts, or any project where a tender and emotional visual impact is desired.

Leave a Reply

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