Please bookmark this page to avoid losing your image tool!

Image To Text 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, charSet = " .:-=+*#%@", resolution = 10, invertOutput = 0) {
    // 1. Parameter parsing and validation
    if (typeof charSet !== 'string' || charSet.length === 0) {
        // Default to a simple, clear set if the provided one is invalid.
        // This set is ordered from lightest (space) to darkest ('@').
        charSet = " .:-=+*#%@"; 
    }
    
    resolution = Number(resolution); 
    if (isNaN(resolution) || resolution <= 0) {
        resolution = 10; // Default if NaN, zero, or negative
    } else {
        resolution = Math.floor(resolution); // Ensure it's an integer
    }
    
    // The 'invertOutput' parameter determines the mapping of brightness to characters.
    // 0 (default): Dark image areas -> dark characters. Light image areas -> light characters.
    // 1: Inverted - Dark image areas -> light characters. Light image areas -> dark characters.
    const useInvertedMapping = Number(invertOutput) === 1; 

    const pre = document.createElement('pre');
    pre.style.fontFamily = "monospace";
    // Adjust line-height and font-size for a more compact and visually appealing text art representation.
    // Monospace characters are typically taller than they are wide.
    // A smaller line-height helps to make the aspect ratio of the text art closer to that of the original image.
    pre.style.lineHeight = "0.7"; 
    pre.style.fontSize = "6px";   // Small font size often yields better visual results for detailed text art.

    // 2. Canvas setup
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d', { 
        willReadFrequently: true // Optimization hint for frequent getImageData calls, supported by some browsers.
    }); 

    const imgWidth = originalImg.naturalWidth;
    const imgHeight = originalImg.naturalHeight;

    // Check if the image has valid dimensions (e.g., it's loaded and not a broken image link)
    if (imgWidth === 0 || imgHeight === 0) {
        pre.textContent = "Error: Image has zero dimensions, is not loaded, or is otherwise invalid.";
        return pre;
    }

    canvas.width = imgWidth;
    canvas.height = imgHeight;
    
    try {
        // Draw the image onto the canvas. This is necessary to access its pixel data.
        ctx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);
    } catch (e) {
        // This might happen for various reasons, including if the Image object is not fully loaded or is invalid.
        console.error("Error drawing image to canvas:", e);
        pre.textContent = "Error: Could not draw image to canvas. Please ensure the image is fully loaded and valid.";
        return pre;
    }

    let imageData;
    try {
        // Get pixel data from the canvas. This can throw a SecurityError for cross-origin images if no CORS headers.
        imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
    } catch (e) {
        console.error("Error getting imageData:", e);
        if (e.name === 'SecurityError') {
            pre.textContent = "Error: Could not access pixel data due to cross-origin restrictions. The image must be served with appropriate CORS headers (e.g., 'Access-Control-Allow-Origin') or be from the same domain as the webpage.";
        } else {
            pre.textContent = "Error: Could not retrieve pixel data from the image. The image might be corrupted or in an unsupported format.";
        }
        return pre;
    }
    const data = imageData.data; // This is a Uint8ClampedArray: [R,G,B,A, R,G,B,A, ...]

    let textArt = "";
    const numCharsInSet = charSet.length;

    // 3. Iterate over the image in blocks defined by 'resolution'
    // Each block of (resolution x resolution) pixels from the original image will be converted into one character.
    for (let y = 0; y < imgHeight; y += resolution) {
        let rowString = ""; 
        for (let x = 0; x < imgWidth; x += resolution) {
            let totalBrightness = 0;
            let numPixelsInBlock = 0;

            // Calculate the average brightness of the current block
            for (let blockY = 0; blockY < resolution; blockY++) {
                for (let blockX = 0; blockX < resolution; blockX++) {
                    const currentPixelY = y + blockY;
                    const currentPixelX = x + blockX;

                    // Ensure the pixel we're sampling is within the image bounds
                    if (currentPixelY < imgHeight && currentPixelX < imgWidth) {
                        const offset = (currentPixelY * imgWidth + currentPixelX) * 4; // Index for R channel of the pixel
                        const r = data[offset];
                        const g = data[offset + 1];
                        const b = data[offset + 2];
                        // Alpha (data[offset + 3]) is ignored in this simple implementation.
                        // For images with transparency, one might incorporate alpha:
                        // const alpha = data[offset + 3] / 255;
                        // const brightness = (0.299 * r + 0.587 * g + 0.114 * b) * alpha;
                        
                        // Calculate brightness using the luminosity method (weighted for human perception)
                        const brightness = 0.299 * r + 0.587 * g + 0.114 * b;
                        totalBrightness += brightness;
                        numPixelsInBlock++;
                    }
                }
            }

            if (numPixelsInBlock === 0) {
                // This case should generally not be hit if imgWidth/Height > 0 and resolution > 0.
                // However, defensively, add a space character to maintain the structure of the text art.
                rowString += ' '; 
                continue;
            }

            const avgBrightness = totalBrightness / numPixelsInBlock; // Average brightness for the block (range 0-255)

            // 4. Map brightness to a character from the charSet
            const normalizedBrightness = avgBrightness / 255; // Normalize brightness to 0-1 range
            let charIndex;

            if (useInvertedMapping) { 
                // Inverted mapping: Dark image areas -> light characters; Light image areas -> dark characters.
                // Assumes charSet is light-to-dark:
                // Brightness 0 (black pixel) maps to charSet[0] (lightest character).
                // Brightness 1 (white pixel) maps to charSet[length-1] (darkest character).
                charIndex = Math.floor(normalizedBrightness * (numCharsInSet - 1));
            } else { 
                // Normal mapping: Dark image areas -> dark characters; Light image areas -> light characters.
                // Assumes charSet is light-to-dark:
                // Brightness 0 (black pixel) maps to charSet[length-1] (darkest character).
                // Brightness 1 (white pixel) maps to charSet[0] (lightest character).
                charIndex = Math.floor((1 - normalizedBrightness) * (numCharsInSet - 1));
            }
            
            // Clamp index to prevent out-of-bounds access due to potential floating point inaccuracies (e.g. value being 1.0000000000000001)
            charIndex = Math.max(0, Math.min(numCharsInSet - 1, charIndex));
            
            rowString += charSet[charIndex];
        }
        textArt += rowString + '\n'; // Append the completed row of characters and a newline
    }

    // Set the text content of the <pre> element.
    // trimEnd() removes any trailing newline from the last line, which is common.
    pre.textContent = textArt.trimEnd(); 

    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 Text Art Converter allows users to transform images into ASCII art representations using a customizable set of characters. By adjusting parameters such as resolution and character set, users can create text art that reflects the brightness and details of the original image. This tool is ideal for artists, designers, and anyone interested in creating text-based art from photos or graphics, making it perfect for online sharing, unique displays, or integrating into projects.

Leave a Reply

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