Please bookmark this page to avoid losing your image tool!

Toca Boca Image Creator

(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.
function processImage(originalImg, edgeThreshold = "80", colorLevels = "6", saturation = "150", edgeThickness = "1") {
    // Parse parameters
    const threshold = parseFloat(edgeThreshold);
    const levels = Math.max(2, parseInt(colorLevels));
    const sat = parseFloat(saturation);
    const thickness = parseInt(edgeThickness);

    const width = originalImg.width;
    const height = originalImg.height;

    // 1. Prepare Edge Detection Canvas
    // We apply a slight blur to reduce noise and prevent textures from becoming edges
    const edgeCanvas = document.createElement('canvas');
    edgeCanvas.width = width;
    edgeCanvas.height = height;
    const edgeCtx = edgeCanvas.getContext('2d', { willReadFrequently: true });
    edgeCtx.filter = 'blur(1px)';
    edgeCtx.drawImage(originalImg, 0, 0);
    const edgeImgData = edgeCtx.getImageData(0, 0, width, height);
    const origData = edgeImgData.data;

    // 2. Prepare Color Canvas
    // Toca Boca style is characterized by vibrant, flat colors
    const canvas = document.createElement('canvas');
    canvas.width = width;
    canvas.height = height;
    const ctx = canvas.getContext('2d', { willReadFrequently: true });
    // Boost saturation, slightly contrast, and blur again to soften gradients before posterizing
    ctx.filter = `saturate(${sat}%) contrast(115%) blur(3px)`;
    ctx.drawImage(originalImg, 0, 0);
    ctx.filter = 'none';
    
    const colorImgData = ctx.getImageData(0, 0, width, height);
    const colorData = colorImgData.data;

    // Helper to get Luminance for Sobel Operator
    const getLuma = (idx) => {
        return 0.2126 * origData[idx] + 0.7152 * origData[idx + 1] + 0.0722 * origData[idx + 2];
    };

    let isEdge = new Uint8Array(width * height);

    // 3. Sobel Edge Detection
    for (let y = 1; y < height - 1; y++) {
        for (let x = 1; x < width - 1; x++) {
            // Surrounding pixels
            const p00 = getLuma(((y - 1) * width + (x - 1)) * 4);
            const p10 = getLuma(((y - 1) * width + x) * 4);
            const p20 = getLuma(((y - 1) * width + (x + 1)) * 4);
            const p01 = getLuma((y * width + (x - 1)) * 4);
            const p21 = getLuma((y * width + (x + 1)) * 4);
            const p02 = getLuma(((y + 1) * width + (x - 1)) * 4);
            const p12 = getLuma(((y + 1) * width + x) * 4);
            const p22 = getLuma(((y + 1) * width + (x + 1)) * 4);

            // Horizontal and Vertical Gradients
            const gx = -p00 + p20 - 2 * p01 + 2 * p21 - p02 + p22;
            const gy = -p00 - 2 * p10 - p20 + p02 + 2 * p12 + p22;

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

            if (mag > threshold) {
                isEdge[y * width + x] = 1;
            }
        }
    }

    // 4. Dilate Edges (to add outline thickness)
    if (thickness > 0) {
        const dilatedEdges = new Uint8Array(isEdge);
        const radius = thickness;
        
        for (let y = 0; y < height; y++) {
            for (let x = 0; x < width; x++) {
                if (isEdge[y * width + x] === 1) {
                    for (let dy = -radius; dy <= radius; dy++) {
                        for (let dx = -radius; dx <= radius; dx++) {
                            // Circular dilation check to avoid blocky outlines
                            if (dx * dx + dy * dy <= radius * radius + 0.5) {
                                const ny = y + dy;
                                const nx = x + dx;
                                if (ny >= 0 && ny < height && nx >= 0 && nx < width) {
                                    dilatedEdges[ny * width + nx] = 1;
                                }
                            }
                        }
                    }
                }
            }
        }
        isEdge = dilatedEdges;
    }

    // 5. Combine Edges and Posterize Colors
    const factor = 255 / (levels - 1);

    for (let y = 0; y < height; y++) {
        for (let x = 0; x < width; x++) {
            const idx = (y * width + x) * 4;
            const edgeIdx = y * width + x;

            if (isEdge[edgeIdx]) {
                // Apply thick, dark border typical of the style
                colorData[idx] = 15;     // R
                colorData[idx + 1] = 15; // G
                colorData[idx + 2] = 20; // B
                // Alpha remains as is
            } else {
                // Quantize/Posterize the colors to create smooth, flat color regions
                colorData[idx] = Math.round(colorData[idx] / factor) * factor;
                colorData[idx + 1] = Math.round(colorData[idx + 1] / factor) * factor;
                colorData[idx + 2] = Math.round(colorData[idx + 2] / factor) * factor;
            }
        }
    }

    // 6. Draw processed data back to main canvas
    ctx.putImageData(colorImgData, 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 Toca Boca Image Creator transforms standard photographs into stylized illustrations characterized by vibrant, flat colors and bold outlines. By utilizing edge detection and color quantization techniques, the tool simplifies complex images into smooth, posterized color regions with thick, dark borders. This tool is ideal for users looking to create playful, cartoon-like avatars, custom digital stickers, or whimsical graphic assets for social media and creative design projects.

Leave a Reply

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