Please bookmark this page to avoid losing your image tool!

Image Edge Highlighting Line Drawer

(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, lineColor = "red", threshold = 100) {
    const width = originalImg.width;
    const height = originalImg.height;

    // Handle cases where image is too small for the 3x3 Sobel kernel.
    // In such cases, return a canvas with the original image drawn on it.
    if (width < 3 || height < 3) {
        const fallbackCanvas = document.createElement('canvas');
        fallbackCanvas.width = width;
        fallbackCanvas.height = height;
        const fallbackCtx = fallbackCanvas.getContext('2d');
        if (fallbackCtx) {
            fallbackCtx.drawImage(originalImg, 0, 0);
        }
        console.warn("Image is too small for edge detection (minimum 3x3 required). Returning original image.");
        return fallbackCanvas;
    }

    // Create a temporary canvas to get original image pixel data.
    // The { willReadFrequently: true } hint can improve performance for getImageData.
    const tempCanvas = document.createElement('canvas');
    tempCanvas.width = width;
    tempCanvas.height = height;
    const tempCtx = tempCanvas.getContext('2d', { willReadFrequently: true });
    
    if (!tempCtx) {
        console.error("Failed to get 2D context for temporary canvas.");
        // Return a blank canvas or a canvas with the original image as a fallback
        const errCanvas = document.createElement('canvas');
        errCanvas.width = width; errCanvas.height = height;
        const errCtx = errCanvas.getContext('2d');
        if (errCtx) errCtx.drawImage(originalImg, 0, 0);
        return errCanvas;
    }
    tempCtx.drawImage(originalImg, 0, 0);
    
    let imageData;
    try {
        imageData = tempCtx.getImageData(0, 0, width, height);
    } catch (e) {
        // This error can occur if the canvas is tainted (e.g., cross-origin image without CORS).
        console.error("Error getting ImageData (possibly due to tainted canvas from cross-origin image):", e);
        const fallbackCanvas = document.createElement('canvas');
        fallbackCanvas.width = width;
        fallbackCanvas.height = height;
        const fallbackCtx = fallbackCanvas.getContext('2d');
        if (fallbackCtx) {
            fallbackCtx.drawImage(originalImg, 0, 0); // Draw original image and return
        }
        return fallbackCanvas;
    }
    const data = imageData.data;

    // Create the output canvas where the result will be drawn.
    const outputCanvas = document.createElement('canvas');
    outputCanvas.width = width;
    outputCanvas.height = height;
    const outputCtx = outputCanvas.getContext('2d');

    if (!outputCtx) {
        console.error("Failed to get 2D context for output canvas.");
        // Fallback similar to tempCtx failure
        const errCanvas = document.createElement('canvas');
        errCanvas.width = width; errCanvas.height = height;
        const errCtx = errCanvas.getContext('2d');
        if (errCtx) errCtx.drawImage(originalImg, 0, 0);
        return errCanvas;
    }

    // Create ImageData for the output. This will store the processed pixels.
    const outputImageData = outputCtx.createImageData(width, height);
    const outputData = outputImageData.data;

    // Copy original image data to outputData. Edges will be drawn on top of this.
    for (let i = 0; i < data.length; i++) {
        outputData[i] = data[i];
    }
    
    // Helper function to get the grayscale value of a pixel at (x,y).
    // Uses Rec. 709 luma coefficients, common for digital video.
    // `data`, `width`, and `height` are accessible via closure.
    const getGrayscale = (x, y) => {
        const i = (y * width + x) * 4;
        return 0.2126 * data[i] + 0.7152 * data[i+1] + 0.0722 * data[i+2];
    };

    // Parse the `lineColor` string (e.g., "red", "#FF0000", "rgb(255,0,0)")
    // into its R, G, B components.
    let rLine = 255, gLine = 0, bLine = 0; // Default to red if parsing fails.
    if (typeof document !== 'undefined') { // Check if document is available (browser environment)
        const colorParserCanvas = document.createElement('canvas');
        colorParserCanvas.width = 1;
        colorParserCanvas.height = 1;
        const colorParserCtx = colorParserCanvas.getContext('2d');
        if(colorParserCtx){
            colorParserCtx.fillStyle = lineColor; // Set the fill style to the provided color string
            colorParserCtx.fillRect(0, 0, 1, 1);  // Draw a 1x1 pixel of this color
            const colorPixel = colorParserCtx.getImageData(0, 0, 1, 1).data;
            rLine = colorPixel[0];
            gLine = colorPixel[1];
            bLine = colorPixel[2];
        } else {
            console.warn("Failed to get 2D context for color parsing. Defaulting line color to red.");
        }
    } else {
        // This might happen if running in a non-browser environment like Node.js without a canvas polyfill.
        console.warn("Document object not available for color parsing. Defaulting line color to red.");
    }
    
    // Iterate over each pixel of the image, excluding border pixels
    // because the Sobel operator uses a 3x3 neighborhood.
    for (let y = 1; y < height - 1; y++) {
        for (let x = 1; x < width - 1; x++) {
            // Apply the Sobel operator to calculate the gradient in X and Y directions.
            // Gx (gradient in X direction)
            const gx = (
                getGrayscale(x + 1, y - 1) +
                2 * getGrayscale(x + 1, y) +
                getGrayscale(x + 1, y + 1)
            ) - (
                getGrayscale(x - 1, y - 1) +
                2 * getGrayscale(x - 1, y) +
                getGrayscale(x - 1, y + 1)
            );

            // Gy (gradient in Y direction)
            const gy = (
                getGrayscale(x - 1, y + 1) +
                2 * getGrayscale(x, y + 1) +
                getGrayscale(x + 1, y + 1)
            ) - (
                getGrayscale(x - 1, y - 1) +
                2 * getGrayscale(x, y - 1) +
                getGrayscale(x + 1, y - 1)
            );

            // Calculate the magnitude of the gradient.
            const magnitude = Math.sqrt(gx * gx + gy * gy);

            // If the magnitude is above the threshold, this pixel is considered an edge.
            if (magnitude > threshold) {
                const pixelIndex = (y * width + x) * 4;
                outputData[pixelIndex]     = rLine; // Red component
                outputData[pixelIndex + 1] = gLine; // Green component
                outputData[pixelIndex + 2] = bLine; // Blue component
                outputData[pixelIndex + 3] = 255;   // Alpha component (fully opaque)
            }
        }
    }

    // Put the processed image data (original + edge lines) onto the output canvas.
    outputCtx.putImageData(outputImageData, 0, 0);
    
    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 Edge Highlighting Line Drawer is a tool designed to enhance images by highlighting edges with a specified color. By applying a Sobel operator algorithm, it detects the edges in the image and overlays them with a customizable color. This tool is useful for various applications, such as improving image clarity for graphics design, facilitating object recognition in computer vision tasks, and enhancing outlines in photography. Users can specify the color of the edges and adjust the sensitivity of the detection with a threshold parameter, making it versatile for multiple visual enhancement needs.

Leave a Reply

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