Please bookmark this page to avoid losing your image tool!

Two Photo Language Identifier Tool

(Free & Supports Bulk Upload)

Drag & drop your images here or

The result will appear here...
You can edit the below JavaScript code to customize the image tool.
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;
}

Free Image Tool Creator

Can't find the image tool you're looking for?
Create one based on your own needs now!

Description

The Two Photo Language Identifier Tool uses optical character recognition (OCR) technology to analyze images and identify the written script or language present within them. The tool generates a side-by-side visual comparison, displaying the original uploaded image on one side and a dedicated results panel on the other, which highlights the identified script and the system’s confidence level. This tool is useful for researchers, travelers, or linguists who need to quickly determine the writing system used in historical documents, signs, or foreign text samples.

Leave a Reply

Your email address will not be published. Required fields are marked *