Please bookmark this page to avoid losing your image tool!

Image 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.
async function processImage(originalImg, sourceLang = 'auto', targetLang = 'en') {
    /**
     * Dynamically loads a script from a URL into the document head.
     * @param {string} url The URL of the script to load.
     * @returns {Promise<void>} A promise that resolves when the script is loaded.
     */
    const loadScript = (url) => {
        return new Promise((resolve, reject) => {
            const existingScript = document.querySelector(`script[src="${url}"]`);
            if (existingScript) {
                // If the script tag exists, check if the global object it creates is available.
                // For Tesseract.js, this is window.Tesseract.
                if (window.Tesseract) {
                    resolve();
                } else {
                    // The script might be loading. Listen to its load/error events.
                    existingScript.addEventListener('load', () => resolve());
                    existingScript.addEventListener('error', (e) => reject(new Error(`Script load error for ${url}`)));
                }
                return;
            }
            const script = document.createElement('script');
            script.src = url;
            script.onload = () => resolve();
            script.onerror = () => reject(new Error(`Script load error for ${url}`));
            document.head.appendChild(script);
        });
    };

    /**
     * Creates a styled DIV element to display error messages.
     * @param {string} message The error message to display.
     * @returns {HTMLDivElement} The created error element.
     */
    const createErrorElement = (message) => {
        const errorDiv = document.createElement('div');
        errorDiv.style.color = 'red';
        errorDiv.style.padding = '20px';
        errorDiv.style.fontFamily = 'Arial, sans-serif';
        errorDiv.style.border = '1px solid red';
        errorDiv.style.backgroundColor = '#ffeeee';
        errorDiv.innerText = message;
        return errorDiv;
    };

    try {
        await loadScript('https://cdn.jsdelivr.net/npm/tesseract.js@5/dist/tesseract.min.js');
    } catch (error) {
        console.error("Failed to load Tesseract.js:", error);
        return createErrorElement('Error: Could not load the OCR library. Please check your network connection.');
    }

    const canvas = document.createElement('canvas');
    canvas.width = originalImg.naturalWidth;
    canvas.height = originalImg.naturalHeight;
    const ctx = canvas.getContext('2d', {
        willReadFrequently: true
    });
    ctx.drawImage(originalImg, 0, 0);

    let scheduler;
    try {
        // Tesseract.js uses 3-letter ISO 639-2 codes (e.g., 'eng', 'spa').
        // The translation API uses 2-letter ISO 639-1 codes (e.g., 'en', 'es').
        // We'll create a small map for common languages to pass the correct code to Tesseract.
        const tesseractLangMap = {
            'en': 'eng', 'es': 'spa', 'fr': 'fra', 'de': 'deu', 'it': 'ita',
            'pt': 'por', 'ja': 'jpn', 'ko': 'kor', 'zh-CN': 'chi_sim', 
            'zh-TW': 'chi_tra', 'ru': 'rus', 'ar': 'ara', 'hi': 'hin'
        };
        const ocrLang = tesseractLangMap[sourceLang] || (sourceLang !== 'auto' ? sourceLang : 'eng');

        scheduler = Tesseract.createScheduler();
        const worker = await Tesseract.createWorker(ocrLang, 1, {
             logger: m => console.log(m) // Logs progress to the console
        });
        scheduler.addWorker(worker);

        const { data: { lines } } = await scheduler.recognize(originalImg);
        
        if (!lines || lines.length === 0) {
             console.log("No text was detected in the image.");
             await scheduler.terminate();
             return canvas; // Return the original image drawn on the canvas
        }

        for (const line of lines) {
            const bbox = line.bbox;
            const originalText = line.text.trim();

            if (!originalText || originalText.length < 1) continue;

            let translatedText = originalText;
            try {
                const apiUrl = `https://api.mymemory.translated.net/get?q=${encodeURIComponent(originalText)}&langpair=${sourceLang}|${targetLang}`;
                const response = await fetch(apiUrl);
                if (!response.ok) throw new Error(`API request failed with status ${response.status}`);
                
                const translationData = await response.json();
                if (translationData.responseData && translationData.responseData.translatedText) {
                    translatedText = translationData.responseData.translatedText;
                } else if (translationData.matches && translationData.matches.length > 0) {
                    // Fallback to the first match if primary one fails
                    translatedText = translationData.matches[0].translation;
                }
            } catch (e) {
                console.error(`Translation API call failed for "${originalText}":`, e);
                // Keep original text if translation fails
            }

            // Cover up the original text by sampling a background color near the text box.
            const sampleX = bbox.x0 > 2 ? bbox.x0 - 2 : bbox.x1 + 2;
            const sampleY = bbox.y0 > 2 ? bbox.y0 - 2 : bbox.y1 + 2;
            const clampedX = Math.max(0, Math.min(canvas.width - 1, sampleX));
            const clampedY = Math.max(0, Math.min(canvas.height - 1, sampleY));
            
            const pixelData = ctx.getImageData(clampedX, clampedY, 1, 1).data;
            ctx.fillStyle = `rgb(${pixelData[0]}, ${pixelData[1]}, ${pixelData[2]})`;
            // Slightly inflate the box to ensure full coverage of the original text
            ctx.fillRect(bbox.x0 - 2, bbox.y0 - 2, (bbox.x1 - bbox.x0) + 4, (bbox.y1 - bbox.y0) + 4);

            // Draw the translated text, adjusting font size to fit.
            // Using a stroke behind the text improves readability on complex backgrounds.
            ctx.fillStyle = 'black';
            ctx.strokeStyle = 'white';
            ctx.lineWidth = 4; // Adjust stroke width for better visibility
            
            let fontSize = (bbox.y1 - bbox.y0) * 0.8; // Start with a font size proportional to the line height
            
            do {
                ctx.font = `bold ${fontSize}px 'Arial', sans-serif`;
                if(ctx.measureText(translatedText).width < (bbox.x1 - bbox.x0)) {
                    break;
                }
                fontSize--;
            } while (fontSize > 5);

            ctx.textAlign = 'center';
            ctx.textBaseline = 'middle';
            
            const textX = bbox.x0 + (bbox.x1 - bbox.x0) / 2;
            const textY = bbox.y0 + (bbox.y1 - bbox.y0) / 2;
            
            ctx.strokeText(translatedText, textX, textY);
            ctx.fillText(translatedText, textX, textY);
        }

        await scheduler.terminate();

    } catch (error) {
        console.error("An error occurred during the image processing:", error);
        if (scheduler) await scheduler.terminate();
        return createErrorElement(`Processing Error: ${error.message || 'An unknown error occurred.'}`);
    }

    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

Image Translator is a tool that allows users to upload images containing text in various languages and automatically translates the detected text into a target language. It utilizes Optical Character Recognition (OCR) to extract text from images, making it useful for translating signs, documents, or any text captured in a photo. This tool is ideal for travelers needing translations of written information, students studying foreign languages, or anyone looking to understand text in images without manual typing.

Leave a Reply

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