You can edit the below JavaScript code to customize the image tool.
Apply Changes
/**
* Analyzes an image to detect objects, generates a translated title,
* and returns a new canvas with the image and the title.
*
* @param {Image} originalImg The original JavaScript Image object.
* @param {string} targetLanguage The target language for the title ('en', 'ru', 'es', 'de', 'fr'). Defaults to 'en'.
* @param {number} fontSize The font size for the title text in pixels. Defaults to 30.
* @param {string} fontColor The CSS color for the title text. Defaults to 'white'.
* @param {string} position The position of the title bar ('top' or 'bottom'). Defaults to 'bottom'.
* @returns {Promise<HTMLCanvasElement>} A promise that resolves to an HTMLCanvasElement with the image and title.
*/
async function processImage(originalImg, targetLanguage = 'en', fontSize = 30, fontColor = 'white', position = 'bottom') {
// Helper to dynamically load a script and return a promise
const loadScript = (url) => {
return new Promise((resolve, reject) => {
// If script already exists, resolve immediately
if (document.querySelector(`script[src="${url}"]`)) {
return resolve();
}
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);
});
};
// A dictionary for translating UI elements and common object names
const translations = {
// UI text
"ui_loading": { 'en': 'Analyzing, please wait...', 'ru': 'Анализ, подождите...', 'es': 'Analizando, por favor espere...', 'de': 'Analysiere, bitte warten...', 'fr': 'Analyse en cours...' },
"ui_title_prefix": { 'en': 'This image may contain:', 'ru': 'На изображении может быть:', 'es': 'Esta imagen puede contener:', 'de': 'Dieses Bild könnte enthalten:', 'fr': 'Cette image peut contenir :' },
"ui_no_objects": { 'en': 'Could not identify objects', 'ru': 'Не удалось распознать объекты', 'es': 'No se pudieron identificar objetos', 'de': 'Objekte konnten nicht identifiziert werden', 'fr': 'Impossible d\'identifier des objets' },
"ui_error": { 'en': 'An error occurred during analysis', 'ru': 'Произошла ошибка во время анализа', 'es': 'Ocurrió un error durante el análisis', 'de': 'Während der Analyse ist ein Fehler aufgetreten', 'fr': 'Une erreur est survenue lors de l\'analyse' },
// Object names (subset of COCO classes, with articles for English)
'person': { 'en': 'a person', 'ru': 'человек', 'es': 'una persona', 'de': 'eine Person', 'fr': 'une personne' },
'bicycle': { 'en': 'a bicycle', 'ru': 'велосипед', 'es': 'una bicicleta', 'de': 'ein Fahrrad', 'fr': 'un vélo' },
'car': { 'en': 'a car', 'ru': 'машина', 'es': 'un coche', 'de': 'ein Auto', 'fr': 'une voiture' },
'dog': { 'en': 'a dog', 'ru': 'собака', 'es': 'un perro', 'de': 'ein Hund', 'fr': 'un chien' },
'cat': { 'en': 'a cat', 'ru': 'кошка', 'es': 'un gato', 'de': 'eine Katze', 'fr': 'un chat' },
'chair': { 'en': 'a chair', 'ru': 'стул', 'es': 'una silla', 'de': 'ein Stuhl', 'fr': 'une chaise' },
'dining table': { 'en': 'a table', 'ru': 'стол', 'es': 'una mesa', 'de': 'ein Tisch', 'fr': 'une table' },
'book': { 'en': 'a book', 'ru': 'книга', 'es': 'un libro', 'de': 'ein Buch', 'fr': 'un livre' },
'bottle': { 'en': 'a bottle', 'ru': 'бутылка', 'es': 'una botella', 'de': 'eine Flasche', 'fr': 'une bouteille' },
'cup': { 'en': 'a cup', 'ru': 'чашка', 'es': 'una taza', 'de': 'eine Tasse', 'fr': 'une tasse' },
'laptop': { 'en': 'a laptop', 'ru': 'ноутбук', 'es': 'un portátil', 'de': 'ein Laptop', 'fr': 'un ordinateur portable' },
'tv': { 'en': 'a tv', 'ru': 'телевизор', 'es': 'un televisor', 'de': 'ein Fernseher', 'fr': 'une télévision' },
'potted plant': { 'en': 'a potted plant', 'ru': 'растение в горшке', 'es': 'una planta en maceta', 'de': 'eine Topfpflanze', 'fr': 'une plante en pot' },
'bird': { 'en': 'a bird', 'ru': 'птица', 'es': 'un pájaro', 'de': 'ein Vogel', 'fr': 'un oiseau' },
'couch': { 'en': 'a couch', 'ru': 'диван', 'es': 'un sofá', 'de': 'eine Couch', 'fr': 'un canapé' },
};
// Helper to get a translation with a fallback to English, then to the key itself
const getTranslation = (key, lang = 'en') => {
const fallbackLang = 'en';
if (translations[key]) {
return translations[key][lang] || translations[key][fallbackLang] || key;
}
return key;
};
// --- Canvas Setup ---
const titleBarHeight = fontSize * 1.8;
const canvas = document.createElement('canvas');
canvas.width = originalImg.naturalWidth;
canvas.height = originalImg.naturalHeight + titleBarHeight;
const ctx = canvas.getContext('2d');
// Reusable function to draw the image and title bar
const drawCanvasContent = (text) => {
// Determine positions based on the 'position' parameter
const imgY = position === 'top' ? titleBarHeight : 0;
const barY = position === 'top' ? 0 : originalImg.naturalHeight;
// Draw the original image
ctx.drawImage(originalImg, 0, imgY, originalImg.naturalWidth, originalImg.naturalHeight);
// Draw the title bar background
ctx.fillStyle = 'rgba(0, 0, 0, 0.7)';
ctx.fillRect(0, barY, canvas.width, titleBarHeight);
// Configure text style
ctx.fillStyle = fontColor;
ctx.font = `${fontSize}px sans-serif`;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
const textX = canvas.width / 2;
const textY = barY + titleBarHeight / 2;
// Simple text truncation to prevent overflow
const padding = 20;
const maxWidth = canvas.width - padding;
let textToDraw = text;
if (ctx.measureText(textToDraw).width > maxWidth) {
while (ctx.measureText(textToDraw + '...').width > maxWidth && textToDraw.length > 0) {
textToDraw = textToDraw.slice(0, -1);
}
textToDraw += '...';
}
ctx.fillText(textToDraw, textX, textY);
};
// Show initial loading message on the canvas
drawCanvasContent(getTranslation('ui_loading', targetLanguage));
try {
// --- Load External Libraries ---
// Dynamically load TensorFlow.js and the pre-trained COCO-SSD model.
// We use specific versions for stability.
if (!window.tf) await loadScript('https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@3.13.0/dist/tf.min.js');
if (!window.cocoSsd) await loadScript('https://cdn.jsdelivr.net/npm/@tensorflow-models/coco-ssd@2.2.2/dist/coco-ssd.min.js');
// --- Model Inference ---
const model = await cocoSsd.load();
const predictions = await model.detect(originalImg);
let titleText;
if (predictions.length > 0) {
// Get unique object classes detected, up to 5 to keep title concise
const uniqueClasses = [...new Set(predictions.map(p => p.class))].slice(0, 5);
const translatedClasses = uniqueClasses.map(c => getTranslation(c, targetLanguage));
const titlePrefix = getTranslation('ui_title_prefix', targetLanguage);
titleText = `${titlePrefix} ${translatedClasses.join(', ')}`;
} else {
titleText = getTranslation('ui_no_objects', targetLanguage);
}
// --- Final Drawing ---
// Redraw canvas with the final generated title
drawCanvasContent(titleText);
} catch (error) {
console.error("Image processing failed:", error);
// Display an error message on the canvas if something goes wrong
drawCanvasContent(getTranslation('ui_error', targetLanguage));
}
return canvas;
}
Apply Changes