Please bookmark this page to avoid losing your image tool!

Image Graffiti Generator

(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,
    text = "GRAFFITI",
    textColor = "#ff0044",
    stencilColor = "#111111",
    wallColor = "#e6e4e0",
    addSplatters = "true"
) {
    // 1. Load graffiti font dynamically using FontFace API
    try {
        const font = new FontFace(
            'Permanent Marker',
            'url(https://fonts.gstatic.com/s/permanentmarker/v16/FhPTLj_xSlGUuBH62peS3sH1_A.woff2)'
        );
        await font.load();
        document.fonts.add(font);
    } catch (err) {
        console.warn("Failed to load graffiti font, using fallback.", err);
    }

    // 2. Setup canvas dimensions based on original image
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
    const width = originalImg.naturalWidth || originalImg.width;
    const height = originalImg.naturalHeight || originalImg.height;
    canvas.width = width;
    canvas.height = height;

    // Apply a slight blur helps reduce noise in the image for a smoother stencil look
    ctx.filter = 'blur(1px)';
    ctx.drawImage(originalImg, 0, 0, width, height);
    ctx.filter = 'none';

    // 3. Helper to parse ANY css color into RGB using an offscreen canvas
    const colorToRGB = (colorStr) => {
        const tempCtx = document.createElement('canvas').getContext('2d');
        tempCtx.fillStyle = '#000000';
        tempCtx.fillStyle = colorStr;
        const c = tempCtx.fillStyle;
        if (/^#[0-9A-Fa-f]{6}$/.test(c)) {
            return {
                r: parseInt(c.substring(1, 3), 16),
                g: parseInt(c.substring(3, 5), 16),
                b: parseInt(c.substring(5, 7), 16)
            };
        } else if (c.startsWith('rgba') || c.startsWith('rgb')) {
            const arr = c.match(/\d+/g);
            return {
                r: parseInt(arr[0] || 0, 10),
                g: parseInt(arr[1] || 0, 10),
                b: parseInt(arr[2] || 0, 10)
            };
        }
        return { r: 0, g: 0, b: 0 };
    };

    const cDark = colorToRGB(stencilColor);
    const cWall = colorToRGB(wallColor);
    const cMid = {
        r: Math.floor((cDark.r + cWall.r) / 2),
        g: Math.floor((cDark.g + cWall.g) / 2),
        b: Math.floor((cDark.b + cWall.b) / 2)
    };

    // 4. Extract pixel data and apply Stencil (Banksy) + Wall Texture effect
    const imgData = ctx.getImageData(0, 0, width, height);
    const data = imgData.data;

    for (let i = 0; i < data.length; i += 4) {
        const r = data[i];
        const g = data[i + 1];
        const b = data[i + 2];
        const lum = 0.299 * r + 0.587 * g + 0.114 * b;

        if (lum < 100) {
            // Dark regions -> solid stencil paint
            data[i] = cDark.r;
            data[i + 1] = cDark.g;
            data[i + 2] = cDark.b;
        } else if (lum < 160) {
            // Midtone regions -> mix of paint and wall
            data[i] = cMid.r;
            data[i + 1] = cMid.g;
            data[i + 2] = cMid.b;
        } else {
            // Light regions -> wall background with concrete-like noise texture
            const noise = (Math.random() - 0.5) * 20; 
            data[i] = Math.min(255, Math.max(0, cWall.r + noise));
            data[i + 1] = Math.min(255, Math.max(0, cWall.g + noise));
            data[i + 2] = Math.min(255, Math.max(0, cWall.b + noise));
        }
        data[i + 3] = 255; // Set fully opaque
    }
    ctx.putImageData(imgData, 0, 0);

    // 5. Add spray paint splatters and dripping effects
    if (String(addSplatters).toLowerCase() === "true") {
        const splatCount = Math.floor((width * height) / 12000); 
        for (let i = 0; i < splatCount; i++) {
            const x = Math.random() * width;
            const y = Math.random() * height;
            const radius = Math.random() * (width * 0.005) + 1;
            
            ctx.fillStyle = Math.random() > 0.4 ? stencilColor : textColor;
            ctx.globalAlpha = Math.random() * 0.7 + 0.3;

            // Paint dot
            ctx.beginPath();
            ctx.arc(x, y, radius, 0, Math.PI * 2);
            ctx.fill();

            // Dripping effect on some dots
            if (Math.random() > 0.8) {
                const dripLen = Math.random() * (height * 0.05) + 5;
                ctx.beginPath();
                ctx.arc(x, y + dripLen, radius * 0.6, 0, Math.PI * 2);
                ctx.fill();

                ctx.beginPath();
                ctx.moveTo(x - radius * 0.8, y);
                ctx.lineTo(x + radius * 0.8, y);
                ctx.lineTo(x + radius * 0.5, y + dripLen);
                ctx.lineTo(x - radius * 0.5, y + dripLen);
                ctx.fill();
            }
        }
        ctx.globalAlpha = 1.0; // Reset alpha
    }

    // 6. Overlay graffiti stylish text
    if (text && text.trim().length > 0) {
        ctx.save();
        let fontSize = Math.floor(width / text.length * 1.5);
        if (fontSize > height * 0.3) fontSize = height * 0.3;
        if (fontSize < 30) fontSize = 30;

        ctx.font = `${fontSize}px "Permanent Marker", "Brush Script MT", Impact, sans-serif`;
        ctx.textAlign = 'center';
        ctx.textBaseline = 'middle';

        // Shrink font size if it exceeds canvas width boundaries
        while (ctx.measureText(text).width > width * 0.9 && fontSize > 20) {
            fontSize -= 2;
            ctx.font = `${fontSize}px "Permanent Marker", "Brush Script MT", Impact, sans-serif`;
        }

        const xPos = width / 2;
        const yPos = height * 0.85;

        // Shadow / 3D Extrusion Effect
        ctx.fillStyle = stencilColor;
        const shadowOffset = Math.max(2, Math.floor(fontSize * 0.05));
        ctx.fillText(text, xPos + shadowOffset, yPos + shadowOffset);
        ctx.fillText(text, xPos + shadowOffset * 1.5, yPos + shadowOffset * 1.5);

        // White pop outline
        ctx.strokeStyle = '#ffffff';
        ctx.lineWidth = Math.max(2, Math.floor(fontSize * 0.05));
        ctx.strokeText(text, xPos, yPos);

        // Fill color
        ctx.fillStyle = textColor;
        ctx.fillText(text, xPos, yPos);

        ctx.restore();
    }

    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 Graffiti Generator transforms your uploaded images into street-style stencil art. The tool applies a stencil-like effect to the image, simulating how it would look when spray-painted onto a wall, complete with texture and concrete-like noise. You can customize the look by selecting specific colors for the stencil, text, and wall background. Additionally, the tool can add realistic spray paint splatters and dripping effects, and overlay stylish graffiti-themed text with 3D extrusion and outlines. This tool is ideal for creating urban-style digital art, unique social media graphics, or themed design assets.

Leave a Reply

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