Please bookmark this page to avoid losing your image tool!

Image To Kaomoji Emoticon 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, outputWidthChars = 60, kaomojiCharsStr = " ,·,(^‿^),(O_o),(°Д°),(ಠ_ಠ),█") {
    const kaomojis = kaomojiCharsStr.split(',');

    // Validate Kaomoji set
    if (kaomojis.length === 0 || (kaomojis.length === 1 && kaomojis[0].trim() === "")) {
        const pre = document.createElement('pre');
        pre.textContent = "Error: No Kaomoji characters provided or the set is empty.";
        pre.style.fontFamily = "monospace";
        return pre;
    }
    
    // Validate originalImg (basic check)
    if (!originalImg || typeof originalImg.width === 'undefined' || typeof originalImg.height === 'undefined') {
        const pre = document.createElement('pre');
        pre.textContent = "Error: Invalid image object provided.";
        pre.style.fontFamily = "monospace";
        return pre;
    }

    // Use naturalWidth/Height if available, otherwise use width/height.
    // These are usually the same for an Image object once loaded.
    const originalWidth = originalImg.naturalWidth || originalImg.width;
    const originalHeight = originalImg.naturalHeight || originalImg.height;

    if (originalWidth === 0 || originalHeight === 0) {
        const pre = document.createElement('pre');
        pre.textContent = "Error: Image has zero dimensions.";
        pre.style.fontFamily = "monospace";
        return pre;
    }
    
    // Ensure output dimensions are at least 1x1
    let effectiveOutputWidthChars = Math.max(1, Math.floor(outputWidthChars));

    // Estimate character cell aspect ratio (width/height).
    // Monospace fonts typically have cells that are taller than they are wide.
    // Example: A character might be 8px wide and 16px high, so aspect ratio is 0.5.
    // This factor helps maintain the image's aspect ratio in the text output.
    const charCellAspectRatio = 0.5; 
    let effectiveOutputHeightChars = Math.round(effectiveOutputWidthChars * (originalHeight / originalWidth) * charCellAspectRatio);
    effectiveOutputHeightChars = Math.max(1, effectiveOutputHeightChars);

    const canvas = document.createElement('canvas');
    canvas.width = effectiveOutputWidthChars;
    canvas.height = effectiveOutputHeightChars;
    
    const ctx = canvas.getContext('2d');
    
    if (!ctx) {
        // This should not typically occur in modern browsers for a '2d' context.
        const pre = document.createElement('pre');
        pre.textContent = "Error: Canvas 2D context is not available.";
        pre.style.fontFamily = "monospace";
        return pre;
    }

    // Disable image smoothing for sharper "pixels" when downscaling.
    // This can lead to more distinct character choices.
    ctx.imageSmoothingEnabled = false;
    // For completeness, though less necessary with modern browser versions:
    // ctx.mozImageSmoothingEnabled = false; (Firefox)
    // ctx.webkitImageSmoothingEnabled = false; (WebKit/Blink)
    // ctx.msImageSmoothingEnabled = false; (Edge Legacy/IE)

    // Draw the image onto the small canvas. This performs downsampling.
    ctx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);

    let imageData;
    try {
        imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
    } catch (e) {
        // This can occur if the canvas is "tainted" (e.g., drawing a cross-origin image without CORS).
        const pre = document.createElement('pre');
        pre.textContent = "Error: Could not get image data. The image might be cross-origin, tainting the canvas.";
        pre.style.fontFamily = "monospace";
        console.error("Error in processImage (getImageData):", e);
        return pre;
    }
    
    const data = imageData.data;
    let kaomojiArt = "";
    const numKaomojis = kaomojis.length;

    for (let y = 0; y < canvas.height; y++) {
        for (let x = 0; x < canvas.width; x++) {
            // Get RGBA components for the current "pixel" block.
            // Each "pixel" in our small canvas corresponds to a region in the original image.
            const R_INDEX = (y * canvas.width + x) * 4;
            const r = data[R_INDEX];
            const g = data[R_INDEX + 1];
            const b = data[R_INDEX + 2];
            // Alpha (data[R_INDEX + 3]) is not used for brightness calculation here.

            // Calculate grayscale brightness using the luminosity method (0-255 range).
            const brightness = 0.299 * r + 0.587 * g + 0.114 * b;

            // Map brightness to an index in the kaomojis array.
            // The kaomojis array is assumed to be ordered from lightest to darkest.
            // - A  bright pixel (e.g., brightness 255, white) should map to the first Kaomoji (index 0).
            // - A dark pixel (e.g., brightness 0, black) should map to the last Kaomoji (index numKaomojis - 1).
            let kaomojiIndex;
            if (numKaomojis === 1) {
                kaomojiIndex = 0; // Only one Kaomoji, so always use it.
            } else {
                // Normalize inverted brightness to 0.0-1.0 range (0 for white, 1 for black).
                const normalizedInvertedBrightness = (255 - brightness) / 255;
                // Scale to the range of kaomoji indices and round to nearest integer.
                kaomojiIndex = Math.round(normalizedInvertedBrightness * (numKaomojis - 1));
            }
            
            // Ensure the index is within the valid bounds of the kaomojis array.
            // This is a safeguard, though Math.round with the above logic should be correct.
            kaomojiIndex = Math.min(numKaomojis - 1, Math.max(0, kaomojiIndex));
            
            kaomojiArt += kaomojis[kaomojiIndex];
        }
        kaomojiArt += '\n'; // Add a newline after each row of characters.
    }

    // Create a <pre> element to display the Kaomoji art, preserving whitespace and formatting.
    const pre = document.createElement('pre');
    pre.style.fontFamily = "monospace, 'Courier New', Courier"; // Essential for alignment
    pre.style.lineHeight = "1.0em"; // Adjust for better visual density if needed
    // pre.style.fontSize = "10px"; // Optional: fixed font size for consistent rendering
    pre.textContent = kaomojiArt;
    
    return pre;
}

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 Kaomoji Emoticon Art Converter is a tool that transforms standard images into unique kaomoji art using varying emoticon characters based on brightness levels. Users can upload an image and specify the output width in character units, after which the tool processes the image and generates a text-based representation utilizing selected kaomoji characters. This converter can be used for creative projects, social media content, and messaging apps where users wish to share stylized representations of images or personalize digital communications with fun, artistic text formats.

Leave a Reply

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