Please bookmark this page to avoid losing your image tool!

Image Gradient Audio Vocoder Media Uploader

(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.
/**
 * Applies a color gradient to an image and generates an audio "sonification"
 * based on the original image's brightness, controlled by a play button.
 * The output is a self-contained HTML element with the processed image and audio player.
 *
 * @param {Image} originalImg The original JavaScript Image object.
 * @param {string} gradientColors A comma-separated string of CSS colors for the gradient (e.g., "red,yellow,#0000FF").
 * @param {string} scanDirection The direction to scan for sonification ('horizontal' or 'vertical').
 * @param {number} duration The duration of the generated audio in seconds.
 * @param {number} minFreq The minimum frequency of the audio in Hz.
 * @param {number} maxFreq The maximum frequency of the audio in Hz.
 * @returns {Promise<HTMLDivElement>} A promise that resolves to a DIV element containing the canvas and a play button.
 */
async function processImage(originalImg, gradientColors = 'black,white', scanDirection = 'horizontal', duration = 5, minFreq = 220, maxFreq = 1200) {

    // --- Helper Functions ---

    /**
     * Parses a CSS color string into an [R, G, B] array.
     * @param {string} colorStr - e.g., 'red', '#FF0000', 'rgb(255,0,0)'
     * @returns {number[]} - An array [r, g, b]
     */
    const parseColor = (colorStr) => {
        const ctx = document.createElement('canvas').getContext('2d');
        ctx.fillStyle = colorStr.trim();
        const hex = ctx.fillStyle; // Will be in #rrggbb format
        return [
            parseInt(hex.slice(1, 3), 16),
            parseInt(hex.slice(3, 5), 16),
            parseInt(hex.slice(5, 7), 16),
        ];
    };

    /**
     * Linearly interpolates between two numbers.
     * @param {number} a - Start value.
     * @param {number} b - End value.
     * @param {number} t - Interpolation factor (0-1).
     * @returns {number} The interpolated value.
     */
    const lerp = (a, b, t) => a * (1 - t) + b * t;

    // --- Main Setup ---

    // 1. Create a container for the canvas and button
    const container = document.createElement('div');
    container.style.position = 'relative';
    container.style.display = 'inline-block';
    container.style.lineHeight = '0'; // Removes extra space below canvas

    // 2. Setup canvas and draw the gradient-mapped image
    const canvas = document.createElement('canvas');
    canvas.width = originalImg.naturalWidth;
    canvas.height = originalImg.naturalHeight;
    const ctx = canvas.getContext('2d');
    ctx.drawImage(originalImg, 0, 0);

    // --- Gradient Mapping ---

    // 3. Create a 256-color gradient lookup table from the input string
    const colors = gradientColors.split(',').map(parseColor);
    const gradientMap = [];
    if (colors.length === 1) {
        for (let i = 0; i < 256; i++) gradientMap.push(colors[0]);
    } else {
        for (let i = 0; i < 256; i++) {
            const t = i / 255;
            const segment = (colors.length - 1) * t;
            const startIndex = Math.floor(segment);
            const endIndex = Math.min(startIndex + 1, colors.length - 1);
            const segmentT = segment - startIndex;

            const startColor = colors[startIndex];
            const endColor = colors[endIndex];

            const r = lerp(startColor[0], endColor[0], segmentT);
            const g = lerp(startColor[1], endColor[1], segmentT);
            const b = lerp(startColor[2], endColor[2], segmentT);
            gradientMap.push([r, g, b]);
        }
    }

    // 4. Apply the gradient map to the image on the canvas
    const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
    const data = imageData.data;
    for (let i = 0; i < data.length; i += 4) {
        const brightness = Math.floor((data[i] + data[i + 1] + data[i + 2]) / 3);
        const newColor = gradientMap[brightness];
        data[i] = newColor[0];
        data[i + 1] = newColor[1];
        data[i + 2] = newColor[2];
    }
    ctx.putImageData(imageData, 0, 0);
    container.appendChild(canvas);


    // --- Audio Generation & UI ---

    // 5. Create the play button
    const playButton = document.createElement('button');
    playButton.textContent = '▶ Play Sonification';
    Object.assign(playButton.style, {
        position: 'absolute',
        bottom: '10px',
        left: '50%',
        transform: 'translateX(-50%)',
        padding: '10px 20px',
        border: '1px solid white',
        backgroundColor: 'rgba(0, 0, 0, 0.6)',
        color: 'white',
        borderRadius: '5px',
        cursor: 'pointer',
        fontSize: '1em',
        fontFamily: 'sans-serif',
        textShadow: '1px 1px 2px black',
        backdropFilter: 'blur(2px)'
    });

    let audioContext = null;

    playButton.onclick = () => {
        // If audio is currently playing, stop it.
        if (audioContext && audioContext.state === 'running') {
            audioContext.close();
            audioContext = null;
            playButton.textContent = '▶ Play Sonification';
            return;
        }

        // Create a new AudioContext (must be done on user interaction)
        audioContext = new (window.AudioContext || window.webkitAudioContext)();
        const oscillator = audioContext.createOscillator();
        const gainNode = audioContext.createGain();
        oscillator.connect(gainNode);
        gainNode.connect(audioContext.destination);

        const now = audioContext.currentTime;

        // Sonify based on the *original* image's brightness, not the new gradient
        const originalCtx = document.createElement('canvas').getContext('2d');
        originalCtx.canvas.width = originalImg.width;
        originalCtx.canvas.height = originalImg.height;
        originalCtx.drawImage(originalImg, 0, 0);
        const originalData = originalCtx.getImageData(0, 0, originalImg.width, originalImg.height).data;

        const scanLength = (scanDirection === 'horizontal') ? originalImg.width : originalImg.height;
        const stepDuration = duration / scanLength;

        // Schedule frequency changes based on pixel brightness
        for (let i = 0; i < scanLength; i++) {
            let totalBrightness = 0;
            let pixelCount = 0;
            if (scanDirection === 'horizontal') {
                for (let y = 0; y < originalImg.height; y++) {
                    const idx = (y * originalImg.width + i) * 4;
                    totalBrightness += (originalData[idx] + originalData[idx + 1] + originalData[idx + 2]) / 3;
                    pixelCount++;
                }
            } else { // vertical
                for (let x = 0; x < originalImg.width; x++) {
                    const idx = (i * originalImg.width + x) * 4;
                    totalBrightness += (originalData[idx] + originalData[idx + 1] + originalData[idx + 2]) / 3;
                    pixelCount++;
                }
            }
            const avgBrightness = pixelCount > 0 ? totalBrightness / pixelCount : 0;
            const freq = lerp(minFreq, maxFreq, avgBrightness / 255);
            oscillator.frequency.setValueAtTime(freq, now + i * stepDuration);
        }

        // Add a small fade-in/fade-out to prevent clicks
        gainNode.gain.setValueAtTime(0, now);
        gainNode.gain.linearRampToValueAtTime(0.5, now + 0.1);
        gainNode.gain.setValueAtTime(0.5, now + duration - 0.1);
        gainNode.gain.linearRampToValueAtTime(0, now + duration);

        oscillator.start(now);
        oscillator.stop(now + duration);

        playButton.textContent = '■ Stop';

        oscillator.onended = () => {
             if (audioContext) {
                audioContext.close();
                audioContext = null;
            }
            playButton.textContent = '▶ Play Sonification';
        };
    };

    container.appendChild(playButton);

    // 6. Return the final element
    return container;
}

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 Gradient Audio Vocoder Media Uploader is a tool that combines visual and auditory elements by applying a color gradient to an uploaded image and generating an audio ‘sonification’ based on the image’s brightness. Users can customize the gradient colors, scanning direction, audio duration, and frequency range. This tool can be used for creative projects, educational purposes, or artistic expression, allowing users to experience images in a multifaceted way through both sight and sound.

Leave a Reply

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