You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, language = 'eng+rus', boxType = 'line', boxColor = '#00FF00', lineWidth = '2', showText = 'true') {
const container = document.createElement('div');
container.style.position = 'relative';
container.style.display = 'inline-block';
const canvas = document.createElement('canvas');
canvas.width = originalImg.width;
canvas.height = originalImg.height;
canvas.style.display = 'block';
canvas.style.maxWidth = '100%';
canvas.style.height = 'auto';
const ctx = canvas.getContext('2d');
ctx.drawImage(originalImg, 0, 0);
container.appendChild(canvas);
const statusDiv = document.createElement('div');
statusDiv.style.position = 'absolute';
statusDiv.style.top = '10px';
statusDiv.style.left = '10px';
statusDiv.style.background = 'rgba(0, 0, 0, 0.75)';
statusDiv.style.color = '#fff';
statusDiv.style.padding = '8px 12px';
statusDiv.style.borderRadius = '6px';
statusDiv.style.fontFamily = 'monospace';
statusDiv.style.fontSize = '14px';
statusDiv.style.zIndex = '10';
statusDiv.style.boxShadow = '0 2px 4px rgba(0,0,0,0.3)';
statusDiv.innerText = 'Initializing Scanner...';
container.appendChild(statusDiv);
(async () => {
try {
statusDiv.innerText = 'Loading OCR Engine...';
// Dynamically inject Tesseract.js if not available
await new Promise((resolve, reject) => {
if (window.Tesseract) return resolve();
let script = document.getElementById('tesseract-js');
if (script) {
script.addEventListener('load', resolve);
script.addEventListener('error', reject);
return;
}
script = document.createElement('script');
script.id = 'tesseract-js';
script.src = 'https://cdn.jsdelivr.net/npm/tesseract.js@5/dist/tesseract.min.js';
script.onload = resolve;
script.onerror = reject;
document.head.appendChild(script);
});
statusDiv.innerText = 'Preparing Engine...';
const worker = await window.Tesseract.createWorker(language, 1, {
logger: m => {
if (m.status === 'recognizing text') {
const progress = Math.round(m.progress * 100);
statusDiv.innerText = `Scanning Imagery: ${progress}%`;
} else {
const statusText = m.status.charAt(0).toUpperCase() + m.status.slice(1);
statusDiv.innerText = `${statusText}...`;
}
}
});
statusDiv.innerText = 'Recognizing Data...';
const { data } = await worker.recognize(canvas);
await worker.terminate();
let itemsToBox = [];
switch (boxType.toLowerCase()) {
case 'word': itemsToBox = data.words; break;
case 'paragraph': itemsToBox = data.paragraphs; break;
case 'block': itemsToBox = data.blocks; break;
case 'line':
default: itemsToBox = data.lines; break;
}
if (!itemsToBox || itemsToBox.length === 0) {
statusDiv.innerText = 'No text boxes found.';
statusDiv.style.background = 'rgba(200, 40, 40, 0.85)';
setTimeout(() => statusDiv.remove(), 4000);
return;
}
ctx.strokeStyle = boxColor;
ctx.lineWidth = parseFloat(lineWidth) || 2;
itemsToBox.forEach(item => {
const bbox = item.bbox;
if (!bbox) return;
// Draw Outline Box
ctx.beginPath();
ctx.rect(bbox.x0, bbox.y0, bbox.x1 - bbox.x0, bbox.y1 - bbox.y0);
ctx.stroke();
// Draw Inner Tint
ctx.fillStyle = boxColor;
ctx.globalAlpha = 0.15;
ctx.fill();
ctx.globalAlpha = 1.0;
// Draw Text Label Box
const text = item.text ? item.text.trim() : '';
if (showText === 'true' && text) {
ctx.font = 'bold 14px sans-serif';
const metrics = ctx.measureText(text);
const tWidth = metrics.width;
const tHeight = 20;
// Prevent label from drawing off-canvas if too close to the top edge
const badgeY = bbox.y0 < tHeight ? bbox.y0 : bbox.y0 - tHeight;
ctx.fillStyle = 'rgba(0, 0, 0, 0.8)';
ctx.fillRect(bbox.x0, badgeY, tWidth + 8, tHeight);
ctx.fillStyle = '#FFFFFF';
ctx.fillText(text, bbox.x0 + 4, badgeY + 14);
}
});
statusDiv.innerText = `Success: ${itemsToBox.length} item(s) identified.`;
statusDiv.style.background = 'rgba(40, 160, 40, 0.85)';
setTimeout(() => statusDiv.remove(), 4000);
} catch (error) {
console.error(error);
statusDiv.innerText = 'Error: ' + error.message;
statusDiv.style.background = 'rgba(200, 40, 40, 0.85)';
}
})();
return container;
}
Apply Changes