Please bookmark this page to avoid losing your image tool!

Image Portrait To Classic Hollywood Cinematic Still 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.
/**
 * Transforms a portrait image into a classic Hollywood cinematic still by applying
 * a series of filters for lighting, color, sharpness, and texture.
 *
 * @param {Image} originalImg The original Image object to process.
 * @param {number} [contrast=60] The contrast level (0-100). 50 is neutral. Higher values create more dramatic lighting.
 * @param {number} [desaturation=90] The amount of desaturation (0-100). 100 is full grayscale.
 * @param {number} [sharpen=25] The amount of sharpening to apply (0-100).
 * @param {number} [grain=10] The amount of cinematic grain to add (0-100).
 * @param {number} [vignette=50] The strength of the vignette effect to isolate the subject (0-100).
 * @param {string} [tintColor='#1a2530'] The hexadecimal color code for the moody tint (e.g., '#RRGGBB').
 * @param {number} [tintAmount=20] The intensity of the color tint (0-100).
 * @returns {Promise<HTMLCanvasElement>} A canvas element with the processed image.
 */
async function processImage(originalImg, contrast = 60, desaturation = 90, sharpen = 25, grain = 10, vignette = 50, tintColor = '#1a2530', tintAmount = 20) {
    const canvas = document.createElement('canvas');
    // Using { willReadFrequently: true } can optimize frequent getImageData/putImageData calls.
    const ctx = canvas.getContext('2d', { willReadFrequently: true });

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

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

    // 2. Apply pixel-level filters: Desaturation, Contrast, and Tint
    if (desaturation > 0 || contrast !== 50 || tintAmount > 0) {
        const imageData = ctx.getImageData(0, 0, w, h);
        const data = imageData.data;

        // Pre-calculate factors and parse colors for efficiency
        const desat = desaturation / 100;
        const tintMix = tintAmount / 100;
        
        // Map contrast from 0-100 to a more effective range for the formula
        const contrastValue = ((contrast - 50) / 50) * 128;
        const contrastFactor = (259 * (contrastValue + 255)) / (255 * (259 - contrastValue));
        
        const tr = parseInt(tintColor.slice(1, 3), 16);
        const tg = parseInt(tintColor.slice(3, 5), 16);
        const tb = parseInt(tintColor.slice(5, 7), 16);

        // Iterate through each pixel
        for (let i = 0; i < data.length; i += 4) {
            let r = data[i];
            let g = data[i + 1];
            let b = data[i + 2];

            // A. Apply Desaturation
            const gray = 0.299 * r + 0.587 * g + 0.114 * b;
            r = r * (1 - desat) + gray * desat;
            g = g * (1 - desat) + gray * desat;
            b = b * (1 - desat) + gray * desat;
            
            // B. Apply Contrast
            r = contrastFactor * (r - 127) + 127;
            g = contrastFactor * (g - 127) + 127;
            b = contrastFactor * (b - 127) + 127;

            // C. Apply Color Tint
            if (tintMix > 0) {
                r = r * (1 - tintMix) + tr * tintMix;
                g = g * (1 - tintMix) + tg * tintMix;
                b = b * (1 - tintMix) + tb * tintMix;
            }

            // Clamp values to the 0-255 range
            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));
        }
        ctx.putImageData(imageData, 0, 0);
    }

    // 3. Apply Sharpening using a convolution filter (Unsharp Mask)
    if (sharpen > 0) {
        const srcData = ctx.getImageData(0, 0, w, h);
        const src = srcData.data;
        const dstData = ctx.createImageData(w, h);
        const dst = dstData.data;
        dst.set(src); // Copy original image data, including alpha

        const amount = sharpen / 100.0;
        
        // Process pixels, skipping a 1-pixel border to avoid edge issues
        for (let y = 1; y < h - 1; y++) {
            for (let x = 1; x < w - 1; x++) {
                const i = (y * w + x) * 4;
                for (let c = 0; c < 3; c++) { // Iterate over R, G, B channels
                    const sc = i + c;
                    // Simple 3x3 high-pass filter kernel
                    const highPass = 5 * src[sc] - (src[sc - 4] + src[sc + 4] + src[sc - w * 4] + src[sc + w * 4]);
                    // Blend original pixel with the high-pass filtered version
                    dst[sc] = src[sc] * (1 - amount) + highPass * amount;
                }
            }
        }
        ctx.putImageData(dstData, 0, 0);
    }
    
    // 4. Apply Vignette effect using a radial gradient and multiply blend mode
    if (vignette > 0) {
        const strength = vignette / 100;
        const outerRadius = Math.sqrt(Math.pow(w / 2, 2) + Math.pow(h / 2, 2));
        const innerRadius = outerRadius * (1 - strength);

        const gradient = ctx.createRadialGradient(w / 2, h / 2, innerRadius, w / 2, h / 2, outerRadius);
        gradient.addColorStop(0, 'rgba(0,0,0,0)');
        // A black vignette can be too harsh; a dark grey is often more subtle.
        gradient.addColorStop(1, `rgba(0,0,0,${strength})`);

        ctx.fillStyle = gradient;
        ctx.fillRect(0, 0, w, h);
    }

    // 5. Apply Cinematic Grain using a tiled noise pattern with 'overlay' blend mode
    if (grain > 0) {
        const grainAmount = grain / 100;
        const grainSize = 128; // Use a small, tileable texture for performance

        const grainCanvas = document.createElement('canvas');
        grainCanvas.width = grainSize;
        grainCanvas.height = grainSize;
        const grainCtx = grainCanvas.getContext('2d');
        const grainData = grainCtx.createImageData(grainSize, grainSize);
        const grainPixels = grainData.data;

        for (let i = 0; i < grainPixels.length; i += 4) {
            const value = Math.floor(Math.random() * 255);
            grainPixels[i] = value;
            grainPixels[i + 1] = value;
            grainPixels[i + 2] = value;
            grainPixels[i + 3] = 255;
        }
        grainCtx.putImageData(grainData, 0, 0);
        
        ctx.globalAlpha = grainAmount * 0.2; // Control grain visibility
        ctx.globalCompositeOperation = 'overlay';
        
        const pattern = ctx.createPattern(grainCanvas, 'repeat');
        if (pattern) {
          ctx.fillStyle = pattern;
          ctx.fillRect(0, 0, w, h);
        }

        // Reset context properties to defaults
        ctx.globalAlpha = 1.0;
        ctx.globalCompositeOperation = 'source-over';
    }

    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 Portrait to Classic Hollywood Cinematic Still Enhancer is a powerful online tool designed to transform your portrait images into stunning, cinematic artworks reminiscent of classic Hollywood films. This tool applies various advanced filters to enhance the lighting, color, sharpness, and texture of your images, allowing for a sophisticated and artistic finish. Users can adjust settings such as contrast for dramatic lighting, desaturation for a vintage feel, sharpening for added detail, and grain for a classic film texture. Additionally, a vignette effect helps to focus attention on the subject, while customizable tinting can create a specific mood or atmosphere. This tool is ideal for photographers, graphic designers, or anyone looking to elevate their image aesthetic for social media, personal projects, or presentations.

Leave a Reply

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