Please bookmark this page to avoid losing your image tool!

Image Technical Drawing Filter Effect 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.
async function processImage(originalImg, threshold = 50, lineColorStr = "0,0,0", backgroundColorStr = "255,255,255") {
    const canvas = document.createElement('canvas');
    let ctx;

    // Attempt to get context with willReadFrequently, fallback if not supported
    try {
        ctx = canvas.getContext('2d', { willReadFrequently: true });
    } catch (e) {
        ctx = canvas.getContext('2d');
    }

    const imgWidth = originalImg.naturalWidth || originalImg.width;
    const imgHeight = originalImg.naturalHeight || originalImg.height;

    if (imgWidth === 0 || imgHeight === 0) {
        console.error("Image has zero width or height. Cannot process.");
        const errorCanvas = document.createElement('canvas');
        errorCanvas.width = 200;
        errorCanvas.height = 100;
        const errorCtx = errorCanvas.getContext('2d');
        errorCtx.fillStyle = 'lightgray';
        errorCtx.fillRect(0, 0, errorCanvas.width, errorCanvas.height);
        errorCtx.fillStyle = 'red';
        errorCtx.font = '12px Arial';
        errorCtx.textAlign = 'center';
        errorCtx.textBaseline = 'middle';
        errorCtx.fillText('Invalid image dimensions', errorCanvas.width / 2, errorCanvas.height / 2);
        return errorCanvas;
    }

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

    try {
        ctx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);
    } catch (e) {
        console.error("Error drawing original image onto canvas:", e);
        const errorCanvas = document.createElement('canvas');
        errorCanvas.width = canvas.width > 0 ? canvas.width : 300;
        errorCanvas.height = canvas.height > 0 ? canvas.height : 150;
        const errorCtx = errorCanvas.getContext('2d');
        errorCtx.fillStyle = '#FFDDDD'; // Light red background
        errorCtx.fillRect(0, 0, errorCanvas.width, errorCanvas.height);
        errorCtx.fillStyle = 'black';
        errorCtx.font = `bold ${Math.min(16, Math.floor(errorCanvas.width/20))}px Arial`;
        errorCtx.textAlign = 'center';
        errorCtx.textBaseline = 'middle';
        errorCtx.fillText('Error: Could not draw input image.', errorCanvas.width / 2, errorCanvas.height / 2);
        return errorCanvas;
    }

    let imageData;
    try {
        imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
    } catch (e) {
        // This error typically occurs due to CORS restrictions.
        console.error("Error getting ImageData from canvas (likely a CORS issue):", e);
        const errorCanvas = document.createElement('canvas');
        errorCanvas.width = canvas.width > 0 ? canvas.width : 350; // Ensure minimum width for message
        errorCanvas.height = canvas.height > 0 ? canvas.height : 200; // Ensure minimum height for message
        const errorCtx = errorCanvas.getContext('2d');
        errorCtx.fillStyle = '#EEEEEE'; // Light gray background
        errorCtx.fillRect(0, 0, errorCanvas.width, errorCanvas.height);
        errorCtx.fillStyle = 'red';
        
        const fontSize = Math.max(12, Math.min(16, Math.floor(errorCanvas.width / 28))); // Responsive font size
        errorCtx.font = `bold ${fontSize}px Arial`;
        errorCtx.textAlign = 'center';
        errorCtx.textBaseline = 'middle';
        
        const messages = [
            "Error processing image: Canvas tainted.",
            "This often occurs with cross-origin images",
            "without proper CORS headers.",
            "Ensure the image is from the same domain or",
            "is served with 'Access-Control-Allow-Origin'.",
        ];
        const lineHeight = fontSize * 1.4;
        const totalTextHeight = (messages.length -1) * lineHeight;
        let startY = (errorCanvas.height - totalTextHeight) / 2;

        messages.forEach((msg, index) => {
             errorCtx.fillText(msg, errorCanvas.width / 2, startY + index * lineHeight);
        });
        return errorCanvas;
    }

    const data = imageData.data;
    const width = canvas.width;
    const height = canvas.height;

    // Helper to parse color strings (e.g., "255,0,0") into [R, G, B] arrays
    const parseColor = (colorStr, defaultColor) => {
        const parts = colorStr.split(',').map(numStr => parseInt(numStr.trim(), 10));
        if (parts.length === 3 && parts.every(num => !isNaN(num) && num >= 0 && num <= 255)) {
            return parts;
        }
        console.warn(`Invalid color string format: "${colorStr}". Using default [${defaultColor.join(',')}].`);
        return defaultColor;
    };

    const lineRgb = parseColor(lineColorStr, [0, 0, 0]); // Default to black lines
    const backgroundRgb = parseColor(backgroundColorStr, [255, 255, 255]); // Default to white background

    // 1. Convert to grayscale
    const grayscaleData = new Uint8ClampedArray(width * height);
    for (let i = 0; i < data.length; i += 4) {
        const r = data[i];
        const g = data[i + 1];
        const b = data[i + 2];
        // Standard luminosity calculation, rounded
        grayscaleData[i / 4] = Math.round(0.299 * r + 0.587 * g + 0.114 * b);
    }

    // Helper to get grayscale pixel, handling boundaries with zero-padding
    const getGrayPixel = (x, y) => {
        if (x < 0 || x >= width || y < 0 || y >= height) {
            return 0; 
        }
        return grayscaleData[y * width + x];
    };

    // 2. Apply Sobel operator for edge detection
    const sobelXKernel = [
        [-1, 0, 1],
        [-2, 0, 2],
        [-1, 0, 1]
    ];
    const sobelYKernel = [
        [-1, -2, -1],
        [0, 0, 0],
        [1, 2, 1]
    ];

    const outputImageData = ctx.createImageData(width, height);
    const outputData = outputImageData.data;

    for (let y = 0; y < height; y++) {
        for (let x = 0; x < width; x++) {
            let gx = 0;
            let gy = 0;

            // Convolve with Sobel kernels
            for (let ky = -1; ky <= 1; ky++) {
                for (let kx = -1; kx <= 1; kx++) {
                    const pixelVal = getGrayPixel(x + kx, y + ky);
                    gx += pixelVal * sobelXKernel[ky + 1][kx + 1];
                    gy += pixelVal * sobelYKernel[ky + 1][kx + 1];
                }
            }

            const magnitude = Math.sqrt(gx * gx + gy * gy);
            const pixelIndex = (y * width + x) * 4;

            // Apply threshold to determine line or background
            if (magnitude > threshold) {
                outputData[pixelIndex]     = lineRgb[0];
                outputData[pixelIndex + 1] = lineRgb[1];
                outputData[pixelIndex + 2] = lineRgb[2];
            } else {
                outputData[pixelIndex]     = backgroundRgb[0];
                outputData[pixelIndex + 1] = backgroundRgb[1];
                outputData[pixelIndex + 2] = backgroundRgb[2];
            }
            outputData[pixelIndex + 3] = 255; // Set alpha to fully opaque
        }
    }

    // Create a new canvas and put the processed image data onto it
    const outputCanvas = document.createElement('canvas');
    outputCanvas.width = width;
    outputCanvas.height = height;
    const outputCtx = outputCanvas.getContext('2d');
    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 Technical Drawing Filter Effect Tool transforms images into technical drawings or line art representations. By applying sophisticated edge detection techniques, this tool allows users to convert regular images into high-contrast outputs that can be used for technical documentation, sketches, and artistic interpretations. It is ideal for architects, engineers, designers, and artists looking to create blueprints, schematics, or enhanced visual content from photographs and other images.

Leave a Reply

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