Please bookmark this page to avoid losing your image tool!

Image Cinestill 800T Filter Effect 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.
async function processImage(originalImg, 
    halationStrength = 0.5, // Range: 0 to 1. Strength of the halation effect.
    halationRadius = 10,    // Range: 0 to 50 (pixels). Blur radius for halation.
    coolingAmount = 0.15,   // Range: 0 to 1. Intensity of the cooling (blue shift) effect.
    saturationFactor = 0.9, // Range: 0 to 2. 1 is original saturation, 0 is grayscale.
    contrastFactor = 1.1,   // Range: 0 to 2. 1 is original contrast.
    grainAmount = 15,       // Range: 0 to 50. Intensity of film grain.
    tealShadowsAmount = 0.1, // Range: 0 to 0.5. Amount of teal tint in shadows.
    orangeHighlightsAmount = 0.1 // Range: 0 to 0.5. Amount of orange tint in highlights.
) {
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
    
    canvas.width = originalImg.naturalWidth || originalImg.width;
    canvas.height = originalImg.naturalHeight || originalImg.height;

    // Handle cases where image might not be loaded or has no dimensions
    if (canvas.width === 0 || canvas.height === 0) {
        console.error("Image has zero width or height.");
        return canvas; 
    }

    // Draw original image
    ctx.drawImage(originalImg, 0, 0);

    // Get ImageData for pixel manipulation
    const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
    const data = imageData.data;
    const len = data.length;

    // Constants for luminance calculation
    const lumR = 0.299;
    const lumG = 0.587;
    const lumB = 0.114;

    for (let i = 0; i < len; i += 4) {
        let r = data[i];
        let g = data[i + 1];
        let b = data[i + 2];

        // 1. Cooling Effect (Simulating tungsten balance in daylight)
        if (coolingAmount > 0) {
            r *= (1 - coolingAmount * 0.5); // Reduce red
            g *= (1 - coolingAmount * 0.25); // Slightly reduce green
            b *= (1 + coolingAmount);      // Increase blue
        }

        // 2. Contrast
        if (contrastFactor !== 1.0) {
            // Adjust contrast: f * (c - 128) + 128
            r = contrastFactor * (r - 128) + 128;
            g = contrastFactor * (g - 128) + 128;
            b = contrastFactor * (b - 128) + 128;
        }
        
        // 3. Saturation
        if (saturationFactor !== 1.0) {
            const gray = r * lumR + g * lumG + b * lumB;
            r = gray + saturationFactor * (r - gray);
            g = gray + saturationFactor * (g - gray);
            b = gray + saturationFactor * (b - gray);
        }

        // Clamp intermediate values to [0, 255]
        r = Math.max(0, Math.min(255, r));
        g = Math.max(0, Math.min(255, g));
        b = Math.max(0, Math.min(255, b));

        // 4. Teal Shadows / Orange Highlights (Split Toning)
        const currentLuminance = r * lumR + g * lumG + b * lumB;
        
        // Teal shadows
        const shadowThreshold = 85; // Pixels with luminance below this are considered shadows
        if (tealShadowsAmount > 0 && currentLuminance < shadowThreshold) {
            // Calculate mix factor, stronger for darker shadows
            const shadowMix = Math.pow((shadowThreshold - currentLuminance) / shadowThreshold, 1.5);
            b += 60 * tealShadowsAmount * shadowMix; // Add blue for teal
            g += 30 * tealShadowsAmount * shadowMix; // Add some green for teal
            r -= 30 * tealShadowsAmount * shadowMix; // Reduce red complementary to cyan/teal
        }

        // Orange highlights
        const highlightThresholdSplitTone = 170; // Pixels with luminance above this are highlights
        if (orangeHighlightsAmount > 0 && currentLuminance > highlightThresholdSplitTone) {
            // Calculate mix factor, stronger for brighter highlights
            const highlightMix = Math.pow((currentLuminance - highlightThresholdSplitTone) / (255 - highlightThresholdSplitTone), 1.5);
            r += 60 * orangeHighlightsAmount * highlightMix; // Add red for orange
            g += 30 * orangeHighlightsAmount * highlightMix; // Add some green for orange
            b -= 30 * orangeHighlightsAmount * highlightMix; // Reduce blue complementary to orange
        }
        
        // Clamp again after split toning
        r = Math.max(0, Math.min(255, r));
        g = Math.max(0, Math.min(255, g));
        b = Math.max(0, Math.min(255, b));

        // 5. Film Grain
        if (grainAmount > 0) {
            const grain = (Math.random() - 0.5) * grainAmount;
            r += grain;
            g += grain;
            b += grain;
        }
        
        // Final Clamp for pixel data
        data[i] = Math.max(0, Math.min(255, r));
        data[i + 1] = Math.max(0, Math.min(255, g));
        data[i + 2] = Math.max(0, Math.min(255, b));
    }

    // Put modified image data back to the main canvas
    ctx.putImageData(imageData, 0, 0);

    // 6. Halation
    if (halationStrength > 0 && halationRadius > 0) {
        const halationCanvas = document.createElement('canvas');
        halationCanvas.width = canvas.width;
        halationCanvas.height = canvas.height;
        const hCtx = halationCanvas.getContext('2d', { willReadFrequently: true });

        // Draw the current image (color-graded, grained) onto halation canvas to extract highlights
        hCtx.drawImage(canvas, 0, 0); 
        
        const hImageData = hCtx.getImageData(0, 0, halationCanvas.width, halationCanvas.height);
        const hData = hImageData.data;
        const hLen = hData.length;

        const halationColorR = 255;
        const halationColorG = 70; 
        const halationColorB = 50; // Reddish-orange halation color
        const halationHighlightThreshold = 200; // Brightness threshold for glow Ccinestill has prominent red halation

        for (let i = 0; i < hLen; i += 4) {
            const rPx = hData[i]; // Red component of the current pixel on main canvas
            const gPx = hData[i+1];
            const bPx = hData[i+2];
            
            const brightness = (rPx + gPx + bPx) / 3;
            let intensityFactor = 0;

            // Trigger halation for overall bright areas or very red areas
            if (brightness > halationHighlightThreshold || rPx > 220) { 
                let exceedAmount = (brightness - halationHighlightThreshold);
                if (rPx > 220) { // Boost intensity for very red pixels
                    exceedAmount += (rPx - 220) * 0.5;
                }
                intensityFactor = Math.min(1, Math.max(0, exceedAmount) / (255 - halationHighlightThreshold + 30));
            }

            if (intensityFactor > 0) {
                hData[i] = halationColorR;
                hData[i + 1] = halationColorG;
                hData[i + 2] = halationColorB;
                hData[i + 3] = intensityFactor * 255; // Alpha is proportional to highlight intensity
            } else {
                hData[i + 3] = 0; // Fully transparent if not a highlight
            }
        }
        hCtx.putImageData(hImageData, 0, 0); // Put the generated halation mask onto halationCanvas

        // Blur the halation mask
        // Create a temporary canvas for blurring because ctx.filter applies to future drawings
        const tempBlurCanvas = document.createElement('canvas');
        tempBlurCanvas.width = halationCanvas.width;
        tempBlurCanvas.height = halationCanvas.height;
        const tempBlurCtx = tempBlurCanvas.getContext('2d');
        
        tempBlurCtx.filter = `blur(${halationRadius}px)`;
        tempBlurCtx.drawImage(halationCanvas, 0, 0); // Draw halationCanvas onto tempBlurCanvas, applying blur
        
        // Composite blurred halation layer onto the main canvas
        ctx.save();
        ctx.globalCompositeOperation = 'lighter'; // Use 'lighter' (additive) or 'screen' for glow
        ctx.globalAlpha = halationStrength; // Control overall halation intensity
        ctx.drawImage(tempBlurCanvas, 0, 0); // Draw the blurred halation map
        ctx.restore(); // Restore canvas context state
    }

    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 Cinestill 800T Filter Effect Tool allows users to apply a cinematic filter effect inspired by the Cinestill 800T film. This tool enhances images by simulating halation, adjusting colors with a cooling effect, and introducing tonal shifts with teal shadows and orange highlights. Users can customize various parameters, including halation strength, grain amount, contrast, and saturation, to achieve the desired appearance. This tool is useful for photographers and digital artists looking to evoke a specific film-like aesthetic or enhance their images with artistic color grading.

Leave a Reply

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