Please bookmark this page to avoid losing your image tool!

Image To Emoji 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.
function processImage(originalImg, blockSize = 10) {
    // Ensure blockSize is a positive integer
    blockSize = Math.max(1, Math.floor(blockSize));

    const canvas = document.createElement('canvas');
    // Add willReadFrequently hint for potential performance optimization by the browser
    const ctx = canvas.getContext('2d', { willReadFrequently: true });

    // Use naturalWidth/Height for the image's actual dimensions
    const imgWidth = originalImg.naturalWidth || originalImg.width;
    const imgHeight = originalImg.naturalHeight || originalImg.height;

    // If image dimensions are invalid or image not loaded, return an empty/error element
    if (imgWidth === 0 || imgHeight === 0) {
        const errorOutput = document.createElement('pre');
        errorOutput.textContent = "Image has zero dimensions or could not be loaded properly.";
        return errorOutput;
    }

    canvas.width = imgWidth;
    canvas.height = imgHeight;
    ctx.drawImage(originalImg, 0, 0, imgWidth, imgHeight);

    // Define a palette of emojis and their representative RGB colors
    // These RGB values are approximate and chosen to give a varied palette.
    const emojiPalette = [
        { emoji: '🔴', r: 220, g: 40, b: 40 },    // Red
        { emoji: '🟠', r: 255, g: 150, b: 0 },   // Orange
        { emoji: '🟡', r: 255, g: 235, b: 0 },   // Yellow
        { emoji: '🟢', r: 70, g: 180, b: 70 },    // Green
        { emoji: '🔵', r: 50, g: 100, b: 220 },   // Blue
        { emoji: '🟣', r: 160, g: 60, b: 190 },   // Purple
        { emoji: '🟤', r: 140, g: 70, b: 20 },    // Brown
        { emoji: 'âš«', r: 30, g: 30, b: 30 },     // Near Black
        { emoji: '⚪', r: 240, g: 240, b: 240 },   // Near White
        { emoji: '🩷', r: 255, g: 170, b: 185 },   // Pink
        { emoji: '💚', r: 100, g: 220, b: 100 },   // Light Green (distinct from darker green)
        { emoji: '💙', r: 120, g: 170, b: 250 },   // Light Blue (distinct from darker blue)
        { emoji: '🩶', r: 150, g: 150, b: 150 },   // Gray
    ];

    // Helper function to calculate squared Euclidean distance between two colors
    // Squared distance is used for efficiency as we only need to compare distances.
    function colorDistanceSquared(r1, g1, b1, r2, g2, b2) {
        const dR = r1 - r2;
        const dG = g1 - g2;
        const dB = b1 - b2;
        return dR * dR + dG * dG + dB * dB;
    }

    const outputPre = document.createElement('pre');
    // Style the <pre> element for emoji display
    outputPre.style.fontFamily = '"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji", "sans-serif"';
    outputPre.style.lineHeight = '1'; // For tight vertical packing of emojis
    outputPre.style.backgroundColor = 'transparent'; // Ensure it blends with parent background

    // Adjust font size based on blockSize, within reasonable limits
    // This helps make the emoji characters roughly correspond to the block size visually.
    const fontSize = Math.min(Math.max(blockSize * 0.8, 8), 30); // Min 8px, Max 30px font
    outputPre.style.fontSize = `${fontSize}px`;
    
    let allImageData;
    try {
        // Get pixel data for the entire image once for performance
        allImageData = ctx.getImageData(0, 0, imgWidth, imgHeight);
    } catch (e) {
        // This can happen due to cross-origin restrictions if the image source is external
        // and the canvas becomes tainted.
        console.error("Error getting image data:", e);
        outputPre.textContent = "Error: Could not access image pixel data. This might be due to cross-origin restrictions.";
        return outputPre;
    }
    const allPixelData = allImageData.data;

    const linesArray = []; // Store lines of emojis to join later (performance for many lines)

    // Iterate over the image in blocks of size `blockSize` x `blockSize`
    for (let y = 0; y < imgHeight; y += blockSize) {
        let currentLineEmojis = '';
        for (let x = 0; x < imgWidth; x += blockSize) {
            // Determine the actual width and height of the current block (handles edges)
            const currentBlockWidth = Math.min(blockSize, imgWidth - x);
            const currentBlockHeight = Math.min(blockSize, imgHeight - y);

            let sumR = 0, sumG = 0, sumB = 0;
            let numPixelsInBlock = 0;

            // Calculate the average color of the pixels in the current block
            for (let j = 0; j < currentBlockHeight; j++) { // Iterate rows within the block
                for (let i = 0; i < currentBlockWidth; i++) { // Iterate columns within the block
                    const pixelXInImage = x + i;
                    const pixelYInImage = y + j;
                    // Calculate the index in the 1D pixel data array
                    const dataIndex = (pixelYInImage * imgWidth + pixelXInImage) * 4;

                    sumR += allPixelData[dataIndex];
                    sumG += allPixelData[dataIndex + 1];
                    sumB += allPixelData[dataIndex + 2];
                    // Alpha (allPixelData[dataIndex + 3]) is ignored for simplicity in this version
                    numPixelsInBlock++;
                }
            }

            if (numPixelsInBlock === 0) {
                currentLineEmojis += ' '; // Add a space for empty or problematic blocks
                continue;
            }

            const avgR = sumR / numPixelsInBlock;
            const avgG = sumG / numPixelsInBlock;
            const avgB = sumB / numPixelsInBlock;

            // Find the emoji in the palette that is closest to the average block color
            let bestMatchEmoji = emojiPalette[0].emoji;
            let minColorDistance = Infinity;

            for (const paletteEntry of emojiPalette) {
                const distance = colorDistanceSquared(avgR, avgG, avgB, paletteEntry.r, paletteEntry.g, paletteEntry.b);
                if (distance < minColorDistance) {
                    minColorDistance = distance;
                    bestMatchEmoji = paletteEntry.emoji;
                }
            }
            currentLineEmojis += bestMatchEmoji;
        }
        linesArray.push(currentLineEmojis);
    }

    outputPre.textContent = linesArray.join('\n');
    return outputPre;
}

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 Emoji Art Converter allows users to transform any image into a unique representation made entirely of emojis. By processing the image to create an ’emoji mosaic,’ the tool analyzes the colors in the image and substitutes them with corresponding emojis that match the hues. This feature is useful for artists, social media enthusiasts, or anyone looking to create eye-catching visuals for online sharing or personal projects. The output is formatted for easy display, making it suitable for use in chat applications, art showcases, or as creative content for various digital platforms.

Leave a Reply

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

1 comment on “Image To Emoji Art Converter”

  1. Lucian Bergeron says:

    I absolutely love this, thank you!