Please bookmark this page to avoid losing your image tool!

Photo Music Soundtrack Finder

(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) {
    /**
     * Finds a music soundtrack genre based on the photo's average color mood.
     * This is an artistic interpretation and not a scientifically accurate process.
     * It works by analyzing the average Hue, Saturation, and Lightness of the image.
     */

    // Helper function to convert an RGB color value to HSL.
    // Handles R, G, and B values from 0 to 255 and returns h, s, and l in the range [0, 1].
    const rgbToHsl = (r, g, b) => {
        r /= 255;
        g /= 255;
        b /= 255;
        const max = Math.max(r, g, b);
        const min = Math.min(r, g, b);
        let h = 0, s = 0, l = (max + min) / 2;

        if (max !== min) {
            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, s, l];
    };

    // Create the final output canvas which will be returned.
    const outputCanvas = document.createElement('canvas');
    const ctx = outputCanvas.getContext('2d');

    const infoHeight = 80;
    // Ensure the canvas is wide enough for the text, but not smaller than the image.
    const canvasWidth = Math.max(originalImg.width, 400);
    const canvasHeight = originalImg.height + infoHeight;

    outputCanvas.width = canvasWidth;
    outputCanvas.height = canvasHeight;

    // A function to draw the final result on the canvas.
    const drawResult = (soundtrack, isError = false) => {
        // Draw the original image. A white background is drawn first for transparent images.
        ctx.fillStyle = '#FFFFFF';
        ctx.fillRect(0, 0, canvasWidth, originalImg.height);
        ctx.drawImage(originalImg, 0, 0);
        
        // Draw the bottom info panel background.
        ctx.fillStyle = isError ? '#8B0000' : '#181818'; // Dark red for errors
        ctx.fillRect(0, originalImg.height, canvasWidth, infoHeight);

        // If it's an error, just display the message and stop.
        if (isError) {
            ctx.fillStyle = '#FFFFFF';
            ctx.font = 'bold 16px "Segoe UI", Roboto, Arial, sans-serif';
            ctx.textAlign = 'center';
            ctx.textBaseline = 'middle';
            ctx.fillText(soundtrack, canvasWidth / 2, originalImg.height + infoHeight / 2);
            return;
        }

        // Draw a divider line.
        ctx.fillStyle = '#444444';
        ctx.fillRect(0, originalImg.height, canvasWidth, 2);

        // Draw a music icon.
        ctx.fillStyle = '#FFFFFF';
        ctx.font = '30px Arial';
        ctx.textBaseline = 'middle';
        ctx.fillText('🎵', 25, originalImg.height + infoHeight / 2);

        // Draw the text labels.
        const textX = 75;
        ctx.fillStyle = '#CCCCCC';
        ctx.font = '16px "Segoe UI", Roboto, Arial, sans-serif';
        ctx.fillText('Suggested Soundtrack:', textX, originalImg.height + 30);

        ctx.fillStyle = '#FFFFFF';
        ctx.font = 'bold 22px "Segoe UI", Roboto, Arial, sans-serif';
        ctx.fillText(soundtrack, textX, originalImg.height + 58);
    };

    // Use a temporary, small canvas for faster image analysis.
    const analysisCanvas = document.createElement('canvas');
    const analysisCtx = analysisCanvas.getContext('2d', { willReadFrequently: true });

    const MAX_ANALYSIS_DIMENSION = 100;
    let analysisWidth = originalImg.width;
    let analysisHeight = originalImg.height;

    if (analysisWidth > MAX_ANALYSIS_DIMENSION || analysisHeight > MAX_ANALYSIS_DIMENSION) {
        if (analysisWidth > analysisHeight) {
            analysisHeight = Math.round((MAX_ANALYSIS_DIMENSION / analysisWidth) * analysisHeight);
            analysisWidth = MAX_ANALYSIS_DIMENSION;
        } else {
            analysisWidth = Math.round((MAX_ANALYSIS_DIMENSION / analysisHeight) * analysisWidth);
            analysisHeight = MAX_ANALYSIS_DIMENSION;
        }
    }
    analysisCanvas.width = analysisWidth;
    analysisCanvas.height = analysisHeight;
    analysisCtx.drawImage(originalImg, 0, 0, analysisWidth, analysisHeight);

    // Get pixel data from the temporary canvas.
    let imageData;
    try {
        imageData = analysisCtx.getImageData(0, 0, analysisWidth, analysisHeight);
    } catch (e) {
        // This error often happens with cross-origin images without CORS headers.
        console.error("Image analysis failed:", e);
        drawResult("Error: Cannot analyze cross-origin image.", true);
        return outputCanvas;
    }

    const data = imageData.data;
    let totalH = 0, totalS = 0, totalL = 0;
    const pixelCount = data.length / 4;

    for (let i = 0; i < data.length; i += 4) {
        const [h, s, l] = rgbToHsl(data[i], data[i + 1], data[i + 2]);
        totalH += h;
        totalS += s;
        totalL += l;
    }

    const avgH = totalH / pixelCount; // Average Hue (0-1)
    const avgS = totalS / pixelCount; // Average Saturation (0-1)
    const avgL = totalL / pixelCount; // Average Lightness (0-1)

    // A simplified logic to map color properties to music genres.
    let soundtrack = "Ambient Chill"; // A safe default

    if (avgS < 0.15) { // Low saturation (grayscale-like images)
        soundtrack = avgL < 0.4 ? "Somber Classical Piano" : "Nostalgic Film Score";
    } else { // Colored images
        const hueDegrees = avgH * 360;

        if (avgL < 0.4) { // Dark images
            soundtrack = (hueDegrees > 180 && hueDegrees < 280) ? "Dark Synthwave" : "Lofi Hip Hop / Chillhop";
        } else if (avgL > 0.65) { // Bright images
            soundtrack = (hueDegrees > 45 && hueDegrees < 150) ? "Happy Acoustic Folk" : "Upbeat Summer Pop";
        } else { // Mid-lightness images with distinct colors
            if (hueDegrees >= 0 && hueDegrees < 60) { // Reds/Oranges
                soundtrack = "Energetic Indie Rock";
            } else if (hueDegrees >= 60 && hueDegrees < 160) { // Yellows/Greens
                soundtrack = "Peaceful Nature Ambience";
            } else if (hueDegrees >= 160 && hueDegrees < 260) { // Blues
                soundtrack = "Relaxing Deep House";
            } else { // Purples/Pinks
                soundtrack = "Dreamy Indie Pop";
            }
        }
    }

    drawResult(soundtrack);
    return outputCanvas;
}

Free Image Tool Creator

Can't find the image tool you're looking for?
Create one based on your own needs now!

Description

The Photo Music Soundtrack Finder is a creative tool that analyzes the average color mood of a photo to suggest a fitting music soundtrack genre. Utilizing concepts from color theory, it interprets the image’s Hue, Saturation, and Lightness and recommends a soundtrack that complements the visual aesthetic. This tool can be particularly useful for content creators, marketers, or anyone looking to enhance their visual projects with a matching audio backdrop, set the mood for presentations, or simply discover musical genres that resonate with their imagery.

Leave a Reply

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