You can edit the below JavaScript code to customize the image tool.
async function processImage(originalImg, sourceLang = 'eng', targetLang = 'fr', coverColor = '#FFFFFF', textColor = '#000000', fontFamily = 'Arial') {
/**
* Dynamically loads an external script. It avoids reloading if the script is already present.
* @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) => {
// Check if Tesseract is already loaded
if (window.Tesseract) {
return resolve();
}
const script = document.createElement('script');
script.src = url;
script.onload = () => resolve();
script.onerror = () => reject(new Error(`Failed to load script: ${url}`));
document.head.appendChild(script);
});
};
/**
* Calculates the optimal font size and line breaks for a text to fit within a bounding box.
* @param {CanvasRenderingContext2D} ctx - The canvas rendering context.
* @param {string} text - The text to be fitted.
* @param {string} fontFamily - The font family for the text.
* @param {number} maxWidth - The maximum width for the text block.
* @param {number} maxHeight - The maximum height for the text block.
* @returns {{fontSize: number, lines: string[], lineHeight: number}} - The calculated properties.
*/
const fitTextInBox = (ctx, text, fontFamily, maxWidth, maxHeight) => {
let fontSize = Math.min(maxHeight, maxWidth / 2); // Start with a reasonable font size estimate
let lines;
let lineHeight;
// Decrease font size until the text fits within the box
while (fontSize > 4) { // Minimum font size of 4px
ctx.font = `${fontSize}px ${fontFamily}`;
const words = text.split(/\s+/); // Split by any whitespace
lines = [];
let currentLine = words[0] || '';
for (let i = 1; i < words.length; i++) {
const word = words[i];
const testLine = currentLine + ' ' + word;
if (ctx.measureText(testLine).width < maxWidth) {
currentLine = testLine;
} else {
lines.push(currentLine);
currentLine = word;
}
}
lines.push(currentLine);
lineHeight = fontSize * 1.2; // A standard line height multiplier
const totalHeight = lines.length * lineHeight;
if (totalHeight <= maxHeight) {
// This font size works
return { fontSize, lines, lineHeight };
}
fontSize -= 1; // Decrement font size and try again
}
// Fallback if text is too long to fit even at the minimum font size
return { fontSize: 4, lines, lineHeight: 4 * 1.2 };
};
// --- Main function logic starts here ---
// Create a canvas to draw on, matching the original image's dimensions.
const canvas = document.createElement('canvas');
canvas.width = originalImg.naturalWidth;
canvas.height = originalImg.naturalHeight;
const ctx = canvas.getContext('2d');
ctx.drawImage(originalImg, 0, 0);
let worker;
try {
// Step 1: Load the Tesseract.js OCR library
// Note: This function depends on the Tesseract.js CDN.
await loadScript('https://cdn.jsdelivr.net/npm/tesseract.js@5/dist/tesseract.min.js');
// Step 2: Initialize a Tesseract worker for the specified source language.
// This will download language-specific data, which may take time on the first run.
console.log(`Initializing Tesseract worker for language: ${sourceLang}`);
worker = await Tesseract.createWorker(sourceLang, 1, {
logger: m => console.log(m.status, `${Math.round(m.progress * 100)}%`) // Log progress
});
// Step 3: Perform OCR on the image to detect text and its location (bounding boxes).
console.log('Recognizing text in the image...');
const { data: { paragraphs } } = await worker.recognize(canvas);
// Step 4: Translate the recognized text using a free, public translation API.
// Note: This uses api.mymemory.translated.net, which has fair use limits.
console.log('Translating recognized text...');
// Map Tesseract's 3-letter language codes (ISO 639-2) to 2-letter codes (ISO 639-1) for the API.
const langMap = { 'eng': 'en', 'fra': 'fr', 'spa': 'es', 'deu': 'de', 'ita': 'it', 'por': 'pt', 'rus': 'ru', 'jpn': 'ja', 'kor': 'ko', 'chi_sim': 'zh-CN', 'chi_tra': 'zh-TW' };
const sourceLangApiCode = langMap[sourceLang] || sourceLang.substring(0, 2);
const translationJobs = paragraphs.map(p => {
const textToTranslate = p.text.trim();
if (!textToTranslate) {
return Promise.resolve({ original: p, translatedText: '' });
}
const apiUrl = `https://api.mymemory.translated.net/get?q=${encodeURIComponent(textToTranslate)}&langpair=${sourceLangApiCode}|${targetLang}`;
return fetch(apiUrl)
.then(res => res.json())
.then(data => ({
original: p,
translatedText: data.responseData.translatedText || `[No translation]`
}))
.catch(error => ({
original: p,
translatedText: `[Network Error]`
}));
});
const translatedParagraphs = await Promise.all(translationJobs);
// Step 5: Render the translations back onto the canvas.
console.log('Rendering translations onto the image...');
for (const { original, translatedText } of translatedParagraphs) {
if (!translatedText) continue;
const bbox = original.bbox;
const rectWidth = bbox.x1 - bbox.x0;
const rectHeight = bbox.y1 - bbox.y0;
// First, cover the original text with a solid rectangle.
ctx.fillStyle = coverColor;
ctx.fillRect(bbox.x0, bbox.y0, rectWidth, rectHeight);
// Then, fit and draw the new translated text.
const { fontSize, lines, lineHeight } = fitTextInBox(ctx, translatedText, fontFamily, rectWidth, rectHeight);
ctx.fillStyle = textColor;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.font = `${fontSize}px ${fontFamily}`;
const totalTextHeight = lines.length * lineHeight;
// Calculate starting Y position to center the text block vertically.
let startY = bbox.y0 + (rectHeight - totalTextHeight) / 2 + (lineHeight / 2);
for (const line of lines) {
const centerX = bbox.x0 + rectWidth / 2;
ctx.fillText(line, centerX, startY);
startY += lineHeight;
}
}
} catch (error) {
console.error("An error occurred during image translation:", error);
// Display an error message directly on the canvas for user feedback.
ctx.fillStyle = 'rgba(255, 0, 0, 0.8)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = 'white';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.font = '24px Arial';
ctx.fillText("An error occurred. Check the console for details.", canvas.width / 2, canvas.height / 2);
} finally {
// Step 6: Terminate the Tesseract worker to free up resources.
if (worker) {
console.log('Terminating Tesseract worker.');
await worker.terminate();
}
}
return canvas;
}
Free Image Tool Creator
Can't find the image tool you're looking for? Create one based on your own needs now!
The Image AI Powered Online Translator Creator allows users to upload an image containing text, which it then processes to recognize and translate the text into a different language. This tool utilizes Optical Character Recognition (OCR) to extract the text and a translation API to convert the recognized text from the source language to the target language. Users can customize the appearance of the translated text, including font color and background color. This tool can be particularly useful for travelers needing to translate signs or menus, students translating texts in foreign languages, or anyone looking to quickly and accurately translate printed material from images.