You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, language = 'eng', minHeightRatio = 0.6) {
// Create Main Container Wrapper
const container = document.createElement('div');
container.style.fontFamily = 'system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif';
container.style.textAlign = 'center';
container.style.padding = '30px';
container.style.backgroundColor = '#ffffff';
container.style.border = '1px solid #e0e0e0';
container.style.borderRadius = '12px';
container.style.boxShadow = '0 8px 24px rgba(0,0,0,0.05)';
container.style.maxWidth = '600px';
container.style.margin = '0 auto';
// Heading
const heading = document.createElement('h2');
heading.innerText = 'Movie ID / Film Identifier';
heading.style.marginTop = '0';
heading.style.marginBottom = '20px';
heading.style.color = '#333';
container.appendChild(heading);
// Display Original Image
const imgCopy = new Image();
imgCopy.src = originalImg.src;
imgCopy.style.maxWidth = '100%';
imgCopy.style.maxHeight = '350px';
imgCopy.style.objectFit = 'contain';
imgCopy.style.borderRadius = '8px';
imgCopy.style.boxShadow = '0 4px 12px rgba(0,0,0,0.1)';
container.appendChild(imgCopy);
// Status Text
const status = document.createElement('div');
status.style.margin = '20px 0';
status.style.fontSize = '16px';
status.style.fontWeight = '500';
status.style.color = '#666';
status.innerText = 'Initializing OCR Engine...';
container.appendChild(status);
// Input Container for Detected Text
const inputContainer = document.createElement('div');
inputContainer.style.marginTop = '15px';
inputContainer.style.display = 'none';
const label = document.createElement('label');
label.innerText = 'Extracted Movie Title:';
label.style.display = 'block';
label.style.marginBottom = '8px';
label.style.fontWeight = 'bold';
label.style.color = '#444';
inputContainer.appendChild(label);
const titleInput = document.createElement('input');
titleInput.type = 'text';
titleInput.style.padding = '12px';
titleInput.style.fontSize = '18px';
titleInput.style.width = '100%';
titleInput.style.boxSizing = 'border-box';
titleInput.style.textAlign = 'center';
titleInput.style.border = '2px solid #ccc';
titleInput.style.borderRadius = '6px';
titleInput.style.outline = 'none';
titleInput.style.transition = 'border-color 0.2s';
titleInput.onfocus = () => { titleInput.style.borderColor = '#01b4e4'; };
titleInput.onblur = () => { titleInput.style.borderColor = '#ccc'; };
inputContainer.appendChild(titleInput);
container.appendChild(inputContainer);
// Action Buttons Container
const actionContainer = document.createElement('div');
actionContainer.style.marginTop = '25px';
actionContainer.style.display = 'none'; // Hidden until ready
actionContainer.style.justifyContent = 'center';
actionContainer.style.gap = '15px';
actionContainer.style.flexWrap = 'wrap';
// Helper function to create stylish search buttons
function createSearchBtn(text, bgColor, fgColor, getUrlFn) {
const btn = document.createElement('button');
btn.innerText = text;
btn.style.padding = '12px 24px';
btn.style.backgroundColor = bgColor;
btn.style.color = fgColor;
btn.style.border = 'none';
btn.style.borderRadius = '6px';
btn.style.fontWeight = 'bold';
btn.style.cursor = 'pointer';
btn.style.fontSize = '15px';
btn.style.transition = 'opacity 0.2s, transform 0.1s';
btn.onmouseover = () => { btn.style.opacity = '0.85'; };
btn.onmouseout = () => { btn.style.opacity = '1'; };
btn.onmousedown = () => { btn.style.transform = 'scale(0.96)'; };
btn.onmouseup = () => { btn.style.transform = 'scale(1)'; };
btn.onclick = () => {
const val = titleInput.value.trim();
if(val) {
window.open(getUrlFn(val), '_blank');
} else {
alert('Please enter a movie title to search.');
}
};
return btn;
}
// Generate TMDB, IMDB, and Google search buttons
const tmdbBtn = createSearchBtn('Search TMDB', '#01b4e4', 'white', val => `https://www.themoviedb.org/search?query=${encodeURIComponent(val)}`);
const imdbBtn = createSearchBtn('Search IMDB', '#f5c518', 'black', val => `https://www.imdb.com/find?q=${encodeURIComponent(val)}&s=tt`);
const googleBtn = createSearchBtn('Google Search', '#ea4335', 'white', val => `https://www.google.com/search?q=${encodeURIComponent(val + ' movie')}`);
actionContainer.appendChild(tmdbBtn);
actionContainer.appendChild(imdbBtn);
actionContainer.appendChild(googleBtn);
container.appendChild(actionContainer);
// Background Processing Logic Un-blocking the UI thread
(async () => {
try {
// 1. Draw image to canvas to ensure predictable internal format mapping
const canvas = document.createElement('canvas');
const width = originalImg.naturalWidth || originalImg.width || 400;
const height = originalImg.naturalHeight || originalImg.height || 600;
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext('2d');
ctx.drawImage(originalImg, 0, 0, width, height);
// 2. Dynamically Import Tesseract JS
if (!window.Tesseract) {
await new Promise((resolve, reject) => {
const script = document.createElement('script');
script.src = 'https://unpkg.com/tesseract.js@v4.1.1/dist/tesseract.min.js';
script.onload = resolve;
script.onerror = () => reject(new Error('Failed to load Tesseract.js from CDN.'));
document.head.appendChild(script);
});
}
// 3. Process the image for text
const result = await window.Tesseract.recognize(
canvas,
language,
{
logger: m => {
if (m.status === 'recognizing text') {
status.innerText = `Extracting Text: ${Math.round(m.progress * 100)}%`;
} else {
status.innerText = `Engine Status: ${m.status}...`;
}
}
}
);
const data = result.data;
// 4. Heuristic Approach based on poster layout logic:
// The movie title is typically the largest text present on the image poster.
let maxLineHeight = 0;
let titleLines = [];
if (data.lines && data.lines.length > 0) {
// Find maximum height of any line consisting of alphanumeric characters
data.lines.forEach(line => {
const height = line.bbox.y1 - line.bbox.y0;
const cleanText = line.text.replace(/[^a-zA-Z0-9]/g, '');
if (cleanText.length > 0 && height > maxLineHeight) {
maxLineHeight = height;
}
});
// Map all text within 'minHeightRatio' (e.g. 60%) to be considered title text parts
data.lines.forEach(line => {
const height = line.bbox.y1 - line.bbox.y0;
const cleanText = line.text.replace(/[^a-zA-Z0-9]/g, '');
if (cleanText.length > 0 && height >= maxLineHeight * minHeightRatio) {
titleLines.push(line);
}
});
}
// Sort structurally by vertical height to preserve word-order context
titleLines.sort((a, b) => a.bbox.y0 - b.bbox.y0);
// Construct final formatted sentence
let extractedTitle = titleLines.map(l => l.text.trim()).join(' ');
extractedTitle = extractedTitle.replace(/\s+/g, ' ').trim();
if (!extractedTitle) {
extractedTitle = "";
status.innerText = "Done! No clear large title text detected. You can enter one manually below.";
status.style.color = '#e4a101';
} else {
status.innerText = "Done! You can confirm or edit the extracted title below.";
status.style.color = '#27ae60';
}
titleInput.value = extractedTitle;
inputContainer.style.display = 'block';
actionContainer.style.display = 'flex';
} catch (error) {
status.innerText = `Error processing image: ${error.message}`;
status.style.color = '#e74c3c';
}
})();
return container;
}
Apply Changes