Please bookmark this page to avoid losing your image tool!

Image YCbCr Color 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) {
    // Use naturalWidth/Height for intrinsic dimensions, fallback to width/height
    const width = originalImg.naturalWidth || originalImg.width;
    const height = originalImg.naturalHeight || originalImg.height;

    // 1. Create a temporary canvas to draw the original image and get its pixel data
    // This step is necessary to access the image's pixel data.
    const sourceCanvas = document.createElement('canvas');
    sourceCanvas.width = width;
    sourceCanvas.height = height;
    const sourceCtx = sourceCanvas.getContext('2d', { willReadFrequently: true }); // Hint for optimization
    sourceCtx.drawImage(originalImg, 0, 0, width, height);
    
    let imageData;
    try {
        imageData = sourceCtx.getImageData(0, 0, width, height);
    } catch (e) {
        // Handle potential security exceptions (e.g., tainted canvas from cross-origin image)
        console.error("Error getting image data:", e);
        const errorDiv = document.createElement('div');
        errorDiv.textContent = "Could not process image. This may be due to cross-origin restrictions if the image is not hosted on the same domain. Please try with a different image or ensure it's served with appropriate CORS headers.";
        errorDiv.style.color = 'red';
        errorDiv.style.padding = '10px';
        errorDiv.style.fontFamily = 'Arial, sans-serif';
        return errorDiv;
    }
    const data = imageData.data; // Uint8ClampedArray: [R,G,B,A, R,G,B,A, ...]

    // 2. Create canvases for displaying Y, Cb, and Cr components
    const yCanvas = document.createElement('canvas');
    yCanvas.width = width;
    yCanvas.height = height;
    const yCtx = yCanvas.getContext('2d');
    const yImageData = yCtx.createImageData(width, height);
    const yData = yImageData.data;

    const cbCanvas = document.createElement('canvas');
    cbCanvas.width = width;
    cbCanvas.height = height;
    const cbCtx = cbCanvas.getContext('2d');
    const cbImageData = cbCtx.createImageData(width, height);
    const cbData = cbImageData.data;

    const crCanvas = document.createElement('canvas');
    crCanvas.width = width;
    crCanvas.height = height;
    const crCtx = crCanvas.getContext('2d');
    const crImageData = crCtx.createImageData(width, height);
    const crData = crImageData.data;

    // 3. Process each pixel: convert RGB to YCbCr and prepare for display
    for (let i = 0; i < data.length; i += 4) {
        const r = data[i];
        const g = data[i + 1];
        const b = data[i + 2];
        const alpha = data[i + 3]; // Preserve original alpha

        // RGB to YCbCr conversion (using common ITU-R BT.601 / JPEG formulas for full-range 0-255)
        // Y': Luma component
        // Cb: Blue-difference chroma component (B-Y)
        // Cr: Red-difference chroma component (R-Y)
        const y_val =  0.299 * r + 0.587 * g + 0.114 * b;
        const cb_val = 128.0 - 0.168736 * r - 0.331264 * g + 0.500 * b;
        const cr_val = 128.0 + 0.500 * r - 0.418688 * g - 0.081312 * b;

        // Clamp results to [0, 255] range and round to the nearest integer
        const y_clamped = Math.max(0, Math.min(255, Math.round(y_val)));
        const cb_clamped = Math.max(0, Math.min(255, Math.round(cb_val))); // Neutral Cb is 128
        const cr_clamped = Math.max(0, Math.min(255, Math.round(cr_val))); // Neutral Cr is 128

        // Populate Y (Luma) channel data (displayed as grayscale)
        yData[i]     = y_clamped; // R value for grayscale
        yData[i + 1] = y_clamped; // G value for grayscale
        yData[i + 2] = y_clamped; // B value for grayscale
        yData[i + 3] = alpha;     // Alpha

        // Populate Cb (Blue-Yellow Chrominance) channel data (colorized display)
        // Cb=0   (max negative B-Y, more yellow) -> mapped to Yellow (255,255,0)
        // Cb=128 (neutral B-Y)                  -> mapped to Grayish (127,127,128)
        // Cb=255 (max positive B-Y, more blue)  -> mapped to Blue (0,0,255)
        cbData[i]     = (255 - cb_clamped); // R component for Cb visualization
        cbData[i + 1] = (255 - cb_clamped); // G component for Cb visualization
        cbData[i + 2] = cb_clamped;         // B component for Cb visualization
        cbData[i + 3] = alpha;              // Alpha
        
        // Populate Cr (Red-Cyan Chrominance) channel data (colorized display)
        // Cr=0   (max negative R-Y, more cyan)  -> mapped to Cyan (0,255,255)
        // Cr=128 (neutral R-Y)                 -> mapped to Grayish (128,127,127)
        // Cr=255 (max positive R-Y, more red)   -> mapped to Red (255,0,0)
        crData[i]     = cr_clamped;         // R component for Cr visualization
        crData[i + 1] = (255 - cr_clamped); // G component for Cr visualization
        crData[i + 2] = (255 - cr_clamped); // B component for Cr visualization
        crData[i + 3] = alpha;              // Alpha
    }

    // 4. Put the processed image data onto their respective canvases
    yCtx.putImageData(yImageData, 0, 0);
    cbCtx.putImageData(cbImageData, 0, 0);
    crCtx.putImageData(crImageData, 0, 0);

    // 5. Create a container element to hold the labeled canvases for display
    const mainContainer = document.createElement('div');
    mainContainer.style.display = 'flex';
    mainContainer.style.flexDirection = 'column'; // Stack Y, Cb, Cr component views vertically
    mainContainer.style.gap = '15px';             // Space between each component view
    mainContainer.style.padding = '10px';           // Padding around the main container
    mainContainer.style.fontFamily = 'Arial, sans-serif'; // Set a common font
    mainContainer.style.textAlign = 'center';     // Center-align text (like labels)

    // Helper function to create a styled container for a canvas and its label
    function createComponentView(canvas, labelText) {
        const viewDiv = document.createElement('div');
        // Optional styling for individual component view containers:
        // viewDiv.style.border = '1px solid #f0f0f0';
        // viewDiv.style.padding = '10px';
        // viewDiv.style.borderRadius = '4px';
        // viewDiv.style.backgroundColor = '#f9f9f9';

        const label = document.createElement('p');
        label.textContent = labelText;
        label.style.margin = '0 0 8px 0'; // Margin below the label, above the canvas
        label.style.fontWeight = 'bold';
        label.style.fontSize = '1em';

        // Style the canvas for responsiveness and proper display
        canvas.style.maxWidth = '100%';    // Ensure canvas scales down if container is narrower
        canvas.style.height = 'auto';      // Maintain aspect ratio when scaling
        canvas.style.display = 'block';    // Remove an_valy default inline element spacing (e.g., bottom margin)
        canvas.style.margin = '0 auto';    // Center canvas if its max-width makes it smaller than viewDiv
        canvas.style.border = '1px solid #ccc'; // Add a light border around the canvas itself

        viewDiv.appendChild(label);
        viewDiv.appendChild(canvas);
        return viewDiv;
    }
    
    // Add the Y, Cb, and Cr component views to the main container
    mainContainer.appendChild(createComponentView(yCanvas, 'Y (Luma Component)'));
    mainContainer.appendChild(createComponentView(cbCanvas, 'Cb (Blue-Yellow Chrominance Component)'));
    mainContainer.appendChild(createComponentView(crCanvas, 'Cr (Red-Cyan Chrominance Component)'));

    return mainContainer; // Return the single DOM element containing all views
}

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 YCbCr Color Viewer is a web tool that allows users to visualize the YCbCr color space representation of images. It takes an input image and processes it to display three distinct components: the Y (Luma) component, which represents brightness; the Cb (Blue-Yellow Chrominance) component, which illustrates the blue-yellow color information; and the Cr (Red-Cyan Chrominance) component, which shows the red-cyan color information. This tool is particularly useful for graphic designers, image processing professionals, and educators who wish to understand how images are represented in the YCbCr color space, which is commonly used in video compression and digital imaging. Users can upload their images to see how color information is distributed and analyze this from a color theory perspective.

Leave a Reply

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