Please bookmark this page to avoid losing your image tool!

Photo Number 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 mosaic of numbers, where each number represents
 * the brightness of a block of pixels.
 *
 * @param {Image} originalImg The original Image object to process.
 * @param {number} [blockSize=20] The size in pixels of each square block. Larger values result in a more abstract image.
 * @param {string} [numberSystem='decimal'] The numbering system to use. Options are 'decimal' (0-255), 'hex' (00-FF), or 'binary' (00000000-11111111).
 * @param {string} [fontColor='auto'] The color of the numbers. Use 'auto' for automatic black/white contrast, or a specific CSS color string like '#FF0000'.
 * @param {string} [fontFamily='monospace'] The CSS font-family to use for the numbers.
 * @returns {Promise<HTMLCanvasElement>} A Promise that resolves with a new canvas element displaying the numbered image.
 */
async function processImage(originalImg, blockSize = 20, numberSystem = 'decimal', fontColor = 'auto', fontFamily = 'monospace') {
    // Create a canvas element to work with
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');

    // Ensure block size is a positive integer
    blockSize = Math.max(1, Math.floor(blockSize));

    // Get image dimensions
    const w = originalImg.naturalWidth;
    const h = originalImg.naturalHeight;
    canvas.width = w;
    canvas.height = h;

    // Draw the image onto the canvas to access its pixel data
    ctx.drawImage(originalImg, 0, 0, w, h);
    const imageData = ctx.getImageData(0, 0, w, h);
    const data = imageData.data;

    // Clear the canvas to draw the new numbered grid
    ctx.clearRect(0, 0, w, h);
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';

    // Iterate through the image in sections based on blockSize
    for (let y = 0; y < h; y += blockSize) {
        for (let x = 0; x < w; x += blockSize) {
            
            // Determine the actual size of the block, handling edges of the image
            const currentBlockWidth = Math.min(blockSize, w - x);
            const currentBlockHeight = Math.min(blockSize, h - y);
            
            // Calculate the average color of the pixels in the current block
            let totalR = 0, totalG = 0, totalB = 0;
            const pixelCount = currentBlockWidth * currentBlockHeight;

            for (let by = 0; by < currentBlockHeight; by++) {
                for (let bx = 0; bx < currentBlockWidth; bx++) {
                    const pixelIndex = ((y + by) * w + (x + bx)) * 4;
                    totalR += data[pixelIndex];
                    totalG += data[pixelIndex + 1];
                    totalB += data[pixelIndex + 2];
                }
            }

            const avgR = totalR / pixelCount;
            const avgG = totalG / pixelCount;
            const avgB = totalB / pixelCount;
            const avgColor = `rgb(${Math.round(avgR)}, ${Math.round(avgG)}, ${Math.round(avgB)})`;

            // Draw the background color block
            ctx.fillStyle = avgColor;
            ctx.fillRect(x, y, currentBlockWidth, currentBlockHeight);

            // Calculate the luminance (brightness) to use as the number value
            const luminance = 0.299 * avgR + 0.587 * avgG + 0.114 * avgB;
            const value = Math.round(luminance);
            
            // Format the number based on the selected system
            let numberString;
            switch (numberSystem.toLowerCase()) {
                case 'hex':
                    numberString = value.toString(16).padStart(2, '0').toUpperCase();
                    break;
                case 'binary':
                    numberString = value.toString(2).padStart(8, '0');
                    break;
                case 'decimal':
                default:
                    numberString = value.toString();
                    break;
            }
            
            // Set the font color, choosing black or white for contrast if set to 'auto'
            ctx.fillStyle = (fontColor === 'auto') 
                ? (luminance > 128 ? '#000000' : '#FFFFFF') 
                : fontColor;
            
            // Dynamically adjust font size to fit inside the block
            let fontSize = Math.min(currentBlockWidth, currentBlockHeight);
            if (fontSize < 5) continue; // Skip text if the block is too small to read

            const padding = 0.9; // Use 90% of block width for text to avoid touching edges
            do {
                ctx.font = `${fontSize}px ${fontFamily}`;
                if (ctx.measureText(numberString).width < currentBlockWidth * padding) {
                    break; // The font size fits
                }
                fontSize--;
            } while (fontSize > 4);

            // Draw the number in the center of the block if it's large enough
            if (fontSize > 4) {
                 ctx.fillText(numberString, x + currentBlockWidth / 2, y + currentBlockHeight / 2);
            }
        }
    }

    // The async function implicitly returns a Promise that resolves with the canvas
    return canvas;
}

Free Image Tool Creator

Can't find the image tool you're looking for?
Create one based on your own needs now!

Description

Photo Number Translator transforms images into a mosaic of numbers, where each number conveys the brightness of a pixel block. Users can adjust the block size for varying levels of abstraction and choose between decimal, hexadecimal, or binary numbering systems. This tool is useful for creating visually striking representations of images, educational purposes in teaching the concepts of pixel brightness and color representation, or simply for artistic projects that explore the relationship between visual arts and numerical data.

Leave a Reply

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