You can edit the below JavaScript code to customize the image tool.
Apply Changes
async function processImage(originalImg, sourceLang = 'eng', targetLang = 'rus') {
/**
* Dynamically loads a script 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) => {
if (document.querySelector(`script[src="${url}"]`)) {
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);
});
};
/**
* Maps Tesseract.js language codes (e.g., 'eng') to API-compatible codes (e.g., 'en').
* @param {string} tesseractCode - The 3-letter language code from Tesseract.
* @returns {string} The 2-letter (or other) language code for the translation API.
*/
const getApiLangCode = (tesseractCode) => {
const map = {
'eng': 'en', 'rus': 'ru', 'deu': 'de', 'fra': 'fr', 'spa': 'es', 'ita': 'it',
'jpn': 'ja', 'chi_sim': 'zh-CN', 'chi_tra': 'zh-TW', 'kor': 'ko', 'por': 'pt',
'ara': 'ar', 'hin': 'hi', 'nld': 'nl', 'swe': 'sv', 'tur': 'tr', 'pol': 'pl'
};
return map[tesseractCode] || tesseractCode.substring(0, 2);
};
/**
* Translates a given text using a free public API.
* @param {string} text - The text to translate.
* @param {string} from - The source language (Tesseract code).
* @param {string} to - The target language (Tesseract code).
* @returns {Promise<string>} The translated text, or the original text on failure.
*/
const translateText = async (text, from, to) => {
if (!text || !text.trim()) {
return "";
}
try {
const sourceApiCode = getApiLangCode(from);
const targetApiCode = getApiLangCode(to);
const url = `https://api.mymemory.translated.net/get?q=${encodeURIComponent(text)}&langpair=${sourceApiCode}|${targetApiCode}`;
const response = await fetch(url);
if (!response.ok) {
console.error("Translation API request failed:", response.statusText);
return text;
}
const data = await response.json();
if (data.responseStatus === 200 && data.responseData.translatedText) {
return data.responseData.translatedText;
} else {
console.error("Translation failed:", data.responseDetails);
return text;
}
} catch (error) {
console.error("Error during translation fetch:", error);
return text;
}
};
// Create a canvas and draw the original image onto it.
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);
try {
// Step 1: Load Tesseract.js library and run OCR
await loadScript('https://cdn.jsdelivr.net/npm/tesseract.js@5/dist/tesseract.min.js');
const worker = await Tesseract.createWorker(sourceLang);
const { data: { lines } } = await worker.recognize(originalImg);
// Step 2 & 3: Translate each line of text and render it on the canvas
const renderingPromises = lines.map(async (line) => {
// Ignore text with low confidence
if (line.confidence < 60 || !line.text.trim()) {
return;
}
const translatedText = await translateText(line.text, sourceLang, targetLang);
if (translatedText && translatedText.toLowerCase() !== line.text.toLowerCase()) {
const { x0, y0, x1, y1 } = line.bbox;
const width = x1 - x0;
const height = y1 - y0;
// Erase original text by drawing a rectangle with a sampled background color
const sampleX = Math.max(0, x0 - 3);
const sampleY = Math.floor(y0 + height / 2);
const sampleColorData = ctx.getImageData(sampleX, sampleY, 1, 1).data;
const bgColor = `rgb(${sampleColorData[0]}, ${sampleColorData[1]}, ${sampleColorData[2]})`;
ctx.fillStyle = bgColor;
ctx.fillRect(x0, y0, width, height);
// Determine a contrasting text color (black or white)
const luminance = (0.299 * sampleColorData[0] + 0.587 * sampleColorData[1] + 0.114 * sampleColorData[2]) / 255;
const textColor = luminance > 0.5 ? 'black' : 'white';
ctx.fillStyle = textColor;
ctx.textBaseline = 'middle';
ctx.textAlign = 'left';
// Dynamically adjust font size to fit the bounding box
let fontSize = height * 0.9;
ctx.font = `bold ${fontSize}px Arial, sans-serif`;
while (ctx.measureText(translatedText).width > width && fontSize > 8) {
fontSize -= 1;
ctx.font = `bold ${fontSize}px Arial, sans-serif`;
}
// Draw the translated text, centered vertically in the original line's box
ctx.fillText(translatedText, x0, y0 + height / 2);
}
});
await Promise.all(renderingPromises);
await worker.terminate();
} catch (error) {
console.error("An error occurred during image translation:", error);
// The function will return the canvas with the original image in case of an error.
}
return canvas;
}
Apply Changes