Please bookmark this page to avoid losing your image tool!

Image Silhouette Filter

(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, silhouetteColor = "black", alphaThresholdInput = 0) {
    // Ensure alphaThreshold is a valid number between 0 and 255
    let alphaThreshold = Number(alphaThresholdInput);
    // Check if 'alphaThreshold' became NaN (e.g. from Number("text_value")) or if input was non-finite
    if (isNaN(alphaThreshold) || !isFinite(alphaThreshold)) {
        alphaThreshold = 0; // Default to 0 if an invalid value was provided
    }
    // Clamp the threshold to the valid 0-255 range and ensure it's an integer
    alphaThreshold = Math.max(0, Math.min(255, Math.floor(alphaThreshold)));

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

    // Use naturalWidth/Height for the intrinsic dimensions of the image
    const imgWidth = originalImg.naturalWidth;
    const imgHeight = originalImg.naturalHeight;

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

    // Handle cases where image dimensions are invalid (e.g., image not loaded or is 0x0)
    if (imgWidth === 0 || imgHeight === 0) {
        // Make canvas somewhat visible and show an error message if it was 0x0
        canvas.width = canvas.width === 0 ? 200 : canvas.width; 
        canvas.height = canvas.height === 0 ? 50 : canvas.height;
        
        ctx.font = "14px Arial";
        ctx.textAlign = "center";
        ctx.textBaseline = "middle";
        ctx.fillStyle = "red"; // Error text color
        ctx.fillText("Invalid image or not loaded.", canvas.width / 2, canvas.height / 2, canvas.width * 0.9);
        return canvas;
    }
    
    // Draw the original image onto the canvas. This is required to access its pixel data.
    ctx.drawImage(originalImg, 0, 0, imgWidth, imgHeight);

    let imageData;
    try {
        imageData = ctx.getImageData(0, 0, imgWidth, imgHeight);
    } catch (e) {
        // This error can occur if the image is cross-origin ("tainted" canvas)
        // or other rarer issues with getImageData.
        console.error("Error an processImage getting ImageData:", e);
        
        // Clear the canvas (it might have the original image drawn) and show an error message.
        ctx.clearRect(0, 0, imgWidth, imgHeight); 
        
        let msg = "Error: Could not process image pixels.";
        if (e.name === 'SecurityError') {
            msg = "Error: Cross-origin image. Cannot access pixels.";
        }
        
        // Adjust font size for the error message to fit the canvas
        let fontSize = 16;
        if (imgWidth < 300 || imgHeight < 100) { 
            fontSize = 12;
        }
        if (imgWidth < 150 || imgHeight < 50) {
             fontSize = Math.max(8, Math.floor(Math.min(imgWidth, imgHeight) / 10)); 
        }

        ctx.font = `${fontSize}px Arial`;
        ctx.textAlign = "center";
        ctx.textBaseline = "middle";
        ctx.fillStyle = "red";
        ctx.fillText(msg, imgWidth / 2, imgHeight / 2, imgWidth * 0.95); // Use most of the canvas width for the text
        return canvas;
    }
    
    const data = imageData.data; // This is a Uint8ClampedArray containing pixel data (R,G,B,A, R,G,B,A, ...)

    // Determine the RGB components of the silhouette color.
    // A temporary 1x1 canvas is used to parse the `silhouetteColor` string (e.g., "red", "#FF0000", "rgb(255,0,0)")
    // into its R, G, B components. This is a robust way to handle various CSS color formats.
    const tempCanvas = document.createElement('canvas');
    tempCanvas.width = 1;
    tempCanvas.height = 1;
    const tempCtx = tempCanvas.getContext('2d', { 
        // Hint for optimization for contexts that are read from frequently.
        // For a single 1x1 pixel read, its impact is minimal but doesn't hurt.
        willReadFrequently: true 
    }); 
    tempCtx.fillStyle = silhouetteColor; // Apply the user-specified color string
    tempCtx.fillRect(0, 0, 1, 1); // Draw a 1x1 rectangle filled with this color
    const colorData = tempCtx.getImageData(0, 0, 1, 1).data; // Read the RGBA value of that pixel
    const rSilhouette = colorData[0];
    const gSilhouette = colorData[1];
    const bSilhouette = colorData[2];
    // Note: The alpha component of the silhouetteColor (colorData[3]) is intentionally ignored.
    // Silhouettes are typically rendered as fully opaque.

    // Iterate over each pixel in the image data. Each pixel consists of 4 bytes (R, G, B, A).
    for (let i = 0; i < data.length; i += 4) {
        const alpha = data[i + 3]; // Get the alpha value of the current pixel from the original image

        // If the original pixel's alpha value is greater than the specified threshold,
        // it's considered part of the "shape" and should be colored with the silhouette color.
        if (alpha > alphaThreshold) {
            data[i] = rSilhouette;     // Set Red component to silhouette color's Red
            data[i + 1] = gSilhouette; // Set Green component to silhouette color's Green
            data[i + 2] = bSilhouette; // Set Blue component to silhouette color's Blue
            data[i + 3] = 255;         // Set Alpha to fully opaque (255) for the silhouette
        } else {
            // If the pixel's alpha is not above the threshold, it's considered "background"
            // or transparent enough, so make this pixel fully transparent.
            data[i + 3] = 0; // Set Alpha to 0 (fully transparent)
        }
    }

    // Put the modified image data back onto the canvas
    ctx.putImageData(imageData, 0, 0);

    return canvas;
}

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 Silhouette Filter is a tool that allows users to convert images into stylized silhouettes. By applying a specified silhouette color and an alpha transparency threshold, users can transform images in a way that highlights their shapes while removing background details. This functionality can be useful for creating artistic representations, designing graphics, or generating icons and logos that require a simplified and clear outline of forms.

Leave a Reply

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