Please bookmark this page to avoid losing your image tool!

Image Histogram Viewer

(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, // HTMLImageElement
    histWidthParam = 256, // number, width of histogram plot area
    histHeightParam = 100, // number, height of histogram plot area
    showRedParam = "true", // string "true" or "false"
    showGreenParam = "true", // string "true" or "false"
    showBlueParam = "true", // string "true" or "false"
    showGrayParam = "true", // string "true" or "false"
    colorRedParam = "rgba(255,0,0,0.7)", // string, color for red hist
    colorGreenParam = "rgba(0,180,0,0.7)", // string, color for green hist
    colorBlueParam = "rgba(0,0,255,0.7)", // string, color for blue hist
    colorGrayParam = "rgba(100,100,100,0.7)", // string, color for gray hist
    backgroundColorParam = "#f0f0f0", // string, canvas background
    textColorParam = "#333333", // string, label text color
    paddingParam = 10, // number, padding around elements
    showLabelsParam = "true", // string "true" or "false"
    labelFontSizeParam = 12 // number, font size for labels
) {
    // Parse and validate parameters
    const histWidth = Math.max(32, Number(histWidthParam) || 256); 
    const histHeight = Math.max(10, Number(histHeightParam) || 100);
    const padding = Math.max(0, Number(paddingParam) || 10);
    const labelFontSize = Math.max(6, Number(labelFontSizeParam) || 12);

    const _showRed = showRedParam.toLowerCase() === "true";
    const _showGreen = showGreenParam.toLowerCase() === "true";
    const _showBlue = showBlueParam.toLowerCase() === "true";
    const _showGray = showGrayParam.toLowerCase() === "true";
    const _showLabels = showLabelsParam.toLowerCase() === "true";
    
    // Helper function to create an error/message canvas
    const createMessageCanvas = (message) => {
        const canvas = document.createElement('canvas');
        const estimatedMessageWidth = message.length * labelFontSize * 0.6 + 2 * padding;
        canvas.width = Math.max(200, histWidth + 2 * padding, estimatedMessageWidth);
        canvas.height = Math.max(50, labelFontSize + 2 * padding);
        
        const ctx = canvas.getContext('2d');
        ctx.fillStyle = backgroundColorParam;
        ctx.fillRect(0, 0, canvas.width, canvas.height);
        ctx.fillStyle = textColorParam;
        ctx.font = `${labelFontSize}px sans-serif`;
        ctx.textAlign = 'center';
        ctx.textBaseline = 'middle';
        ctx.fillText(message, canvas.width / 2, canvas.height / 2);
        return canvas;
    };

    // 1. Get image data
    const imgWidth = originalImg.naturalWidth;
    const imgHeight = originalImg.naturalHeight;

    if (!originalImg.complete || imgWidth === 0 || imgHeight === 0) {
        return createMessageCanvas("Image not loaded or invalid dimensions");
    }

    const sourceCanvas = document.createElement('canvas');
    sourceCanvas.width = imgWidth;
    sourceCanvas.height = imgHeight;
    
    const sourceCtx = sourceCanvas.getContext('2d', { willReadFrequently: true });
    try {
        sourceCtx.drawImage(originalImg, 0, 0, imgWidth, imgHeight);
    } catch (e) {
        console.error("Error drawing image to source canvas:", e);
        return createMessageCanvas("Error drawing original image.");
    }
    
    let imageData;
    try {
        imageData = sourceCtx.getImageData(0, 0, imgWidth, imgHeight);
    } catch (e) {
        console.error("Error getting image data (getImageData):", e);
        return createMessageCanvas("Cannot process image (e.g., cross-origin restrictions)");
    }
    const data = imageData.data;

    // 2. Calculate histograms
    const rHist = new Array(256).fill(0);
    const gHist = new Array(256).fill(0);
    const bHist = new Array(256).fill(0);
    const grayHist = new Array(256).fill(0);

    for (let i = 0; i < data.length; i += 4) {
        const r = data[i];
        const g = data[i + 1];
        const b = data[i + 2];
        // Alpha data[i+3] is ignored

        rHist[r]++;
        gHist[g]++;
        bHist[b]++;
        
        const gray = Math.round(0.299 * r + 0.587 * g + 0.114 * b);
        grayHist[gray]++;
    }

    // 3. Prepare plot infos
    const plotInfos = []; 
    if (_showRed) plotInfos.push({ data: rHist, color: colorRedParam, name: "Red Channel" });
    if (_showGreen) plotInfos.push({ data: gHist, color: colorGreenParam, name: "Green Channel" });
    if (_showBlue) plotInfos.push({ data: bHist, color: colorBlueParam, name: "Blue Channel" });
    if (_showGray) plotInfos.push({ data: grayHist, color: colorGrayParam, name: "Grayscale" });

    // 4. Handle no plots selected
    if (plotInfos.length === 0) {
        return createMessageCanvas("No channels selected for histogram");
    }

    // 5. Calculate output canvas dimensions
    const outputCanvasWidth = histWidth + 2 * padding;
    let outputCanvasHeight = padding; // Initial top padding

    for (let i = 0; i < plotInfos.length; i++) {
        if (_showLabels) {
            outputCanvasHeight += labelFontSize + padding; // Space for label + padding below it
        }
        outputCanvasHeight += histHeight + padding; // Space for plot + padding below it
    }
    
    // 6. Create output canvas and draw
    const outputCanvas = document.createElement('canvas');
    outputCanvas.width = outputCanvasWidth;
    outputCanvas.height = outputCanvasHeight;
    const ctx = outputCanvas.getContext('2d');

    ctx.fillStyle = backgroundColorParam;
    ctx.fillRect(0, 0, outputCanvasWidth, outputCanvasHeight);

    let currentY = padding; 

    for (const plot of plotInfos) {
        if (_showLabels) {
            ctx.fillStyle = textColorParam;
            ctx.font = `${labelFontSize}px sans-serif`;
            ctx.textBaseline = 'top';
            ctx.fillText(plot.name, padding, currentY);
            currentY += labelFontSize + padding;
        }

        const histData = plot.data;
        let maxFreq = 0;
        for (let k = 0; k < 256; k++) {
            if (histData[k] > maxFreq) {
                maxFreq = histData[k];
            }
        }
        
        const barPlotX = padding;
        const barPlotY = currentY;
        const barWidthValue = histWidth / 256; 
        
        ctx.fillStyle = plot.color;

        if (maxFreq > 0) { 
            for (let k = 0; k < 256; k++) {
                const barHeight = (histData[k] / maxFreq) * histHeight;
                if (barHeight > 0) { 
                    ctx.fillRect(
                        barPlotX + k * barWidthValue,       
                        barPlotY + histHeight - barHeight, 
                        barWidthValue,                     
                        barHeight                      
                    );
                }
            }
        }
        currentY += histHeight + padding; 
    }
    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 Image Histogram Viewer is a tool that allows users to analyze the color distribution of images by generating histograms for the red, green, blue, and grayscale channels. Users can upload an image and customize the histogram display options, such as selecting which channels to show, setting the dimensions of the histogram, and applying color themes for better visualization. This tool is useful for photographers, graphic designers, and anyone interested in image processing and analysis, helping them understand the color composition and evaluate tonal ranges within their images.

Leave a Reply

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