Please bookmark this page to avoid losing your image tool!

Image Fujichrome Velvia 50 Filter Effect Application

(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, intensity = 1.0) {
    const canvas = document.createElement('canvas');
    // Use { willReadFrequently: true } for potential performance optimization if supported by the browser.
    // This hints to the browser that we'll be using getImageData/putImageData frequently.
    const ctx = canvas.getContext('2d', { willReadFrequently: true });

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

    // If image dimensions are not valid, return an empty canvas.
    if (!imgWidth || !imgHeight) {
        console.error("Image Fujichrome Velvia 50 Filter: Image has no dimensions or is not loaded. Returning an empty canvas.");
        canvas.width = 0;
        canvas.height = 0;
        return canvas;
    }

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

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

    let imageData;
    try {
        // Get the pixel data from the canvas.
        imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
    } catch (e) {
        // This can happen due to cross-origin issues if the image is from another domain and CORS isn't set up.
        console.error("Image Fujichrome Velvia 50 Filter: Could not getImageData. Canvas may be tainted by cross-origin data.", e);
        // In case of an error (e.g., tainted canvas), return the canvas with the original image drawn but unprocessed.
        return canvas; 
    }
    
    const data = imageData.data; // This is a Uint8ClampedArray: [R,G,B,A, R,G,B,A, ...]

    // Ensure intensity is a number and clamped to a reasonable range.
    // Affects the strength of the filter:
    // 0.0 = no effect (original image characteristics)
    // 1.0 = standard "Velvia 50" effect as defined by base parameters
    // > 1.0 = exaggerated effect (clamped at 2.0 to prevent extreme results)
    let numIntensity = Number(intensity);
    if (isNaN(numIntensity)) {
        numIntensity = 1.0; // Default to 1.0 if input is not a valid number
    }
    const currentIntensity = Math.max(0, Math.min(2.0, numIntensity));

    // Base parameters for Fujichrome Velvia 50 emulation.
    // These values are chosen to approximate the film's characteristics:
    // high contrast, high saturation, and specific color responses.
    const base_contrast = 1.2;    // Velvia is known for higher contrast. (1.0 = no change)
    const base_saturation = 1.4;  // Velvia has strong, vivid colors. (1.0 = no change)
    
    // Gamma adjustments for R, G, B channels to mimic film's color rendition.
    // Gamma < 1.0 generally brightens/intensifies that color component.
    // Gamma > 1.0 generally darkens/deepens that color component.
    const base_red_gamma = 0.95;    // Enhances reds.
    const base_green_gamma = 0.93;  // Enhances greens, making them lush.
    const base_blue_gamma = 1.05;   // Deepens blues.

    // Calculate effective filter parameters based on the current intensity.
    // If currentIntensity is 0, parameters will result in no change.
    // If currentIntensity is 1, parameters will be their base values.
    const actual_contrast = 1.0 + (base_contrast - 1.0) * currentIntensity;
    const actual_saturation = 1.0 + (base_saturation - 1.0) * currentIntensity;
    
    const derive_final_gamma = (base_gamma_val, current_intensity_val) => {
        // If base_gamma is 1.0 (no change), or intensity is 0, final gamma is 1.0.
        if (base_gamma_val === 1.0 || current_intensity_val === 0) return 1.0;
        // Interpolate the gamma adjustment: (base_gamma - 1.0) is the "amount" of gamma shift.
        return 1.0 + (base_gamma_val - 1.0) * current_intensity_val;
    };

    const final_red_gamma = derive_final_gamma(base_red_gamma, currentIntensity);
    const final_green_gamma = derive_final_gamma(base_green_gamma, currentIntensity);
    const final_blue_gamma = derive_final_gamma(base_blue_gamma, currentIntensity);

    // Standard luminance coefficients (Rec. 601 / NTSC) for saturation calculation.
    const lumR = 0.299;
    const lumG = 0.587;
    const lumB = 0.114;

    // Iterate over each pixel (each pixel consists of 4 values: R, G, B, A).
    for (let i = 0; i < data.length; i += 4) {
        // Get current pixel's RGB values. Alpha (data[i+3]) is preserved.
        let r_val = data[i];
        let g_val = data[i + 1];
        let b_val = data[i + 2];

        // Normalize RGB values to the [0, 1] range for calculations.
        let r_n = r_val / 255;
        let g_n = g_val / 255;
        let b_n = b_val / 255;

        // 1. Apply Contrast adjustment.
        if (actual_contrast !== 1.0) { // Optimization: skip if no change.
            r_n = (r_n - 0.5) * actual_contrast + 0.5;
            g_n = (g_n - 0.5) * actual_contrast + 0.5;
            b_n = (b_n - 0.5) * actual_contrast + 0.5;
        }
        // Clamp values to [0, 1] after contrast.
        r_n = Math.max(0, Math.min(1, r_n));
        g_n = Math.max(0, Math.min(1, g_n));
        b_n = Math.max(0, Math.min(1, b_n));
        
        // 2. Apply Saturation adjustment.
        if (actual_saturation !== 1.0) { // Optimization: skip if no change.
            // Calculate luminance of the current pixel.
            const L = lumR * r_n + lumG * g_n + lumB * b_n; 
            // Adjust saturation: push color components further from (or closer to) luminance.
            r_n = L + actual_saturation * (r_n - L);
            g_n = L + actual_saturation * (g_n - L);
            b_n = L + actual_saturation * (b_n - L);
        }
        // Clamp values to [0, 1] after saturation.
        r_n = Math.max(0, Math.min(1, r_n));
        g_n = Math.max(0, Math.min(1, g_n));
        b_n = Math.max(0, Math.min(1, b_n));

        // 3. Apply Velvia-like color gamma adjustments to individual channels.
        // Math.pow(0, positive_gamma) is 0. If gamma becomes non-positive (not expected here due to intensity clamp),
        // Math.pow(0, non_positive_gamma) could be Infinity or NaN.
        // The (val > 0) check is a safeguard, though current clamping ensures gamma is positive.
        if (final_red_gamma !== 1.0) {
             r_n = (r_n > 0) ? Math.pow(r_n, final_red_gamma) : 0;
        }
        if (final_green_gamma !== 1.0) {
             g_n = (g_n > 0) ? Math.pow(g_n, final_green_gamma) : 0;
        }
        if (final_blue_gamma !== 1.0) {
             b_n = (b_n > 0) ? Math.pow(b_n, final_blue_gamma) : 0;
        }
        
        // Final clamp, though values should generally be within [0,1] already.
        r_n = Math.max(0, Math.min(1, r_n));
        g_n = Math.max(0, Math.min(1, g_n));
        b_n = Math.max(0, Math.min(1, b_n));

        // Convert normalized [0, 1] values back to [0, 255] and update pixel data.
        data[i] = r_n * 255;
        data[i + 1] = g_n * 255;
        data[i + 2] = b_n * 255;
        // data[i + 3] (alpha) remains unchanged.
    }

    // Write the modified pixel data back to the canvas.
    ctx.putImageData(imageData, 0, 0);
    
    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 Fujichrome Velvia 50 Filter Effect Application allows users to apply a Velvia 50 film simulation effect to their images. This tool enhances the saturation and contrast of the images, mimicking the vibrant colors and distinct tonal characteristics associated with Fujichrome Velvia 50 film. Users can adjust the intensity of the effect to achieve subtle or dramatic enhancements, making it suitable for photographers, graphic designers, and anyone looking to enhance their images with a classic film look. Common use cases include enhancing landscape photography, creating vivid visuals for social media, and adding artistic effects to personal projects.

Leave a Reply

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

Other Image Tools:

Image Revolog Texture Film Filter Effect Tool

Image Lomography Metropolis Filter Effect Application

Image Variable ND Filter Effect Tool

Image 8mm Movie Film Filter Effect Application

Image TMax 100 Filter Effect Application

Image Fog Filter Effect Tool

Image Ektachrome E100 Filter Effect Application

Image RED Cinema Camera Filter Effect Tool

Image Reverse Graduated ND Filter Effect Tool

Image Kaleidoscope Filter Effect Tool

Image Platinum Palladium Print Filter Effect

Image Light Leak Filter Effect Tool

Image Moire Pattern Filter Effect Tool

Image Pull Processing Filter Effect Tool

Photo Ambrotype Filter Effect Tool

Image Cross-Screen Star Filter Effect Tool

Image Tiffen Ultra Contrast Filter Effect Application

Photo Telephoto Lens Compression Filter Effect Tool

Image Leica M6 Camera Render Filter Effect

Image Cokin Sunset Filter Effect Application

Image CineScope Aspect Ratio Filter Effect Tool

Image Ilford FP4 Plus Filter Effect Tool

Image Infrared 850nm Filter Effect Tool

Image Pentax 67 Medium Format Filter Effect Tool

Image ARRI Alexa Cinema Camera Filter Effect Enhancer

Image Cinestill 50D Filter Effect Application

Image Kodachrome 64 Filter Effect Tool

Photo Lomography Berlin Kino Filter Effect Tool

Image Fujifilm Neopan Filter Effect Tool

Image Polaroid Instant Film Filter Effect Tool

Image Holga Camera Filter Effect Tool

Image Fisheye Lens Distortion Filter Effect Tool

Image Kodak Gold 200 Film Filter Effect Tool

Photo Macro Filter Effect Tool

Image Neutral Density Filter Effect Tool

Image Green Filter Black And White Effect Tool

See All →