Please bookmark this page to avoid losing your image tool!

Image Retouching For Laser Engraving

(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.
/**
 * Retouches an image to make it suitable for laser engraving.
 * This involves converting the image to grayscale, adjusting brightness and contrast,
 * applying optional sharpening, and then converting it to pure black and white
 * using dithering or a simple threshold.
 *
 * @param {Image} originalImg The original Image object to process.
 * @param {number} [brightness=0] Brightness adjustment. Recommended range: -100 to 100.
 * @param {number} [contrast=0] Contrast adjustment. Recommended range: -100 to 100.
 * @param {number} [sharpen=0] Sharpening amount. Recommended range: 0 to 100.
 * @param {string} [ditheringMethod='floyd-steinberg'] The quantization method. Options: 'none', 'bayer', 'floyd-steinberg'.
 * @param {number} [threshold=128] The threshold for black/white conversion (0-255), only used if ditheringMethod is 'none'.
 * @returns {HTMLCanvasElement} A canvas element with the processed image.
 */
function processImage(originalImg, brightness = 0, contrast = 0, sharpen = 0, ditheringMethod = 'floyd-steinberg', threshold = 128) {
    // 1. Setup Canvas
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
    const width = originalImg.naturalWidth;
    const height = originalImg.naturalHeight;
    canvas.width = width;
    canvas.height = height;

    ctx.drawImage(originalImg, 0, 0, width, height);
    const imageData = ctx.getImageData(0, 0, width, height);
    const data = imageData.data;

    // Create a floating point array for more precise intermediate calculations
    const grayData = new Float32Array(width * height);

    // 2. Pass 1: Grayscale, Brightness & Contrast
    // The contrast formula is taken from the CamanJS library.
    const contrastFactor = (259 * (contrast + 255)) / (255 * (259 - contrast));
    for (let i = 0; i < data.length; i += 4) {
        const r = data[i];
        const g = data[i + 1];
        const b = data[i + 2];

        // Standard luminance calculation
        let gray = 0.299 * r + 0.587 * g + 0.114 * b;

        // Apply brightness
        gray += brightness;

        // Apply contrast
        gray = contrastFactor * (gray - 128) + 128;

        // Clamp the value and store it
        grayData[i / 4] = Math.max(0, Math.min(255, gray));
    }

    // 3. Pass 2: Sharpening (if requested)
    if (sharpen > 0) {
        const sharpenAmount = sharpen / 100;
        const sharpenKernel = [
            [0, -1, 0],
            [-1, 5, -1],
            [0, -1, 0]
        ];
        const identityKernel = [
            [0, 0, 0],
            [0, 1, 0],
            [0, 0, 0]
        ];

        // Create a blended kernel based on the sharpen amount
        const finalKernel = identityKernel.map((row, y) =>
            row.map((val, x) => (1 - sharpenAmount) * val + sharpenAmount * sharpenKernel[y][x])
        );
        
        const grayCopy = new Float32Array(grayData); // Work on a copy
        for (let y = 1; y < height - 1; y++) {
            for (let x = 1; x < width - 1; x++) {
                let sum = 0;
                const i = y * width + x;
                for (let ky = -1; ky <= 1; ky++) {
                    for (let kx = -1; kx <= 1; kx++) {
                        sum += grayCopy[(y + ky) * width + (x + kx)] * finalKernel[ky + 1][kx + 1];
                    }
                }
                grayData[i] = sum;
            }
        }
    }


    // 4. Pass 3: Quantization (Dithering or Threshold) and Final Write
    const method = ditheringMethod.toLowerCase();

    if (method === 'floyd-steinberg') {
        for (let y = 0; y < height; y++) {
            for (let x = 0; x < width; x++) {
                const i = y * width + x;
                const dataIndex = i * 4;

                const oldPixel = Math.max(0, Math.min(255, grayData[i]));
                const newPixel = oldPixel < 128 ? 0 : 255;
                const quantError = oldPixel - newPixel;

                // Set the final pixel value in the image data
                data[dataIndex] = data[dataIndex + 1] = data[dataIndex + 2] = newPixel;

                // Distribute the error to neighboring pixels
                if (x + 1 < width) grayData[i + 1] += quantError * 7 / 16;
                if (y + 1 < height) {
                    if (x > 0) grayData[i + width - 1] += quantError * 3 / 16;
                    grayData[i + width] += quantError * 5 / 16;
                    if (x + 1 < width) grayData[i + width + 1] += quantError * 1 / 16;
                }
            }
        }
    } else if (method === 'bayer') {
        const bayerMatrix = [
            [1, 9, 3, 11],
            [13, 5, 15, 7],
            [4, 12, 2, 10],
            [16, 8, 14, 6]
        ];
        const matrixSize = 4;
        for (let y = 0; y < height; y++) {
            for (let x = 0; x < width; x++) {
                const i = y * width + x;
                const dataIndex = i * 4;
                const grayValue = Math.max(0, Math.min(255, grayData[i]));
                const bayerThreshold = ((bayerMatrix[y % matrixSize][x % matrixSize] - 1) / 16) * 255;

                const newPixel = grayValue > bayerThreshold ? 255 : 0;
                data[dataIndex] = data[dataIndex + 1] = data[dataIndex + 2] = newPixel;
            }
        }
    } else { // 'none' or any other value defaults to simple threshold
        for (let i = 0; i < grayData.length; i++) {
            const dataIndex = i * 4;
            const grayValue = Math.max(0, Math.min(255, grayData[i]));
            const newPixel = grayValue > threshold ? 255 : 0;
            data[dataIndex] = data[dataIndex + 1] = data[dataIndex + 2] = newPixel;
        }
    }

    // 5. Put the modified 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 Retouching for Laser Engraving tool allows users to prepare images for laser engraving by applying a series of enhancements. It converts images to grayscale and allows for adjustments in brightness and contrast. Users can also apply sharpening effects to enhance details before converting the image to pure black and white. This tool is particularly useful for photographers, artists, and crafters looking to create high-quality engravings from their images.

Leave a Reply

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