Please bookmark this page to avoid losing your image tool!

Image To Marker 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 into a marker drawing style.
 *
 * @param {Image} originalImg The original image object to be processed.
 * @param {number} markerSize The base size (thickness) of the marker strokes. Default is 8.
 * @param {number} density A value between 0 and 1 that controls the number of strokes. Higher means more strokes and detail. Default is 0.5.
 * @param {string} colors A comma-separated string of hex color codes to use for the marker palette. Default is a standard 8-color set.
 * @param {number} angle The general angle of the marker strokes in degrees. Use -1 for random angles for each stroke. Default is 45.
 * @returns {HTMLCanvasElement} A new canvas element with the marker-style drawing.
 */
async function processImage(originalImg, markerSize = 8, density = 0.5, colors = '#000000,#FF0000,#0000FF,#008000,#FFFF00,#FFA500,#800080,#A52A2A', angle = 45) {

    // 1. Setup Canvases
    const width = originalImg.width;
    const height = originalImg.height;

    // Hidden canvas to get pixel data from the original image
    const hiddenCanvas = document.createElement('canvas');
    hiddenCanvas.width = width;
    hiddenCanvas.height = height;
    const hiddenCtx = hiddenCanvas.getContext('2d');
    hiddenCtx.drawImage(originalImg, 0, 0);
    const imageData = hiddenCtx.getImageData(0, 0, width, height).data;

    // Output canvas for drawing the result
    const outputCanvas = document.createElement('canvas');
    outputCanvas.width = width;
    outputCanvas.height = height;
    const ctx = outputCanvas.getContext('2d');

    // Fill the background with white
    ctx.fillStyle = '#FFFFFF';
    ctx.fillRect(0, 0, width, height);

    // 2. Prepare Color Palette
    const hexToRgb = (hex) => {
        const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
        return result ? {
            r: parseInt(result[1], 16),
            g: parseInt(result[2], 16),
            b: parseInt(result[3], 16)
        } : null;
    };

    const palette = colors.split(',')
        .map(hex => hexToRgb(hex.trim()))
        .filter(c => c !== null);

    if (palette.length === 0) {
        // Add a default black color if the palette is empty or parsing failed
        palette.push({ r: 0, g: 0, b: 0 });
    }

    // 3. Helper function to find the closest color in the palette
    const findClosestColor = (r, g, b, colorPalette) => {
        let closestColor = colorPalette[0];
        let minDistanceSq = Infinity;

        for (const color of colorPalette) {
            const distanceSq = Math.pow(r - color.r, 2) + Math.pow(g - color.g, 2) + Math.pow(b - color.b, 2);
            if (distanceSq < minDistanceSq) {
                minDistanceSq = distanceSq;
                closestColor = color;
            }
        }
        return `rgb(${closestColor.r},${closestColor.g},${closestColor.b})`;
    };

    // 4. Drawing Logic
    ctx.lineCap = 'round';
    ctx.globalAlpha = 0.85; // Simulate marker ink transparency and layering

    const step = Math.max(1, Math.floor(markerSize * 0.7));
    
    // Create a shuffled list of points to draw in a random order, making it look more natural
    const points = [];
    for (let y = 0; y < height; y += step) {
        for (let x = 0; x < width; x += step) {
            points.push({ x, y });
        }
    }
    
    // Fisher-Yates shuffle for random order
    for (let i = points.length - 1; i > 0; i--) {
        const j = Math.floor(Math.random() * (i + 1));
        [points[i], points[j]] = [points[j], points[i]];
    }

    for (const point of points) {
        // Use density to probabilistically skip some strokes
        if (Math.random() > density) {
            continue;
        }

        const { x, y } = point;
        const index = (y * width + x) * 4;
        const r = imageData[index];
        const g = imageData[index + 1];
        const b = imageData[index + 2];
        const a = imageData[index + 3];

        // Skip transparent or very light areas
        if (a < 128 || (r > 245 && g > 245 && b > 245)) {
            continue;
        }
        
        // Find the matching marker color
        const closestColor = findClosestColor(r, g, b, palette);
        ctx.strokeStyle = closestColor;
        
        // Add random variations to each stroke for a more hand-drawn feel
        const currentMarkerSize = markerSize * (0.8 + Math.random() * 0.4);
        const strokeLength = currentMarkerSize * 1.5;
        ctx.lineWidth = currentMarkerSize;
        
        const baseAngle = (angle === -1) ?
            Math.random() * Math.PI * 2 :
            angle * Math.PI / 180;
        
        const finalAngle = baseAngle + (Math.random() - 0.5) * (Math.PI / 6); // Add slight angle jitter

        const dx = Math.cos(finalAngle) * strokeLength / 2;
        const dy = Math.sin(finalAngle) * strokeLength / 2;

        ctx.beginPath();
        ctx.moveTo(x - dx, y - dy);
        ctx.lineTo(x + dx, y + dy);
        ctx.stroke();
    }

    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 To Marker Converter transforms traditional images into a unique marker drawing style, simulating the appearance of marker strokes on a canvas. Users can customize the thickness and density of the marker strokes, choose from a variety of color palettes, and alter the orientation of the strokes. This tool is ideal for artists and designers looking to create stylized artwork from photographs or digital images, enhancing graphic design projects, educational materials, or personal illustrations.

Leave a Reply

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