Please bookmark this page to avoid losing your image tool!

Photo Pinhole Camera Filter

(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) {
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');

    const w = originalImg.naturalWidth || originalImg.width;
    const h = originalImg.naturalHeight || originalImg.height;

    if (w === 0 || h === 0) {
        console.warn("Photo Pinhole Camera Filter: Image has zero dimensions. Returning a 1x1 canvas.");
        canvas.width = 1;
        canvas.height = 1;
        // You could optionally fill this 1x1 canvas with a color to indicate an issue
        // e.g., const errorCtx = canvas.getContext('2d'); errorCtx.fillStyle = 'red'; errorCtx.fillRect(0,0,1,1);
        return canvas;
    }

    canvas.width = w;
    canvas.height = h;

    // 1. Apply base image filters and draw the image
    // Pinhole camera effects typically include:
    // - Soft focus (slight blur)
    // - Desaturation or altered colors (e.g., sepia tint)
    // - Changes in contrast and brightness (often slightly darker, sometimes higher contrast)
    
    const blurAmount = '0.8px';        // Softens the image slightly
    const saturation = '50%';      // Reduces color vibrancy
    const sepiaTone = '30%';       // Adds a vintage brownish tint
    const contrastValue = '120%';  // Increases contrast for a more dramatic look
    const brightnessValue = '90%'; // Slightly darkens the image, common in old photos
    
    ctx.filter = `blur(${blurAmount}) saturate(${saturation}) sepia(${sepiaTone}) contrast(${contrastValue}) brightness(${brightnessValue})`;
    ctx.drawImage(originalImg, 0, 0, w, h);
    ctx.filter = 'none'; // Reset filter for subsequent drawing operations (like grain or vignette)

    // 2. Apply Film Grain
    // This adds a noisy texture, characteristic of old film.
    const grainIntensity = 20; // Adjusts how strong the grain effect is. Max +/- pixel value change.
    
    // Getting and putting image data can be performance-intensive on very large images,
    // but is necessary for pixel-level manipulation like grain.
    const imageData = ctx.getImageData(0, 0, w, h);
    const data = imageData.data; // This is a Uint8ClampedArray: [R,G,B,A, R,G,B,A, ...]

    for (let i = 0; i < data.length; i += 4) {
        // Only apply grain to pixels that are not fully transparent
        if (data[i + 3] > 0) { // Check alpha channel (data[i+3])
            // Generate a random noise value (can be positive or negative)
            const noise = (Math.random() - 0.5) * grainIntensity;
            
            // Add noise to Red, Green, and Blue channels
            // Ensure values stay within the 0-255 range
            data[i]   = Math.min(255, Math.max(0, data[i] + noise));   // Red
            data[i+1] = Math.min(255, Math.max(0, data[i+1] + noise)); // Green
            data[i+2] = Math.min(255, Math.max(0, data[i+2] + noise)); // Blue
            // Alpha channel (data[i+3]) remains unchanged
        }
    }
    ctx.putImageData(imageData, 0, 0);

    // 3. Apply Vignetting
    // This darkens the corners of the image, a common optical effect in pinhole cameras.
    const centerX = w / 2;
    const centerY = h / 2;

    // vignetteStartRadius: The radius from the center where the image is still clear
    // (i.e., where the dark gradient begins to fade in).
    // Relative to the smaller dimension of the image to ensure it looks good on various aspect ratios.
    const vignetteStartRadius = Math.min(w, h) * 0.20; 
    
    // vignetteEndRadius: The radius where the gradient reaches its maximum darkness.
    // This should typically extend to or beyond the corners of the image.
    // Distance from center to a corner: Math.sqrt(centerX^2 + centerY^2)
    const vignetteEndRadius = Math.sqrt(centerX * centerX + centerY * centerY); 

    const gradient = ctx.createRadialGradient(
        centerX, centerY, vignetteStartRadius, 
        centerX, centerY, vignetteEndRadius
    );

    // Define the color stops for the gradient:
    // - Starts fully transparent at vignetteStartRadius.
    // - Becomes partially dark towards the middle of the fade.
    // - Reaches its darkest point at vignetteEndRadius.
    gradient.addColorStop(0, 'rgba(0,0,0,0)');          // Center of vignette effect (transparent black)
    gradient.addColorStop(0.6, 'rgba(0,0,0,0.4)');       // Mid-point of vignette fade (darker)
    gradient.addColorStop(1, 'rgba(0,0,0,0.85)');      // Edge of vignette effect (very dark)

    ctx.fillStyle = gradient;
    // Using the default 'source-over' composite operation, which draws the gradient on top.
    ctx.fillRect(0, 0, w, h);

    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 Photo Pinhole Camera Filter is a web-based tool designed to apply a vintage aesthetic to your images, emulating the effect of a pinhole camera. This tool softens images with a slight blur, reduces color vibrancy through desaturation, and adds a classic sepia tone while enhancing contrast and reducing brightness for a dramatic, nostalgic look. It further incorporates realistic film grain and vignetting effects, darkening the corners of the image to add depth and focus. This tool is ideal for photographers, artists, and anyone looking to create artistic, retro-themed images for personal projects, social media, or decorative purposes.

Leave a Reply

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