Please bookmark this page to avoid losing your image tool!

Image Website Content 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, targetLang = 'en', sourceLang = 'en') {

    /**
     * Dynamically loads the Tesseract.js script from a CDN if it's not already present.
     * @returns {Promise<void>} A promise that resolves when the script is loaded.
     */
    const ensureTesseract = () => {
        return new Promise((resolve, reject) => {
            // Check if Tesseract is already available in the global scope
            if (window.Tesseract) {
                return resolve();
            }
            const script = document.createElement('script');
            script.src = 'https://cdn.jsdelivr.net/npm/tesseract.js@5/dist/tesseract.min.js';
            script.onload = resolve;
            script.onerror = () => reject(new Error('Failed to load Tesseract.js script. Please check your internet connection and ad-blockers.'));
            document.head.appendChild(script);
        });
    };

    /**
     * Maps 2-letter ISO 639-1 language codes to 3-letter Tesseract language codes.
     * @param {string} isoCode - The 2-letter language code (e.g., 'en').
     * @returns {string} The corresponding Tesseract language code (e.g., 'eng').
     */
    const getTesseractLangCode = (isoCode) => {
        const map = {
            en: 'eng', es: 'spa', fr: 'fra', de: 'deu', it: 'ita',
            pt: 'por', ru: 'rus', ja: 'jpn', ko: 'kor', ar: 'ara',
            'zh-CN': 'chi_sim', 'zh-TW': 'chi_tra'
        };
        // Handle common case where user might just provide 'zh'
        if (isoCode === 'zh') return 'chi_sim'; 
        return map[isoCode] || 'eng'; // Default to English if not found
    };
    
    // Create a canvas to work on, preserving the original image dimensions.
    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, canvas.width, canvas.height);

    try {
        // Step 1: Ensure Tesseract.js is loaded
        await ensureTesseract();

        const tesseractLang = getTesseractLangCode(sourceLang);
        
        // Logger for showing progress in the developer console
        const logger = ({ status, progress }) => {
            let message = `[OCR] ${status}`;
            if (progress && status === 'recognizing text') {
                message += `: ${(progress * 100).toFixed(1)}%`;
            }
           console.log(message);
        };

        // Step 2: Initialize Tesseract worker and perform Optical Character Recognition (OCR)
        const worker = await Tesseract.createWorker(tesseractLang, 1, { logger });
        const { data: { lines } } = await worker.recognize(canvas);

        if (!lines || lines.length === 0) {
            console.log("No text found in the image.");
            await worker.terminate();
            return canvas; // Return the original image on the canvas
        }

        // Step 3: Prepare recognized text for a batch translation request
        const originalLinesText = lines.map(line => line.text.trim());
        const separator = ' [|||] ';
        const textToTranslate = originalLinesText.join(separator);

        // Step 4: Translate text using a free, key-less API (MyMemory)
        console.log(`[Translate] Requesting translation from '${sourceLang}' to '${targetLang}'...`);
        const apiUrl = `https://api.mymemory.translated.net/get?q=${encodeURIComponent(textToTranslate)}&langpair=${sourceLang}|${targetLang}`;
        const response = await fetch(apiUrl);
        if (!response.ok) {
            throw new Error(`Translation API failed with status: ${response.status}`);
        }
        const translationData = await response.json();
        
        if (translationData.responseStatus !== 200) {
             throw new Error(`Translation API error: ${translationData.responseDetails}`);
        }
        
        // Split the translated blob back into individual lines
        const translatedFullText = translationData.responseData.translatedText;
        const translatedLines = translatedFullText.split(separator.trim()).map(line => line.trim());

        if (originalLinesText.length !== translatedLines.length) {
            console.warn("Translation line count mismatch. Layout may be affected.");
        }

        // Step 5: Draw the translated text over the original text on the canvas
        console.log("[Render] Reconstructing image with translated text...");
        lines.forEach((line, index) => {
            const translatedText = translatedLines[index];
            if (!translatedText || !line.text.trim()) return;

            const bbox = line.bbox;

            // 5a. Cover the old text by sampling a background color from just outside the text box.
            const sampleX = Math.max(0, bbox.x0 - 5);
            const sampleY = Math.max(0, bbox.y0 + Math.floor(bbox.height / 2));
            const pixelData = ctx.getImageData(sampleX, sampleY, 1, 1).data;
            const bgColor = `rgb(${pixelData[0]}, ${pixelData[1]}, ${pixelData[2]})`;
            ctx.fillStyle = bgColor;
            ctx.fillRect(bbox.x0, bbox.y0, bbox.width, bbox.height);

            // 5b. Determine a contrasting text color (black or white) for readability.
            const brightness = (pixelData[0] * 299 + pixelData[1] * 587 + pixelData[2] * 114) / 1000;
            ctx.fillStyle = brightness > 128 ? 'black' : 'white';
            ctx.textBaseline = "middle";
            ctx.textAlign = "left";

            // 5c. Automatically adjust font size so the translated text fits in the original's bounding box.
            let fontSize = bbox.height;
            do {
                ctx.font = `bold ${fontSize}px "Arial", sans-serif`;
                fontSize -= 1;
            } while (fontSize > 5 && ctx.measureText(translatedText).width > bbox.width);
            
            // 5d. Draw the new text, vertically centered in the bounding box.
            const yPos = bbox.y0 + bbox.height / 2;
            ctx.fillText(translatedText, bbox.x0, yPos);
        });

        // Step 6: Clean up the Tesseract worker to free up resources
        await worker.terminate();
        console.log("Processing complete.");

        return canvas;

    } catch (error) {
        console.error("Image translation failed:", error);
        // Draw the error message on the canvas for user feedback
        ctx.fillStyle = 'rgba(255, 0, 0, 0.8)';
        ctx.fillRect(0, canvas.height - 40, canvas.width, 40);
        ctx.fillStyle = 'white';
        ctx.font = 'bold 16px Arial';
        ctx.textAlign = 'center';
        ctx.textBaseline = 'middle';
        ctx.fillText(`Error: ${error.message}`, canvas.width / 2, canvas.height - 20);
        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

The Image Website Content Translator is an online tool that allows users to upload an image containing text in a specified source language and translate that text into a target language. Utilizing Optical Character Recognition (OCR) technology, the tool extracts text from images and processes the translation through a free API. This is particularly useful for translating signage, documents, websites, or any visual content that contains written information, aiding in accessibility and understanding of foreign languages.

Leave a Reply

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