Please bookmark this page to avoid losing your image tool!

Image Text Search By Topic 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, searchTopic = "") {
    // 1. Ensure Tesseract.js is loaded for OCR
    if (typeof window.Tesseract === 'undefined') {
        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"));
            document.head.appendChild(script);
        });
    }

    // 2. Perform Optical Character Recognition (OCR)
    // Tesseract.recognize automatically creates and terminates the web worker
    const result = await window.Tesseract.recognize(originalImg, 'eng');
    const { data } = result;
    const words = data.words || [];
    const lines = data.lines || [];

    // 3. Process search filters
    const topicStr = String(searchTopic).toLowerCase().trim();
    const keywords = (topicStr && topicStr !== "all") 
        ? topicStr.split(/\s+/).filter(w => w.length > 0) 
        : [];

    let matchedWords = [];
    if (keywords.length === 0) {
        matchedWords = words; // Match everything if no specific query
    } else {
        matchedWords = words.filter(word => {
            const text = word.text.toLowerCase();
            return keywords.some(k => text.includes(k));
        });
    }

    // 4. Create the main wrapper container
    const container = document.createElement('div');
    container.style.display = 'flex';
    container.style.flexDirection = 'column';
    container.style.gap = '16px';
    container.style.fontFamily = 'system-ui, -apple-system, "Segoe UI", Roboto, sans-serif';
    container.style.boxSizing = 'border-box';
    container.style.width = '100%';

    // 5. Setup Canvas for highlighting
    const canvas = document.createElement('canvas');
    canvas.width = originalImg.width;
    canvas.height = originalImg.height;
    canvas.style.maxWidth = '100%';
    canvas.style.height = 'auto';
    canvas.style.border = '1px solid #ccc';
    canvas.style.borderRadius = '6px';
    canvas.style.boxShadow = '0 4px 6px rgba(0,0,0,0.1)';

    const ctx = canvas.getContext('2d');
    
    // Draw the clean underlying image
    ctx.drawImage(originalImg, 0, 0);

    if (matchedWords.length > 0) {
        // Apply a dark dim overlay to the entire image to make highlights pop
        ctx.fillStyle = 'rgba(0, 0, 0, 0.65)';
        ctx.fillRect(0, 0, canvas.width, canvas.height);

        const strokeWidth = Math.max(2, Math.floor(canvas.width / 400)); // scale stroke for big images
        ctx.strokeStyle = '#00FF00'; // Lime green
        ctx.lineWidth = strokeWidth;

        // Cutout the dim layer & stroke rectangles around matches
        for (const word of matchedWords) {
            const { x0, y0, x1, y1 } = word.bbox;
            const width = x1 - x0;
            const height = y1 - y0;

            // Restoring original pixels via a clip path mask
            ctx.save();
            ctx.beginPath();
            ctx.rect(x0, y0, width, height);
            ctx.clip();
            ctx.drawImage(originalImg, 0, 0);
            ctx.restore();

            // Draw bounding box
            ctx.strokeRect(x0, y0, width, height);
        }
    } else {
        // Overlay communicating no matches found
        ctx.fillStyle = 'rgba(0, 0, 0, 0.8)';
        ctx.fillRect(0, 0, canvas.width, canvas.height);

        ctx.fillStyle = '#ffffff';
        ctx.textAlign = 'center';
        ctx.textBaseline = 'middle';
        const fontSize = Math.max(16, Math.floor(canvas.width / 25));
        ctx.font = `bold ${fontSize}px sans-serif`;
        
        const message = words.length === 0 
            ? 'No readable text detected in image.' 
            : `No text correctly matches: "${searchTopic}"`;
            
        ctx.fillText(message, canvas.width / 2, canvas.height / 2);
    }
    
    container.appendChild(canvas);

    // 6. Extracted Texts Section List Viewer below the image
    const resultsDiv = document.createElement('div');
    resultsDiv.style.backgroundColor = '#f8fafc';
    resultsDiv.style.padding = '16px';
    resultsDiv.style.border = '1px solid #e2e8f0';
    resultsDiv.style.borderRadius = '6px';

    const header = document.createElement('h3');
    header.textContent = `Found Statements (${matchedWords.length > 0 ? (keywords.length > 0 ? "Filtered" : "All") : 0})`;
    header.style.margin = '0 0 12px 0';
    header.style.color = '#334155';
    resultsDiv.appendChild(header);

    const escapeHtml = (str) => {
        return str.replace(/[&<>'"]/g, 
            tag => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', "'": '&#39;', '"': '&quot;' }[tag])
        );
    };

    if (matchedWords.length > 0) {
        const list = document.createElement('ul');
        list.style.margin = '0';
        list.style.paddingLeft = '24px';
        list.style.color = '#475569';
        list.style.maxHeight = '250px';
        list.style.overflowY = 'auto'; // scrollable if many results
        list.style.lineHeight = '1.5';

        // Extract and filter readable lines
        const matchedLines = [];
        for (const line of lines) {
            const lineStr = line.text.trim();
            if (!lineStr) continue;

            if (keywords.length === 0) {
                matchedLines.push(lineStr);
            } else {
                const lowerLine = lineStr.toLowerCase();
                if (keywords.some(k => lowerLine.includes(k))) {
                    matchedLines.push(lineStr);
                }
            }
        }

        for (const lineStr of matchedLines) {
            const li = document.createElement('li');
            li.style.marginBottom = '8px';
            
            let htmlContent = escapeHtml(lineStr);
            if (keywords.length > 0) {
                keywords.forEach(keyword => {
                    const safeKey = escapeHtml(keyword).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
                    const regex = new RegExp(`(${safeKey})`, 'gi');
                    htmlContent = htmlContent.replace(
                        regex, 
                        '<strong style="color:#16a34a; background-color:#dcfce7; padding:0 4px; border-radius:3px;">$1</strong>'
                    );
                });
            }
            
            li.innerHTML = htmlContent;
            list.appendChild(li);
        }
        
        resultsDiv.appendChild(list);
    } else {
        const emptyMsg = document.createElement('p');
        emptyMsg.textContent = 'No matching text to display.';
        emptyMsg.style.margin = '0';
        emptyMsg.style.color = '#94a3b8';
        emptyMsg.style.fontStyle = 'italic';
        resultsDiv.appendChild(emptyMsg);
    }

    container.appendChild(resultsDiv);

    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 Image Text Search By Topic Tool uses Optical Character Recognition (OCR) to identify and extract text from images, allowing users to search for specific keywords or topics within the visual content. Once a topic is entered, the tool highlights the relevant text directly on the image and provides a searchable list of matching text segments below. This tool is useful for quickly locating specific information in scanned documents, infographics, screenshots, or photographs containing text.

Leave a Reply

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