Please bookmark this page to avoid losing your image tool!

Image To Cyrillic Character 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.
async function processImage(originalImg, resolutionFactor = 0.1, invertColorsStr = "false", customChars = "") {
    // Default Cyrillic character set, ordered from darkest to lightest.
    // This set provides a decent range of visual densities.
    const DEFAULT_CHARS_STRING = "ЩШЖБДМФнстлпиегчхэьыъ:. ";

    let effectiveCharacters = (customChars && customChars.length > 0) ? customChars.split('') : DEFAULT_CHARS_STRING.split('');

    // Parse the invertColorsStr parameter
    const invert = String(invertColorsStr).toLowerCase() === "true";

    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d', { willReadFrequently: true }); // Hint for performance

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

    let imageData;
    try {
        imageData = ctx.getImageData(0, 0, canvas.width, canvas.height).data;
    } catch (e) {
        console.error("Error getting image data (possibly CORS issue if image is from another domain):", e);
        const errorPre = document.createElement('pre');
        errorPre.textContent = "Error processing image: Could not get pixel data. If the image is from another domain, ensure CORS policy allows it.";
        return errorPre;
    }


    // charCellSize: The size of the image block (in pixels) that corresponds to one character.
    // resolutionFactor is clamped between 0.01 (100px cell) and 1.0 (1px cell).
    // Default 0.1 means 1/0.1 = 10px cell size.
    const clampedResolutionFactor = Math.max(0.01, Math.min(1.0, resolutionFactor));
    const charCellSize = Math.max(1, Math.floor(1 / clampedResolutionFactor));

    const numCharsAcross = Math.floor(canvas.width / charCellSize);
    const numCharsDown = Math.floor(canvas.height / charCellSize);

    if (numCharsAcross === 0 || numCharsDown === 0) {
        const errorPre = document.createElement('pre');
        errorPre.textContent = "Image dimensions too small for the selected resolution factor, resulting in 0 characters.";
        return errorPre;
    }
    
    let artString = "";

    for (let yBlock = 0; yBlock < numCharsDown; yBlock++) {
        for (let xBlock = 0; xBlock < numCharsAcross; xBlock++) {
            const blockStartX = xBlock * charCellSize;
            const blockStartY = yBlock * charCellSize;

            let totalBrightness = 0;
            let pixelCount = 0;

            for (let py = 0; py < charCellSize; py++) {
                for (let px = 0; px < charCellSize; px++) {
                    const currentPixelX = blockStartX + px;
                    const currentPixelY = blockStartY + py;

                    if (currentPixelX < canvas.width && currentPixelY < canvas.height) {
                        const R_INDEX = (currentPixelY * canvas.width + currentPixelX) * 4;
                        const r = imageData[R_INDEX];
                        const g = imageData[R_INDEX + 1];
                        const b = imageData[R_INDEX + 2];
                        // Standard luminance formula (perceptual brightness)
                        const brightness = 0.299 * r + 0.587 * g + 0.114 * b;
                        totalBrightness += brightness;
                        pixelCount++;
                    }
                }
            }

            let averageBrightness = pixelCount > 0 ? totalBrightness / pixelCount : 0; // Range: 0 (black) to 255 (white)

            if (invert) {
                // Invert brightness: dark becomes light, light becomes dark.
                averageBrightness = 255 - averageBrightness;
            }

            // Map brightness to a character.
            // effectiveCharacters is ordered from darkest to lightest.
            // Low averageBrightness (dark pixel) maps to an early index (dark character).
            // High averageBrightness (light pixel) maps to a late index (light character).
            // The division by 256 ensures that 255 maps to the last character's bucket correctly.
            const charIndex = Math.floor((averageBrightness / 256) * effectiveCharacters.length);
            
            // Clamp index to be safe, though the formula should prevent out-of-bounds.
            const finalCharIndex = Math.max(0, Math.min(effectiveCharacters.length - 1, charIndex));
            
            artString += effectiveCharacters[finalCharIndex];
        }
        artString += '\n';
    }

    const pre = document.createElement('pre');
    pre.style.fontFamily = "monospace, 'Courier New', Courier";
    // Adjust line-height to compensate for typical character aspect ratios (monospace characters are often taller than wide).
    // This makes the overall art aspect ratio closer to the original image.
    // "1.0em" or "normal" would use default line spacing.
    pre.style.lineHeight = "0.8em"; 
    pre.style.whiteSpace = "pre"; // Crucial for preserving formatting
    pre.style.margin = "0"; // Remove default pre margins
    pre.textContent = artString;

    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 Cyrillic Character Art Converter transforms images into artistic representations using Cyrillic characters. Users can adjust the resolution factor to control the level of detail in the output, and can choose to invert the colors for a different artistic effect. This tool is ideal for creating unique text-based images for use in digital art, social media posts, or any platform where textual creativity can enhance visual content.

Leave a Reply

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