You can edit the below JavaScript code to customize the image tool.
Apply Changes
async function processImage(originalImg, secondPanelColor = "#000000", textColor = "#4caf50") {
// Create wrapper container
const container = document.createElement('div');
container.style.fontFamily = 'system-ui, -apple-system, sans-serif';
container.style.maxWidth = '100%';
container.style.overflow = 'hidden';
container.style.borderRadius = '8px';
container.style.boxShadow = '0 4px 12px rgba(0,0,0,0.15)';
container.style.display = 'inline-block';
// Create our canvas which will have the "Two Photo" layout
const canvas = document.createElement('canvas');
canvas.style.display = 'block';
canvas.style.maxWidth = '100%';
container.appendChild(canvas);
// Determine sensible dimensions to prevent colossal canvas sizes
const MAX_HEIGHT = 600;
let w = originalImg.width;
let h = originalImg.height;
if (h > MAX_HEIGHT) {
w = (MAX_HEIGHT / h) * w;
h = MAX_HEIGHT;
}
// Width is doubled to accommodate the "Two Photo" layout (side-by-side)
canvas.width = w * 2;
canvas.height = Math.max(h, 400);
const ctx = canvas.getContext('2d');
// Utility to render the current visual state
function drawScene(statusText, resultScript = null, confidence = null) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = '#ffffff';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// --- Photo 1: Left Side (Original Image) ---
ctx.drawImage(originalImg, 0, 0, originalImg.width, originalImg.height, 0, 0, w, h);
// --- Photo 2: Right Side (Identified Script Panel) ---
// Draw blurred version of original as background
ctx.save();
ctx.filter = 'blur(10px) brightness(0.6)';
ctx.drawImage(originalImg, 0, 0, originalImg.width, originalImg.height, w, 0, w, h);
ctx.restore();
// Overlay color tint on right panel
ctx.fillStyle = secondPanelColor;
ctx.globalAlpha = 0.75;
ctx.fillRect(w, 0, w, canvas.height);
ctx.globalAlpha = 1.0;
// Divider line in the center
ctx.fillStyle = '#ffffff';
ctx.fillRect(w - 2, 0, 4, canvas.height);
const rightCenterX = w + w / 2;
const rightCenterY = canvas.height / 2;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
if (resultScript) {
// Processing resolved: Map results onto the Right Photo
ctx.fillStyle = '#ffffff';
ctx.font = 'bold 28px sans-serif';
ctx.fillText("Language / Script Identified", rightCenterX, rightCenterY - 40);
ctx.fillStyle = textColor;
ctx.font = 'bold 44px sans-serif';
// Simple string shortening for display cleanliness if needed
ctx.fillText(resultScript.substring(0, 30), rightCenterX, rightCenterY + 15);
if (confidence) {
ctx.fillStyle = '#cccccc';
ctx.font = '18px sans-serif';
ctx.fillText(`Confidence: ${confidence}%`, rightCenterX, rightCenterY + 65);
}
} else {
// Processing ongoing: Draw loading status UI
ctx.fillStyle = '#ffffff';
ctx.font = 'bold 24px sans-serif';
ctx.fillText(statusText, rightCenterX, rightCenterY);
// Simple animated dots
const millis = Date.now();
const dots = '.'.repeat(Math.floor(millis / 500) % 4);
ctx.fillText(dots, rightCenterX, rightCenterY + 30);
}
}
// Animation loop for loading indicator
let isProcessing = true;
let loadingMessage = "Loading Tesseract OCR";
const animate = () => {
if (!isProcessing) return; // Self-terminate
drawScene(loadingMessage);
requestAnimationFrame(animate);
};
requestAnimationFrame(animate);
// Launch detection asynchronously
(async () => {
try {
// Dynamically load Tesseract.js (Optical Character/Script Recognition library)
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);
});
}
loadingMessage = "Initializing Language Engine...";
// Primary strategy: Use Orientation and Script Detection (OSD) engine
const result = await window.Tesseract.recognize(
originalImg,
'osd',
{ logger: m => {
if (m.status) {
loadingMessage = m.status.charAt(0).toUpperCase() + m.status.slice(1);
}
}}
);
isProcessing = false; // Stop animation loop
let scriptName = "Unknown Error";
let conf = 0;
// Traverse typical Tesseract response configurations securely
if (result?.data?.osd?.script_name) {
scriptName = result.data.osd.script_name;
conf = result.data.osd.script_confidence || 0;
} else if (result?.data?.osd?.script) {
scriptName = result.data.osd.script;
conf = result.data.osd.script_confidence || 0;
} else if (result?.data?.script) {
scriptName = result.data.script;
}
drawScene(null, scriptName, typeof conf === 'number' && conf > 0 ? conf.toFixed(1) : null);
} catch (error) {
console.warn("OSD failed natively, executing text extraction heuristic fallback:", error);
try {
// Secondary fallback strategy: Run OCR and use Unicode ranges to detect structural scripts
loadingMessage = "Script recognition fail. Checking raw text...";
const result = await window.Tesseract.recognize(
originalImg,
'eng', // Default OCR engine language
{ logger: m => {
if (m.status) loadingMessage = m.status.charAt(0).toUpperCase() + m.status.slice(1);
}}
);
isProcessing = false;
const text = result.data.text || "";
let detected = 'Unknown / No Text Validated';
let matchLength = 0;
const scriptChecks = [
{ name: 'Latin (English/Euro)', regex: /[a-zA-Z]/g },
{ name: 'Cyrillic (Russian)', regex: /[\u0400-\u04ff]/g },
{ name: 'CJK (Chinese/Japanese/Korean)', regex: /[\u3040-\u30ff\u4e00-\u9fff\uac00-\ud7af]/g },
{ name: 'Arabic', regex: /[\u0600-\u06ff]/g },
{ name: 'Devanagari (Hindi)', regex: /[\u0900-\u097f]/g },
{ name: 'Greek', regex: /[\u0370-\u03ff]/g }
];
for (const check of scriptChecks) {
const matches = text.match(check.regex);
if (matches && matches.length > matchLength) {
matchLength = matches.length;
detected = check.name; // Takes majority presence
}
}
if (matchLength === 0 && text.trim().length > 0) {
detected = 'Unrecognized Script Found';
}
drawScene(null, detected, null);
} catch (err2) {
console.error(err2);
isProcessing = false;
drawScene("Error Identifying Language / Script");
}
}
})();
// Returns immediately while processing completes visibly
return container;
}
Apply Changes