Please bookmark this page to avoid losing your image tool!

Image Custom Alphabet Translator

(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.
/**
 * Translates an image into a textual representation using a custom alphabet,
 * similar to ASCII art but with user-defined characters.
 *
 * @param {HTMLImageElement} originalImg The source image object to be processed.
 * @param {string} [customAlphabet='@%#*+=-:. '] The set of characters to map to brightness levels. It's recommended to sort this from visually "dense" to "sparse" characters.
 * @param {number} [blockSize=10] The size (in pixels) of each square block of the original image that corresponds to one character in the output. Smaller values yield higher detail.
 * @param {number} [fontSize=10] The font size (in pixels) for the characters in the output canvas.
 * @param {string} [fontFamily='monospace'] The font family to use for rendering the text. The function will attempt to load non-standard fonts from Google Fonts. Monospace fonts are recommended for best results.
 * @param {string} [backgroundColor='#FFFFFF'] The background color of the output canvas.
 * @param {string} [textColor='#000000'] The color of the text characters.
 * @param {number} [invert=0] If set to 1, the brightness-to-character mapping is inverted (bright image areas get "dense" characters and dark areas get "sparse" ones).
 * @returns {Promise<HTMLCanvasElement>} A promise that resolves to a new canvas element containing the generated character art.
 */
async function processImage(originalImg, customAlphabet = '@%#*+=-:. ', blockSize = 10, fontSize = 10, fontFamily = 'monospace', backgroundColor = '#FFFFFF', textColor = '#000000', invert = 0) {
    // 1. Sanitize parameters
    blockSize = Math.max(1, parseInt(blockSize, 10) || 10);
    fontSize = Math.max(1, parseInt(fontSize, 10) || 10);
    invert = (parseInt(invert, 10) === 1) ? 1 : 0;
    if (typeof customAlphabet !== 'string' || customAlphabet.length === 0) {
        customAlphabet = '@%#*+=-:. ';
    }

    // 2. Handle font loading
    const finalFontFamily = await (async () => {
        const genericFamilies = ['serif', 'sans-serif', 'monospace', 'cursive', 'fantasy', 'system-ui'];
        const isGeneric = genericFamilies.some(f => fontFamily.toLowerCase().includes(f));
        if (isGeneric || document.fonts.check(`${fontSize}px "${fontFamily}"`)) {
            return fontFamily; // Font is generic or already available
        }

        // Attempt to load as a Google Font
        try {
            const googleFontFamily = fontFamily.replace(/\s/g, '+');
            const fontUrl = `https://fonts.googleapis.com/css2?family=${googleFontFamily}&display=swap`;

            if (!document.querySelector(`link[href="${fontUrl}"]`)) {
                const link = document.createElement('link');
                link.rel = 'stylesheet';
                link.href = fontUrl;
                document.head.appendChild(link);
                // Wait for the stylesheet to load
                await new Promise((resolve, reject) => {
                    link.onload = resolve;
                    link.onerror = reject;
                });
            }

            await document.fonts.load(`${fontSize}px "${fontFamily}"`);
            return fontFamily;
        } catch (e) {
            console.warn(`Could not load font '${fontFamily}'. Falling back to monospace.`, e);
            return 'monospace';
        }
    })();


    // 3. Create a temporary canvas to read image pixels
    const tempCanvas = document.createElement('canvas');
    const tempCtx = tempCanvas.getContext('2d', {
        willReadFrequently: true
    });
    tempCanvas.width = originalImg.naturalWidth;
    tempCanvas.height = originalImg.naturalHeight;
    tempCtx.drawImage(originalImg, 0, 0);

    // 4. Calculate output grid dimensions
    const cols = Math.floor(tempCanvas.width / blockSize);
    const rows = Math.floor(tempCanvas.height / blockSize);
    if (cols === 0 || rows === 0) {
        console.warn("Image is too small for the specified block size.");
        return document.createElement('canvas');
    }

    // 5. Create and configure the output canvas
    const outputCanvas = document.createElement('canvas');
    const outputCtx = outputCanvas.getContext('2d');

    // Use square cells to approximate the original aspect ratio
    const cellWidth = fontSize;
    const cellHeight = fontSize;

    outputCanvas.width = cols * cellWidth;
    outputCanvas.height = rows * cellHeight;

    outputCtx.fillStyle = backgroundColor;
    outputCtx.fillRect(0, 0, outputCanvas.width, outputCanvas.height);

    outputCtx.fillStyle = textColor;
    outputCtx.font = `${fontSize}px "${finalFontFamily}"`;
    outputCtx.textAlign = 'center';
    outputCtx.textBaseline = 'middle';

    // 6. Process image blocks and draw characters
    const alphabetLength = customAlphabet.length;
    for (let y = 0; y < rows; y++) {
        for (let x = 0; x < cols; x++) {
            const startX = x * blockSize;
            const startY = y * blockSize;

            const imageData = tempCtx.getImageData(startX, startY, blockSize, blockSize);
            const data = imageData.data;
            let totalBrightness = 0;
            const pixelCount = data.length / 4;

            for (let i = 0; i < data.length; i += 4) {
                const r = data[i];
                const g = data[i + 1];
                const b = data[i + 2];
                // Use the luminosity method for a more perceptually accurate brightness
                const brightness = 0.299 * r + 0.587 * g + 0.114 * b;
                totalBrightness += brightness;
            }

            const avgBrightness = totalBrightness / pixelCount;
            const brightnessValue = invert ? 255 - avgBrightness : avgBrightness;

            // Map the brightness value to a character index
            const charIndex = Math.floor((brightnessValue / 255) * (alphabetLength - 1));
            const char = customAlphabet[Math.max(0, Math.min(alphabetLength - 1, charIndex))];

            // Calculate draw position to be the center of the cell
            const drawX = x * cellWidth + cellWidth / 2;
            const drawY = y * cellHeight + cellHeight / 2;

            outputCtx.fillText(char, drawX, drawY);
        }
    }

    // 7. Return the final canvas
    return outputCanvas;
}

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 Custom Alphabet Translator is a tool that transforms images into artistic representations using user-defined characters, akin to ASCII art. Users can customize the style by selecting a specific set of characters to map various brightness levels in the image, allowing for unique and personalized outputs. The tool also offers options to adjust block size for detail, font size, font family for rendering, as well as background and text colors. This can be particularly useful for creating decorative text art for social media posts, creative projects, or any context where visual representation through text is desired.

Leave a Reply

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