You can edit the below JavaScript code to customize the image tool.
Apply Changes
async function processImage(originalImg, searchText = '') {
// Create main container for the result
const container = document.createElement('div');
container.style.display = 'flex';
container.style.flexDirection = 'column';
container.style.alignItems = 'center';
container.style.width = '100%';
container.style.boxSizing = 'border-box';
// Create canvas to render image and highlights
const canvas = document.createElement('canvas');
canvas.width = originalImg.naturalWidth || originalImg.width;
canvas.height = originalImg.naturalHeight || originalImg.height;
canvas.style.maxWidth = '100%';
canvas.style.height = 'auto';
canvas.style.marginBottom = '20px';
canvas.style.boxShadow = '0 4px 6px rgba(0,0,0,0.1)';
const ctx = canvas.getContext('2d');
ctx.drawImage(originalImg, 0, 0);
container.appendChild(canvas);
// Create a text container for displaying extracted text lists
const txtContainer = document.createElement('div');
txtContainer.style.width = '100%';
txtContainer.style.padding = '15px';
txtContainer.style.backgroundColor = '#f8f9fa';
txtContainer.style.border = '1px solid #dee2e6';
txtContainer.style.borderRadius = '5px';
txtContainer.style.fontFamily = 'system-ui, -apple-system, sans-serif';
txtContainer.style.maxHeight = '300px';
txtContainer.style.overflowY = 'auto';
txtContainer.style.boxSizing = 'border-box';
const h3 = document.createElement('h3');
h3.style.margin = '0 0 10px 0';
h3.style.fontSize = '1.1rem';
h3.style.color = '#333';
h3.textContent = 'Processing image, please wait...';
txtContainer.appendChild(h3);
const list = document.createElement('ul');
list.style.margin = '0';
list.style.paddingLeft = '20px';
list.style.color = '#444';
txtContainer.appendChild(list);
container.appendChild(txtContainer);
const search = searchText.toString().trim().toLowerCase();
// Dynamically load Tesseract.js for OCR functionality
if (!window.Tesseract) {
await new Promise((resolve, reject) => {
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;
document.head.appendChild(script);
});
}
try {
const { data } = await window.Tesseract.recognize(canvas, 'eng');
const lines = data.lines || [];
ctx.lineWidth = Math.max(1, Math.min(4, canvas.width * 0.003));
ctx.strokeStyle = '#ef4444'; // Red outline
ctx.fillStyle = 'rgba(239, 68, 68, 0.2)'; // semi-transparent red fill
let matchCount = 0;
const searchWords = search.split(/\s+/);
h3.textContent = 'Rendering matches...';
for (const line of lines) {
const lineText = line.text.trim();
if (lineText.length === 0) continue;
// Check if the current line includes the search string
if (!search || lineText.toLowerCase().includes(search)) {
matchCount++;
// Draw bounding boxes on canvas
// - Empty search: Highlight everything word by word
// - Single-word search: Highlight precise matching words
// - Multi-word phrase search: Highlight entire matched line boundary
if (!search) {
for (const word of line.words) {
const { x0, y0, x1, y1 } = word.bbox;
ctx.strokeRect(x0, y0, x1 - x0, y1 - y0);
ctx.fillRect(x0, y0, x1 - x0, y1 - y0);
}
} else if (searchWords.length === 1) {
for (const word of line.words) {
if (word.text.toLowerCase().includes(search)) {
const { x0, y0, x1, y1 } = word.bbox;
ctx.strokeRect(x0, y0, x1 - x0, y1 - y0);
ctx.fillRect(x0, y0, x1 - x0, y1 - y0);
}
}
} else {
const { x0, y0, x1, y1 } = line.bbox;
ctx.strokeRect(x0, y0, x1 - x0, y1 - y0);
ctx.fillRect(x0, y0, x1 - x0, y1 - y0);
}
// Add to list visualization
const li = document.createElement('li');
li.style.marginBottom = '8px';
li.style.lineHeight = '1.4';
li.style.wordBreak = 'break-word';
if (search) {
const escapedSearch = search.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
const regex = new RegExp(`(${escapedSearch})`, 'gi');
const highlighted = lineText.replace(regex, '<mark style="background-color: #fef08a; padding: 0 2px; border-radius: 2px;">$1</mark>');
li.innerHTML = `${highlighted} <span style="color: #888; font-size: 0.85em;">(Confidence: ${Math.round(line.confidence)}%)</span>`;
} else {
li.textContent = `${lineText} `;
const confSpan = document.createElement('span');
confSpan.style.color = '#888';
confSpan.style.fontSize = '0.85em';
confSpan.textContent = `(Confidence: ${Math.round(line.confidence)}%)`;
li.appendChild(confSpan);
}
list.appendChild(li);
}
}
if (matchCount === 0) {
const noMatch = document.createElement('p');
noMatch.textContent = search ? `No matches found for "${searchText}".` : 'No text recognized.';
noMatch.style.color = '#666';
noMatch.style.fontStyle = 'italic';
noMatch.style.margin = '0';
list.replaceWith(noMatch);
h3.textContent = 'Found Text:';
} else {
h3.textContent = search ? `Found Matches (${matchCount}):` : `Found Text (${matchCount} lines):`;
}
} catch (e) {
console.error("OCR Error:", e);
const errP = document.createElement('p');
errP.style.color = '#dc3545';
errP.style.margin = '0';
errP.textContent = 'An error occurred during text recognition. Please try an image with clearer text.';
list.replaceWith(errP);
h3.textContent = 'Evaluation Failed';
}
return container;
}
Apply Changes