Please bookmark this page to avoid losing your image tool!

Image HSL Color Display 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, maxColors = 256, sampleStep = 1) {
    // Helper function for RGB to HSL conversion
    function _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, s, 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: Math.round(h * 360),
            s: Math.round(s * 100),
            l: Math.round(l * 100)
        };
    }

    // Sanitize parameters
    maxColors = Math.max(1, Math.floor(maxColors));
    sampleStep = Math.max(1, Math.floor(sampleStep));

    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');

    if (!ctx) {
        const errorDiv = document.createElement('div');
        errorDiv.textContent = 'Error: Canvas 2D context is not supported in this environment.';
        errorDiv.style.color = 'red';
        errorDiv.style.padding = '10px';
        errorDiv.style.border = '1px solid red';
        errorDiv.style.backgroundColor = '#ffe0e0';
        return errorDiv;
    }
    
    // Use naturalWidth/Height for intrinsic dimensions, fallback to width/height
    const imgWidth = originalImg.naturalWidth || originalImg.width;
    const imgHeight = originalImg.naturalHeight || originalImg.height;

    if (!imgWidth || !imgHeight) {
        const errorDiv = document.createElement('div');
        errorDiv.textContent = 'Error: Image has zero dimensions. It might not be loaded yet, or the image source is invalid.';
        errorDiv.style.color = 'red'; 
        errorDiv.style.padding = '10px';
        errorDiv.style.border = '1px solid red';
        errorDiv.style.backgroundColor = '#ffe0e0';
        return errorDiv;
    }

    canvas.width = imgWidth;
    canvas.height = imgHeight;

    try {
        ctx.drawImage(originalImg, 0, 0, imgWidth, imgHeight);
    } catch (e) {
        const errorDiv = document.createElement('div');
        errorDiv.textContent = 'Error: Could not draw image on canvas. Ensure the image is valid and accessible. Check console for details.';
        errorDiv.style.color = 'red';
        errorDiv.style.padding = '10px';
        errorDiv.style.border = '1px solid red';
        errorDiv.style.backgroundColor = '#ffe0e0';
        console.error("Error drawing image on canvas:", e);
        return errorDiv;
    }
    
    const uniqueHslColors = new Set();
    let imageData;
    try {
        imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
    } catch (e) {
        const errorDiv = document.createElement('div');
        errorDiv.textContent = 'Error: Could not get image data. This often happens with cross-origin images if the server does not provide appropriate CORS headers. Check console for details.';
        errorDiv.style.color = 'red';
        errorDiv.style.padding = '10px';
        errorDiv.style.border = '1px solid red';
        errorDiv.style.backgroundColor = '#ffe0e0';
        console.error("Error getting ImageData from canvas:", e);
        return errorDiv;
    }
    
    const data = imageData.data;

    pixelLoop: // Label to break out of nested loops
    for (let y = 0; y < canvas.height; y += sampleStep) {
        for (let x = 0; x < canvas.width; x += sampleStep) {
            if (uniqueHslColors.size >= maxColors) {
                break pixelLoop;
            }
            const index = (y * canvas.width + x) * 4; // Each pixel is 4 bytes (R,G,B,A)
            const r = data[index];
            const g = data[index + 1];
            const b = data[index + 2];
            // const a = data[index + 3]; // Alpha channel, not directly used in HSL color itself

            const hsl = _rgbToHsl(r, g, b);
            const hslString = `hsl(${hsl.h}, ${hsl.s}%, ${hsl.l}%)`;
            uniqueHslColors.add(hslString);
        }
    }

    // Create the main container for displaying color swatches
    const container = document.createElement('div');
    container.style.display = 'flex';
    container.style.flexWrap = 'wrap';
    container.style.gap = '10px';
    container.style.fontFamily = 'Arial, Helvetica, sans-serif';
    container.style.padding = '10px';
    container.style.border = '1px solid #dadce0'; // A light grey border
    container.style.borderRadius = '8px';
    container.style.maxHeight = '400px'; // Limit height and allow scrolling
    container.style.overflowY = 'auto'; 
    container.style.backgroundColor = '#f8f9fa'; // Light background for the container

    if (uniqueHslColors.size === 0) {
        container.textContent = 'No distinct HSL colors were found with the current settings. ';
        if (imgWidth < sampleStep || imgHeight < sampleStep) {
             container.textContent += `The image dimensions (${imgWidth}x${imgHeight}) may be smaller than the sampleStep (${sampleStep}), preventing pixel sampling. Try reducing the sampleStep value.`;
        } else {
             container.textContent += `The image might be monochrome, or the parameters (maxColors: ${maxColors}, sampleStep: ${sampleStep}) are too restrictive.`;
        }
        container.style.textAlign = 'center';
        container.style.color = '#5f6368'; // A muted text color for info
        return container;
    }
    
    // Sort colors: by Hue, then Saturation, then Lightness for a structured display
    const sortedHslColors = Array.from(uniqueHslColors).sort((hslStrA, hslStrB) => {
        const parseHsl = (str) => {
            const parts = str.substring(4, str.length - 1).split(',');
            return {
                h: parseInt(parts[0].trim(), 10),
                s: parseInt(parts[1].replace('%', '').trim(), 10),
                l: parseInt(parts[2].replace('%', '').trim(), 10)
            };
        };
        const a = parseHsl(hslStrA);
        const b = parseHsl(hslStrB);

        if (a.h !== b.h) return a.h - b.h; // Sort by Hue
        if (a.s !== b.s) return a.s - b.s; // Then by Saturation
        return a.l - b.l;                  // Finally by Lightness
    });

    sortedHslColors.forEach(hslString => {
        const swatchContainer = document.createElement('div');
        swatchContainer.style.display = 'flex';
        swatchContainer.style.flexDirection = 'column';
        swatchContainer.style.alignItems = 'center';
        swatchContainer.style.border = '1px solid #dfe1e5'; // Slightly darker border for each swatch box
        swatchContainer.style.padding = '8px';
        swatchContainer.style.borderRadius = '4px';
        swatchContainer.style.backgroundColor = '#ffffff'; // White background for each swatch box
        swatchContainer.style.minWidth = '120px'; // Ensure enough space for HSL string
        swatchContainer.style.boxShadow = '0 1px 2px rgba(0,0,0,0.05)';

        const swatch = document.createElement('div');
        swatch.style.width = '50px';
        swatch.style.height = '50px';
        swatch.style.backgroundColor = hslString;
        swatch.style.border = '1px solid #ced4da'; // Border for the color square itself
        swatch.style.borderRadius = '3px';
        swatch.style.marginBottom = '8px';
        swatch.setAttribute('title', `Color: ${hslString}`); // Tooltip on hover

        const label = document.createElement('span');
        label.style.fontSize = '12px';
        label.style.color = '#3c4043'; // Dark grey for text, good contrast
        label.textContent = hslString;
        
        swatchContainer.appendChild(swatch);
        swatchContainer.appendChild(label);
        container.appendChild(swatchContainer);
    });

    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 HSL Color Display Tool is designed to analyze an image and extract its distinct colors represented in the HSL (Hue, Saturation, Lightness) color model. This tool allows users to specify the maximum number of colors to display and the sampling step for analyzing pixel data. Ideal for artists, designers, and developers, this tool is useful for quickly identifying color palettes from images, aiding in color selection for design projects or creating color schemes for websites and applications.

Leave a Reply

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