Please bookmark this page to avoid losing your image tool!

Image To Alcohol Marker Art 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.
/**
 * Converts an image to an alcohol marker art style by posterizing colors,
 * applying semi-transparent strokes, and adding outlines via edge detection.
 *
 * @param {Image} originalImg The original image object to convert.
 * @param {number} numColors The number of colors to quantize the image to, simulating a limited marker palette.
 * @param {number} strokeSize The average size of the marker strokes in pixels.
 * @param {number} strokeDensity A multiplier for the number of strokes drawn. Higher values result in a denser, more filled-in look.
 * @param {string} lineColor The color of the outlines, in a CSS format (e.g., '#000000' or 'rgb(0,0,0)').
 * @param {number} lineWidth The width of the outlines in pixels.
 * @param {number} lineThreshold The sensitivity for edge detection (a value from 0 to 255). Lower values detect more faint edges.
 * @returns {HTMLCanvasElement} A canvas element with the rendered marker art.
 */
function processImage(originalImg, numColors = 16, strokeSize = 8, strokeDensity = 0.9, lineColor = '#202020', lineWidth = 1, lineThreshold = 40) {
    const width = originalImg.width;
    const height = originalImg.height;

    // Create the final canvas to draw on
    const canvas = document.createElement('canvas');
    canvas.width = width;
    canvas.height = height;
    const ctx = canvas.getContext('2d');

    // Create a temporary canvas for image data manipulation
    const tempCanvas = document.createElement('canvas');
    tempCanvas.width = width;
    tempCanvas.height = height;
    // 'willReadFrequently' is a performance hint for browsers for frequent getImageData calls
    const tempCtx = tempCanvas.getContext('2d', {
        willReadFrequently: true
    });

    // === Step 1: Posterize the image to reduce the color palette ===
    // This simulates using a limited set of marker colors.
    tempCtx.drawImage(originalImg, 0, 0, width, height);
    const posterizedImageData = tempCtx.getImageData(0, 0, width, height);
    const pData = posterizedImageData.data;
    // The factor determines the size of the color "bins"
    const factor = 255 / (Math.max(2, numColors) - 1);
    for (let i = 0; i < pData.length; i += 4) {
        pData[i] = Math.round(pData[i] / factor) * factor;
        pData[i + 1] = Math.round(pData[i + 1] / factor) * factor;
        pData[i + 2] = Math.round(pData[i + 2] / factor) * factor;
    }

    // === Step 2: Simulate random marker strokes ===
    // This builds up the color base with a textured, hand-drawn feel.
    ctx.fillStyle = '#FFFFFF';
    ctx.fillRect(0, 0, width, height);
    ctx.lineCap = 'round';

    // Calculate the number of strokes to draw based on image area and density
    const numStrokes = Math.floor((width * height) / strokeSize * strokeDensity);

    for (let i = 0; i < numStrokes; i++) {
        // Pick a random point on the image
        const x = Math.floor(Math.random() * width);
        const y = Math.floor(Math.random() * height);

        // Get the posterized color at that point
        const pixelIndex = (y * width + x) * 4;
        const r = pData[pixelIndex];
        const g = pData[pixelIndex + 1];
        const b = pData[pixelIndex + 2];

        // Avoid drawing strokes for pure white areas (often the background)
        if (r > 250 && g > 250 && b > 250) {
            continue;
        }

        // Set stroke style with semi-transparency to simulate marker layering
        ctx.strokeStyle = `rgba(${r}, ${g}, ${b}, 0.5)`;
        // Vary stroke width slightly for a more natural look
        ctx.lineWidth = strokeSize * (0.75 + Math.random() * 0.5);

        // Draw a short line at a random angle
        const angle = Math.random() * Math.PI * 2;
        const length = strokeSize;
        ctx.beginPath();
        ctx.moveTo(x - Math.cos(angle) * length / 2, y - Math.sin(angle) * length / 2);
        ctx.lineTo(x + Math.cos(angle) * length / 2, y + Math.sin(angle) * length / 2);
        ctx.stroke();
    }

    // === Step 3: Draw outlines using Sobel edge detection ===
    // This adds definition, similar to inking over a marker drawing.
    tempCtx.drawImage(originalImg, 0, 0, width, height);
    const originalImageData = tempCtx.getImageData(0, 0, width, height);
    const oData = originalImageData.data;

    // Convert the original image to grayscale for simpler edge detection
    const grayData = new Uint8ClampedArray(width * height);
    for (let i = 0; i < oData.length; i += 4) {
        const grayscale = oData[i] * 0.299 + oData[i + 1] * 0.587 + oData[i + 2] * 0.114;
        grayData[i / 4] = grayscale;
    }

    ctx.fillStyle = lineColor;
    // 'multiply' blend mode helps the lines blend into the colors underneath, darkening them.
    ctx.globalCompositeOperation = 'multiply';

    // Sobel operator kernels for edge detection
    const kx = [
        [-1, 0, 1],
        [-2, 0, 2],
        [-1, 0, 1]
    ];
    const ky = [
        [-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 gx = 0;
            let gy = 0;

            // Apply the Sobel kernels to the 3x3 pixel neighborhood
            for (let i = -1; i <= 1; i++) {
                for (let j = -1; j <= 1; j++) {
                    const luma = grayData[(y + i) * width + (x + j)];
                    gx += luma * kx[i + 1][j + 1];
                    gy += luma * ky[i + 1][j + 1];
                }
            }

            const magnitude = Math.sqrt(gx * gx + gy * gy);

            // If the gradient magnitude is above the threshold, it's an edge
            if (magnitude > lineThreshold) {
                ctx.fillRect(x, y, lineWidth, lineWidth);
            }
        }
    }

    // Reset composite operation to default
    ctx.globalCompositeOperation = 'source-over';

    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 Alcohol Marker Art Converter is an online tool that transforms images into a unique alcohol marker art style. It achieves this by reducing the color palette to simulate a limited selection of marker colors, adding semi-transparent strokes for a hand-drawn effect, and outlining key features using edge detection. This tool is perfect for artists, designers, or anyone looking to create playful and artistic renditions of their photos or images, making it suitable for personal projects, social media content, or gifts.

Leave a Reply

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