Please bookmark this page to avoid losing your image tool!

Image Audio Spectrum 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, amplitudeStr = "0.5", frequencyCountStr = "32", effectColorStr = "255,0,0", direction = "horizontal", effectType = "tint", smoothnessStr = "0.2") {

    // Helper: Clamp number
    function clamp(value, min, max) {
        return Math.min(max, Math.max(min, value));
    }

    // Helper: Lerp (Linear Interpolation)
    function lerp(a, b, t) {
        return a * (1 - t) + b * t;
    }

    // Helper: Parse color string (e.g., "#RRGGBB", "rgb(r,g,b)", "r,g,b")
    function parseColor(colorStr) {
        const defaultErrorColor = { r: 255, g: 0, b: 0 }; // Default to red on error

        if (typeof colorStr !== 'string') {
            return defaultErrorColor;
        }

        let str = colorStr.replace(/\s+/g, '').toLowerCase();
        let r, g, b;

        if (str.startsWith('#')) {
            if (str.length === 4) { // #RGB format
                r = parseInt(str[1] + str[1], 16);
                g = parseInt(str[2] + str[2], 16);
                b = parseInt(str[3] + str[3], 16);
            } else if (str.length === 7) { // #RRGGBB format
                r = parseInt(str.substring(1, 3), 16);
                g = parseInt(str.substring(3, 5), 16);
                b = parseInt(str.substring(5, 7), 16);
            } else {
                return defaultErrorColor; // Invalid hex format
            }
        } else if (str.startsWith('rgb(') && str.endsWith(')')) {
            const parts = str.substring(4, str.length - 1).split(',');
            if (parts.length === 3) {
                r = parseInt(parts[0], 10);
                g = parseInt(parts[1], 10);
                b = parseInt(parts[2], 10);
            } else {
                return defaultErrorColor; // Invalid rgb() format
            }
        } else if (str.includes(',')) {
            const parts = str.split(',');
            if (parts.length === 3) {
                r = parseInt(parts[0], 10);
                g = parseInt(parts[1], 10);
                b = parseInt(parts[2], 10);
            } else {
                return defaultErrorColor; // Invalid r,g,b format
            }
        } else {
            return defaultErrorColor; // Unsupported format
        }

        if (isNaN(r) || isNaN(g) || isNaN(b) || r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255) {
            return defaultErrorColor; // Invalid color component values
        }
        return { r, g, b };
    }

    // 1. Parse and validate parameters
    let amplitude = parseFloat(amplitudeStr);
    if (isNaN(amplitude)) amplitude = 0.5;

    let frequencyCount = parseInt(frequencyCountStr, 10);
    if (isNaN(frequencyCount) || frequencyCount <= 0) {
        frequencyCount = 32;
    }
    frequencyCount = Math.min(frequencyCount, 1024); // Cap frequency count for performance

    const parsedColor = parseColor(effectColorStr);

    if (direction !== 'horizontal' && direction !== 'vertical') {
        direction = 'horizontal'; // Default direction
    }

    if (!['brightness', 'tint', 'color_filter'].includes(effectType)) {
        effectType = 'tint'; // Default effect type
    }
    
    let smoothness = parseFloat(smoothnessStr);
    if (isNaN(smoothness)) smoothness = 0.2;
    smoothness = clamp(smoothness, 0, 1);


    // 2. Canvas setup
    const canvas = document.createElement('canvas');
    const iw = originalImg.naturalWidth || originalImg.width;
    const ih = originalImg.naturalHeight || originalImg.height;

    if (!iw || !ih || iw === 0 || ih === 0) {
        console.warn("Image has invalid dimensions or is not loaded. Returning a 1x1 canvas.");
        canvas.width = 1;
        canvas.height = 1;
        const ctxFallback = canvas.getContext('2d');
        if (ctxFallback) {
             ctxFallback.fillStyle = 'gray';
             ctxFallback.fillRect(0,0,1,1);
        }
        return canvas;
    }

    canvas.width = iw;
    canvas.height = ih;
    const ctx = canvas.getContext('2d');
    if (!ctx) { // Should not happen in modern browsers
        console.error("Could not get 2D context from canvas.");
        return canvas; // Return empty canvas
    }
    ctx.drawImage(originalImg, 0, 0, iw, ih);
    
    let imageData;
    try {
        imageData = ctx.getImageData(0, 0, iw, ih);
    } catch (e) {
        // This can happen due to tainted canvas (e.g. cross-origin image without CORS)
        console.error("Could not get image data (possibly tainted canvas):", e);
        // Draw a simple message on the canvas indicating the error
        ctx.fillStyle = "rgba(0,0,0,0.7)";
        ctx.fillRect(0,0,iw,ih);
        ctx.fillStyle = "white";
        ctx.font = "16px Arial";
        ctx.textAlign = "center";
        ctx.fillText("Error: Could not process image (security/CORS issue).", iw/2, ih/2);
        return canvas;
    }
    const data = imageData.data;

    // 3. Generate raw spectrum values (0-1)
    const rawSpectrumValues = [];
    if (frequencyCount > 0) {
        for (let i = 0; i < frequencyCount; i++) {
            rawSpectrumValues.push(Math.random());
        }
    } else { // Should have been caught by validation, but as a safe guard
        return canvas; // No effect if no frequencies
    }


    // 4. Smooth spectrum values
    let spectrumValues = [...rawSpectrumValues];
    if (smoothness > 0 && frequencyCount > 1) {
        const smoothed = [];
        // Window size for smoothing, at least 1
        const windowSize = Math.max(1, Math.floor(frequencyCount * smoothness));
        const halfWindow = Math.floor(windowSize / 2);

        for (let i = 0; i < frequencyCount; i++) {
            let sum = 0;
            let numInWindow = 0;
            for (let j = 0; j < windowSize; j++) {
                let idx = i + j - halfWindow;
                // Apply effect at edges by clamping index
                idx = clamp(idx, 0, frequencyCount - 1); 
                sum += rawSpectrumValues[idx];
                numInWindow++;
            }
            smoothed[i] = (numInWindow > 0) ? sum / numInWindow : rawSpectrumValues[i];
        }
        spectrumValues = smoothed;
    }

    // 5. Loop through pixels and apply effect
    const len = data.length;
    const w = canvas.width;
    const h = canvas.height;

    for (let i = 0; i < len; i += 4) {
        const rOrig = data[i];
        const gOrig = data[i+1];
        const bOrig = data[i+2];

        const x = (i / 4) % w;
        const y = Math.floor((i / 4) / w);

        let bandIndex;
        if (direction === 'horizontal') { // Spectrum varies along X, bars are vertical
            bandIndex = Math.floor((x / w) * frequencyCount);
        } else { // direction === 'vertical', Spectrum varies along Y, bars are horizontal
            bandIndex = Math.floor((y / h) * frequencyCount);
        }
        bandIndex = clamp(bandIndex, 0, frequencyCount - 1);

        const currentSpectrumValue = spectrumValues[bandIndex]; // Should always be valid (0-1)

        let newR = rOrig, newG = gOrig, newB = bOrig;

        if (effectType === 'brightness') {
            // factor ranges from (1 - amplitude) to (1 + amplitude) if spectrumValue is 0 to 1
            const factor = 1 + (currentSpectrumValue - 0.5) * 2 * amplitude;
            newR = rOrig * factor;
            newG = gOrig * factor;
            newB = bOrig * factor;
        } else if (effectType === 'tint') {
            // mix ranges 0 to 1, controlled by spectrum value and amplitude
            const mix = clamp(currentSpectrumValue * amplitude, 0, 1);
            newR = lerp(rOrig, parsedColor.r, mix);
            newG = lerp(gOrig, parsedColor.g, mix);
            newB = lerp(bOrig, parsedColor.b, mix);
        } else if (effectType === 'color_filter') {
            // t ranges 0 to 1, determines how much of parsedColor (normalized) to multiply by
            const t = clamp(currentSpectrumValue * amplitude, 0, 1);
            newR = rOrig * lerp(1, parsedColor.r / 255, t);
            newG = gOrig * lerp(1, parsedColor.g / 255, t);
            newB = bOrig * lerp(1, parsedColor.b / 255, t);
        }

        data[i]   = clamp(newR, 0, 255);
        data[i+1] = clamp(newG, 0, 255);
        data[i+2] = clamp(newB, 0, 255);
        // data[i+3] (alpha) remains unchanged
    }

    // 6. Put image data back and return 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 Audio Spectrum Filter Effect Tool allows users to apply striking visual effects to images by simulating audio spectrum visuals. Users can adjust various parameters such as amplitude, frequency count, effect color, direction of the effect, effect type (brightness, tint, or color filter), and smoothness to customize the appearance of the image. This tool can be particularly useful for artists, musicians, and content creators looking to enhance their visuals, create unique backgrounds, or develop engaging designs that can accompany audio elements in videos and presentations.

Leave a Reply

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