Please bookmark this page to avoid losing your image tool!

Image To Blueprint CAD Style Converter

(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, gridSize = 50, gridLineWidth = 0.5, detailThreshold = 20, outlineThreshold = 40, blurRadius = 2, detailLineWidth = 1, outlineLineWidth = 2) {

    /**
     * Helper function to convert RGBA image data to a grayscale array (1 byte per pixel).
     * @param {Uint8ClampedArray} rgbaData - The source image data array.
     * @param {number} width - The width of the image.
     * @param {number} height - The height of the image.
     * @returns {Uint8ClampedArray} A new array containing grayscale values.
     */
    const toGrayscale = (rgbaData, width, height) => {
        const grayData = new Uint8ClampedArray(width * height);
        for (let i = 0; i < rgbaData.length; i += 4) {
            // Using the luminosity method for a standard grayscale conversion
            const gray = rgbaData[i] * 0.299 + rgbaData[i + 1] * 0.587 + rgbaData[i + 2] * 0.114;
            grayData[i / 4] = gray;
        }
        return grayData;
    };

    /**
     * Helper function for a separable box blur, which is more efficient than a 2D convolution.
     * @param {Uint8ClampedArray} grayData - The source grayscale data.
     * @param {number} width - The width of the image.
     * @param {number} height - The height of the image.
     * @param {number} radius - The blur radius.
     * @returns {Uint8ClampedArray} A new array containing the blurred grayscale data.
     */
    const boxBlur = (grayData, width, height, radius) => {
        const tempBlurData = new Uint8ClampedArray(grayData.length);
        const finalBlurData = new Uint8ClampedArray(grayData.length);
        
        // Horizontal pass
        for (let y = 0; y < height; y++) {
            for (let x = 0; x < width; x++) {
                let sum = 0;
                let count = 0;
                for (let kx = -radius; kx <= radius; kx++) {
                    const ix = x + kx;
                    if (ix >= 0 && ix < width) {
                        sum += grayData[y * width + ix];
                        count++;
                    }
                }
                tempBlurData[y * width + x] = sum / count;
            }
        }
        
        // Vertical pass
        for (let y = 0; y < height; y++) {
            for (let x = 0; x < width; x++) {
                let sum = 0;
                let count = 0;
                for (let ky = -radius; ky <= radius; ky++) {
                    const iy = y + ky;
                    if (iy >= 0 && iy < height) {
                        sum += tempBlurData[iy * width + x];
                        count++;
                    }
                }
                finalBlurData[y * width + x] = sum / count;
            }
        }
        return finalBlurData;
    };

    /**
     * Helper function to apply the Sobel operator for edge detection.
     * @param {Uint8ClampedArray} grayData - The source grayscale data.
     * @param {number} width - The width of the image.
     * @param {number} height - The height of the image.
     * @returns {Uint8ClampedArray} A new array containing edge magnitude values.
     */
    const sobelOperator = (grayData, width, height) => {
        const magnitudeData = new Uint8ClampedArray(width * height);
        // Sobel kernels for detecting horizontal and vertical edges
        const Gx = [
            [-1, 0, 1],
            [-2, 0, 2],
            [-1, 0, 1]
        ];
        const Gy = [
            [-1, -2, -1],
            [0, 0, 0],
            [1, 2, 1]
        ];

        for (let y = 1; y < height - 1; y++) {
            for (let x = 1; x < width - 1; x++) {
                let sumX = 0;
                let sumY = 0;
                // Apply 3x3 kernels by convolving with the image patch
                for (let ky = -1; ky <= 1; ky++) {
                    for (let kx = -1; kx <= 1; kx++) {
                        const val = grayData[(y + ky) * width + (x + kx)];
                        sumX += val * Gx[ky + 1][kx + 1];
                        sumY += val * Gy[ky + 1][kx + 1];
                    }
                }
                // Calculate the gradient magnitude and store it
                const magnitude = Math.sqrt(sumX * sumX + sumY * sumY);
                magnitudeData[y * width + x] = magnitude;
            }
        }
        return magnitudeData;
    };

    // --- Main Function Logic ---

    const width = originalImg.naturalWidth;
    const height = originalImg.naturalHeight;

    const canvas = document.createElement('canvas');
    canvas.width = width;
    canvas.height = height;
    const ctx = canvas.getContext('2d', { willReadFrequently: true });

    // 1. Draw Blueprint Background with specified color
    ctx.fillStyle = '#0A3D91';
    ctx.fillRect(0, 0, width, height);

    // 2. Draw Grid
    ctx.strokeStyle = `rgba(255, 255, 255, 0.15)`;
    ctx.lineWidth = gridLineWidth;
    ctx.beginPath();
    for (let x = gridLineWidth / 2; x <= width; x += gridSize) {
        ctx.moveTo(x, 0);
        ctx.lineTo(x, height);
    }
    for (let y = gridLineWidth / 2; y <= height; y += gridSize) {
        ctx.moveTo(0, y);
        ctx.lineTo(width, y);
    }
    ctx.stroke();

    // 3. Perform Edge Detection
    // Draw the image to a temporary canvas to get its pixel data for processing
    const tempCanvas = document.createElement('canvas');
    tempCanvas.width = width;
    tempCanvas.height = height;
    const tempCtx = tempCanvas.getContext('2d', { willReadFrequently: true });
    tempCtx.drawImage(originalImg, 0, 0, width, height);
    const imageData = tempCtx.getImageData(0, 0, width, height);

    // Image processing pipeline: Grayscale -> Blur -> Sobel
    const grayData = toGrayscale(imageData.data, width, height);
    const blurredGrayData = boxBlur(grayData, width, height, blurRadius);
    
    // Get two edge maps: one for fine details (from original) and one for outlines (from blurred)
    const detailEdges = sobelOperator(grayData, width, height);
    const outlineEdges = sobelOperator(blurredGrayData, width, height);

    // 4. Draw Detected Edges onto the Canvas
    ctx.fillStyle = 'white';

    // First, draw fine details with a thinner line width
    if (detailLineWidth > 0) {
        const detailOffset = Math.floor(detailLineWidth / 2);
        for (let y = 0; y < height; y++) {
            for (let x = 0; x < width; x++) {
                if (detailEdges[y * width + x] > detailThreshold) {
                    ctx.fillRect(x - detailOffset, y - detailOffset, detailLineWidth, detailLineWidth);
                }
            }
        }
    }
    
    // Second, draw main outlines with a thicker line width.
    // Drawing this last ensures outlines are visually dominant.
    if (outlineLineWidth > 0) {
        const outlineOffset = Math.floor(outlineLineWidth / 2);
         for (let y = 0; y < height; y++) {
            for (let x = 0; x < width; x++) {
                if (outlineEdges[y * width + x] > outlineThreshold) {
                    ctx.fillRect(x - outlineOffset, y - outlineOffset, outlineLineWidth, outlineLineWidth);
                }
            }
        }
    }

    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 To Blueprint CAD Style Converter transforms images into a blueprint-style rendering, which includes a grid pattern and enhances outlines and details for a technical drawing effect. Users can specify parameters such as grid size and line widths to customize the output. This tool is particularly useful for architects, engineers, and designers who want to create stylized representations of technical drawings or blueprints from photographs or digital images.

Leave a Reply

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