Please bookmark this page to avoid losing your image tool!

Image Desert Mirage Filter Effect Generator

(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, colorIntensity = 0.5, distortionStrength = 10, distortionFrequency = 0.05) {
    const canvas = document.createElement('canvas');
    // { willReadFrequently: true } is a performance hint for contexts where getImageData is called often.
    const ctx = canvas.getContext('2d', { willReadFrequently: true });

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

    // Handle cases where the image might not be loaded or has no dimensions.
    if (width === 0 || height === 0) {
        console.warn("Image has zero width or height. Returning empty canvas.");
        canvas.width = 1; // Set a minimal size to avoid errors with 0x0 canvas
        canvas.height = 1;
        return canvas;
    }

    canvas.width = width;
    canvas.height = height;

    // Draw the original image onto the canvas. This is necessary to access its pixel data.
    ctx.drawImage(originalImg, 0, 0, width, height);

    let originalImageData;
    try {
        // Get pixel data from the canvas.
        originalImageData = ctx.getImageData(0, 0, width, height);
    } catch (e) {
        // This can happen due to cross-origin restrictions if the image is not served with CORS headers.
        console.error("Could not get image data, possibly due to cross-origin restrictions:", e);
        // Return the canvas with the original image drawn, as processing is not possible.
        return canvas; 
    }
    
    const outputImageData = ctx.createImageData(width, height);
    const data = originalImageData.data; // Source pixel data
    const outputData = outputImageData.data; // Destination pixel data

    // Pre-calculate a factor for the x-component of the wave phase.
    // This gives the waves a slight shimmer/diagonal aspect rather than being perfectly horizontal.
    const phaseShiftXFactor = distortionFrequency * 0.1;

    for (let y = 0; y < height; y++) {
        // yProgress is a normalized value from 0 (top) to 1 (bottom).
        // Used to make the distortion effect stronger towards the bottom of the image.
        const yProgress = (height > 1) ? (y / (height - 1)) : 0; 
        
        // The amplitude of the wave modulation increases with yProgress.
        const currentWaveAmplitude = distortionStrength * yProgress;

        for (let x = 0; x < width; x++) {
            let horizontalShift = 0;
            // Calculate horizontal pixel displacement only if there's strength and frequency.
            if (currentWaveAmplitude !== 0 && distortionFrequency !== 0) {
                 horizontalShift = currentWaveAmplitude * Math.sin(y * distortionFrequency + x * phaseShiftXFactor);
            }
            
            // Determine the source pixel coordinates after applying distortion.
            let sourceX = Math.round(x + horizontalShift);
            const sourceY = y; // For this effect, we only distort horizontally.

            // Clamp source coordinates to be within image boundaries.
            sourceX = Math.max(0, Math.min(width - 1, sourceX));
            // sourceY is y, which is already in bounds [0, height-1].

            const sourceIndex = (sourceY * width + sourceX) * 4; // Calculate index in 1D pixel array.

            // Get original RGBA values from the source pixel.
            let r = data[sourceIndex];
            let g = data[sourceIndex + 1];
            let b = data[sourceIndex + 2];
            const a = data[sourceIndex + 3];

            // --- Apply Color Filter (Desert Mirage Tones) ---
            // Work with floating point numbers for color calculations for precision.
            let nr = parseFloat(r);
            let ng = parseFloat(g);
            let nb = parseFloat(b);

            // 1. Apply brightness increase and slight desaturation (washout effect).
            // colorIntensity scales the strength of these effects (0: no effect, 1: full effect).
            const brightnessFactor = 1.0 + 0.4 * colorIntensity; // Up to 40% brighter at full intensity.
            const desaturationAmount = 0.25 * colorIntensity;  // Up to 25% desaturation.

            if (desaturationAmount > 0) { // Avoid division by zero if nr,ng,nb are all 0
                const avg = (nr + ng + nb) / 3.0;
                nr = nr * (1.0 - desaturationAmount) + avg * desaturationAmount;
                ng = ng * (1.0 - desaturationAmount) + avg * desaturationAmount;
                nb = nb * (1.0 - desaturationAmount) + avg * desaturationAmount;
            }
            
            nr *= brightnessFactor;
            ng *= brightnessFactor;
            nb *= brightnessFactor;

            // 2. Tint towards a hazy warm color (light, warm, slightly desaturated yellow-orange).
            // Define target tint color components.
            const tintR = 255.0; 
            const tintG = 225.0; 
            const tintB = 160.0; 
            
            // Blend current color with the tint color.
            // colorIntensity controls the blend factor.
            const tintBlendFactor = 0.5 * colorIntensity; 

            nr = nr * (1.0 - tintBlendFactor) + tintR * tintBlendFactor;
            ng = ng * (1.0 - tintBlendFactor) + tintG * tintBlendFactor;
            nb = nb * (1.0 - tintBlendFactor) + tintB * tintBlendFactor;
            
            // Write the processed RGBA values to the output pixel data.
            // Clamp values to [0, 255] and round to integers.
            const destIndex = (y * width + x) * 4;
            outputData[destIndex] = Math.min(255, Math.max(0, Math.round(nr)));
            outputData[destIndex + 1] = Math.min(255, Math.max(0, Math.round(ng)));
            outputData[destIndex + 2] = Math.min(255, Math.max(0, Math.round(nb)));
            outputData[destIndex + 3] = a; // Preserve original alpha.
        }
    }

    // Put the modified pixel data back onto the canvas.
    ctx.putImageData(outputImageData, 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 Desert Mirage Filter Effect Generator allows users to apply a unique desert mirage effect to their images, enhancing them with a warm, hazy tint, increased brightness, and a wave-like distortion. This tool can be particularly useful for photographers seeking to create artistic, dreamlike visuals for personal projects, social media, or marketing materials. By adjusting the color intensity and distortion parameters, users can customize the effect to suit their artistic vision, making it an excellent resource for graphic designers and creative enthusiasts alike.

Leave a Reply

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