Please bookmark this page to avoid losing your image tool!

Image Linguistic Translator Tool

(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, pixelationLevel = 8, dithering = 'floyd-steinberg', textOverlay = '', fontColor = '0,0,0', fontSize = 24, textX = 10, textY = 10) {

    /**
     * Dynamically loads a Google Font to be used on the canvas.
     * Uses "VT323" for a retro, pixelated, MS Paint-like feel.
     * @param {string} fontFamily - The name of the font family to load.
     * @param {number} size - The font size to use for loading check.
     */
    const loadFont = async (fontFamily, size) => {
        const fontId = `font-loader-${fontFamily.replace(/\s/g, '-')}`;
        if (document.getElementById(fontId)) {
           // Font stylesheet is already added, assume it's loaded or loading
           await document.fonts.load(`${size}px ${fontFamily}`);
           return;
        }
        
        const link = document.createElement('link');
        link.id = fontId;
        link.rel = 'stylesheet';
        link.href = `https://fonts.googleapis.com/css2?family=${fontFamily.replace(/\s/g, '+')}&display=swap`;
        
        const fontPromise = document.fonts.load(`${size}px ${fontFamily}`);
        document.head.appendChild(link);
        await fontPromise;
    };

    // --- 1. SETUP & PARAMETER VALIDATION ---
    const FONT_FAMILY = 'VT323';
    if (textOverlay && textOverlay.trim() !== '') {
        await loadFont(FONT_FAMILY, fontSize);
    }
    
    const w = originalImg.width;
    const h = originalImg.height;
    const blocksize = Math.max(1, Math.floor(pixelationLevel));

    // The iconic 16-color Windows / VGA palette
    const palette = [
        [0, 0, 0], [128, 0, 0], [0, 128, 0], [128, 128, 0],
        [0, 0, 128], [128, 0, 128], [0, 128, 128], [192, 192, 192],
        [128, 128, 128], [255, 0, 0], [0, 255, 0], [255, 255, 0],
        [0, 0, 255], [255, 0, 255], [0, 255, 255], [255, 255, 255]
    ];

    /**
     * Finds the closest color in the palette to a given RGB color.
     * Uses squared Euclidean distance for efficiency.
     */
    const findClosestColor = (r, g, b, pal) => {
        let closest = pal[0];
        let minDistance = Infinity;
        for (const color of pal) {
            const dist = (r - color[0]) ** 2 + (g - color[1]) ** 2 + (b - color[2]) ** 2;
            if (dist < minDistance) {
                minDistance = dist;
                closest = color;
            }
        }
        return closest;
    };


    // --- 2. IMAGE PROCESSING (PIXELATION & DITHERING) ---

    // Create a working canvas, downsampled if pixelation is requested.
    // Downsampling first improves performance of the dithering algorithm.
    const workingCanvas = document.createElement('canvas');
    const workingCtx = workingCanvas.getContext('2d');
    workingCanvas.width = Math.floor(w / blocksize);
    workingCanvas.height = Math.floor(h / blocksize);
    
    // Draw the original image onto the smaller canvas, which averages the pixels.
    workingCtx.drawImage(originalImg, 0, 0, workingCanvas.width, workingCanvas.height);

    const imageData = workingCtx.getImageData(0, 0, workingCanvas.width, workingCanvas.height);
    const pixels = imageData.data;
    
    // Create a floating-point representation of the image for accurate error diffusion.
    const floatPixels = [];
    for (let i = 0; i < pixels.length; i += 4) {
        floatPixels.push({ r: pixels[i], g: pixels[i + 1], b: pixels[i + 2] });
    }

    // Apply color quantization and optional dithering.
    for (let y = 0; y < workingCanvas.height; y++) {
        for (let x = 0; x < workingCanvas.width; x++) {
            const index = y * workingCanvas.width + x;
            const oldColor = floatPixels[index];
            
            const newColor = findClosestColor(oldColor.r, oldColor.g, oldColor.b, palette);

            // Update the final pixel data with the new quantized color.
            pixels[index * 4] = newColor[0];
            pixels[index * 4 + 1] = newColor[1];
            pixels[index * 4 + 2] = newColor[2];
            
            if (dithering.toLowerCase() === 'floyd-steinberg') {
                const errR = oldColor.r - newColor[0];
                const errG = oldColor.g - newColor[1];
                const errB = oldColor.b - newColor[2];

                // Distribute the error to neighboring pixels.
                const distributeError = (dx, dy, factor) => {
                    const nx = x + dx;
                    const ny = y + dy;
                    if (nx >= 0 && nx < workingCanvas.width && ny >= 0 && ny < workingCanvas.height) {
                        const neighborIndex = ny * workingCanvas.width + nx;
                        floatPixels[neighborIndex].r += errR * factor;
                        floatPixels[neighborIndex].g += errG * factor;
                        floatPixels[neighborIndex].b += errB * factor;
                    }
                };

                distributeError(1, 0, 7 / 16);
                distributeError(-1, 1, 3 / 16);
                distributeError(0, 1, 5 / 16);
                distributeError(1, 1, 1 / 16);
            }
        }
    }

    // Put the processed pixel data back onto the working canvas.
    workingCtx.putImageData(imageData, 0, 0);

    // --- 3. FINAL COMPOSITION & TEXT OVERLAY ---
    
    // Create the final output canvas at the original size.
    const outputCanvas = document.createElement('canvas');
    outputCanvas.width = w;
    outputCanvas.height = h;
    const outputCtx = outputCanvas.getContext('2d');
    
    // Disable anti-aliasing to preserve the sharp, blocky pixel look.
    outputCtx.imageSmoothingEnabled = false;
    outputCtx.mozImageSmoothingEnabled = false;
    outputCtx.webkitImageSmoothingEnabled = false;
    outputCtx.msImageSmoothingEnabled = false;

    // Draw the processed (and possibly smaller) working canvas onto the final canvas, scaling it up.
    outputCtx.drawImage(workingCanvas, 0, 0, w, h);

    // Add the text overlay if provided.
    if (textOverlay && textOverlay.trim() !== '') {
        outputCtx.font = `${fontSize}px "${FONT_FAMILY}"`;
        outputCtx.fillStyle = `rgb(${fontColor})`;
        outputCtx.textBaseline = 'top';
        outputCtx.fillText(textOverlay, textX, textY);
    }
    
    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 Linguistic Translator Tool allows users to pixelate images while applying optional dithering effects and adding customizable text overlays. With features like selecting a pixelation level, utilizing a retro color palette, and overlaying text in a chosen font style and size, this tool is ideal for creating pixel art or retro-styled images. It can be particularly useful for designers, game developers, or anyone looking to add a creative touch to their images by transforming them into an artistic representation reminiscent of vintage graphics.

Leave a Reply

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