Please bookmark this page to avoid losing your image tool!

Image Surrealist 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.
function processImage(originalImg, posterLevels = 5, distortionAmplitude = 10, distortionFrequency = 0.05, hueShift = 90) {

    // --- Helper: rgbToHsl ---
    // r, g, b are in [0, 255]
    // returns h in [0, 360), s in [0, 1], l in [0, 1]
    function rgbToHsl(r, g, b) {
        r /= 255; g /= 255; b /= 255;
        const max = Math.max(r, g, b), min = Math.min(r, g, b);
        let h, s;
        const l = (max + min) / 2;

        if (max === min) {
            h = s = 0; // achromatic
        } else {
            const d = max - min;
            s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
            switch (max) {
                case r: h = (g - b) / d + (g < b ? 6 : 0); break;
                case g: h = (b - r) / d + 2; break;
                case b: h = (r - g) / d + 4; break;
            }
            h /= 6;
        }
        return { h: h * 360, s: s, l: l };
    }

    // --- Helper: hslToRgb ---
    // h in [0, 360), s in [0, 1], l in [0, 1]
    // returns r, g, b in [0, 255]
    function hslToRgb(h, s, l) {
        let r, g, b;
        if (s === 0) {
            r = g = b = l; // achromatic
        } else {
            function hue2rgb(p, q, t) {
                if (t < 0) t += 1;
                if (t > 1) t -= 1;
                if (t < 1 / 6) return p + (q - p) * 6 * t;
                if (t < 1 / 2) return q;
                if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
                return p;
            }
            const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
            const p = 2 * l - q;
            h /= 360; // normalize h to [0,1] for calculations
            r = hue2rgb(p, q, h + 1 / 3);
            g = hue2rgb(p, q, h);
            b = hue2rgb(p, q, h - 1 / 3);
        }
        return { 
            r: Math.round(r * 255), 
            g: Math.round(g * 255), 
            b: Math.round(b * 255) 
        };
    }

    // Parameter Sanitization
    let pLevelsVal = Number(posterLevels);
    if (isNaN(pLevelsVal)) pLevelsVal = 5; 
    const finalPosterLevels = Math.max(2, Math.floor(pLevelsVal));

    let dAmplitudeVal = Number(distortionAmplitude);
    if (isNaN(dAmplitudeVal)) dAmplitudeVal = 10; 

    let dFrequencyVal = Number(distortionFrequency);
    if (isNaN(dFrequencyVal)) dFrequencyVal = 0.05; 
    
    let hShiftVal = Number(hueShift);
    if (isNaN(hShiftVal)) hShiftVal = 90; 
    const finalHueShiftNormalized = (hShiftVal % 360 + 360) % 360;


    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d', { willReadFrequently: true });

    const imgWidth = originalImg.naturalWidth || originalImg.width;
    const imgHeight = originalImg.naturalHeight || originalImg.height;

    canvas.width = imgWidth;
    canvas.height = imgHeight;
    
    if (imgWidth === 0 || imgHeight === 0) {
        console.error("Image has zero dimensions. Cannot process.");
        ctx.fillStyle = "gray";
        ctx.fillRect(0,0, canvas.width || 100, canvas.height || 30); // Draw something on small canvas
        ctx.fillStyle = "red";
        ctx.font = "12px Arial";
        ctx.textAlign = "center";
        const message = "Error: Image has zero dimensions.";
        if (canvas.width > 0 && canvas.height > 0){
            ctx.fillText(message, canvas.width / 2, canvas.height / 2);
        } // else nothing can be drawn usefully.
        return canvas;
    }

    try {
        ctx.drawImage(originalImg, 0, 0, imgWidth, imgHeight);
    } catch (e) {
        console.error("Error drawing original image: ", e);
        ctx.fillStyle = "red";
        ctx.font = "16px Arial";
        ctx.textAlign = "center";
        ctx.fillText("Error: Could not draw image.", canvas.width / 2, canvas.height / 2);
        return canvas;
    }
    
    let imageData;
    try {
        imageData = ctx.getImageData(0, 0, imgWidth, imgHeight);
    } catch (e) {
        console.error("Could not getImageData: ", e);
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        ctx.fillStyle = "red";
        ctx.font = "16px Arial";
        ctx.textAlign = "center";
        ctx.fillText("Error: Cross-origin issue or other problem reading image data.", canvas.width / 2, canvas.height / 2, canvas.width * 0.9);
        return canvas;
    }
    
    const data = imageData.data;
    const outputImageData = ctx.createImageData(imgWidth, imgHeight);
    const outputData = outputImageData.data;

    const posterFactor = 255 / (finalPosterLevels - 1);

    for (let y = 0; y < imgHeight; y++) {
        for (let x = 0; x < imgWidth; x++) {
            // 1. Calculate source coordinates for distortion
            let srcX = x + dAmplitudeVal * Math.sin(y * dFrequencyVal + x * dFrequencyVal * 0.1);
            let srcY = y + dAmplitudeVal * Math.cos(x * dFrequencyVal - y * dFrequencyVal * 0.1);

            // Clamp srcX and srcY to be within image bounds
            srcX = Math.max(0, Math.min(imgWidth - 1, srcX));
            srcY = Math.max(0, Math.min(imgHeight - 1, srcY));

            const iSrcX = Math.round(srcX);
            const iSrcY = Math.round(srcY);

            // 2. Get original pixel data from (iSrcX, iSrcY)
            const originalPixelIndex = (iSrcY * imgWidth + iSrcX) * 4;
            let r = data[originalPixelIndex];
            let g = data[originalPixelIndex + 1];
            let b = data[originalPixelIndex + 2];
            const a = data[originalPixelIndex + 3];

            // 3. Apply posterization
            r = Math.round(r / posterFactor) * posterFactor;
            g = Math.round(g / posterFactor) * posterFactor;
            b = Math.round(b / posterFactor) * posterFactor;
            
            // 4. Convert to HSL, shift hue, convert back to RGB
            let hsl = rgbToHsl(r, g, b);
            hsl.h = (hsl.h + finalHueShiftNormalized) % 360; 
            
            let rgbShifted = hslToRgb(hsl.h, hsl.s, hsl.l);
            r = rgbShifted.r;
            g = rgbShifted.g;
            b = rgbShifted.b;
            
            // 5. Set the pixel in the output ImageData
            const outputPixelIndex = (y * imgWidth + x) * 4;
            outputData[outputPixelIndex] = r;
            outputData[outputPixelIndex + 1] = g;
            outputData[outputPixelIndex + 2] = b;
            outputData[outputPixelIndex + 3] = a;
        }
    }

    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 Surrealist Filter Effect Tool allows users to apply a creative and artistic filter to their images, transforming them with surreal visual effects. By adjusting parameters such as posterization levels, distortion amplitude, distortion frequency, and hue shift, users can create unique and vibrant variations of their original images. This tool is ideal for artists, designers, and anyone looking to enhance their images for social media, presentations, or personal projects with a distinctive, dream-like quality.

Leave a Reply

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