forks

Creation chat

ClarkZhang
please create a OCR tool page, user can upload an image, and the tool will extract the text from the image
02-25 09:00

登录 后可以评论

Assistant
(HTML code has been generated and updated; see above for the current version.) This OCR tool page includes: 1. A clean, modern UI with responsive design that works on both mobile and desktop 2. Full dark/light mode support with theme toggle button 3. Image upload functionality with preview 4. Tesseract.js integration for client-side OCR processing 5. Progress tracking during OCR processing 6. Text extraction display with copy functionality 7. User-friendly instructions and notes 8. Error handling and user feedback 9. Console logging for debugging purposes The tool works entirely in the browser - no images are uploaded to any server. It supports both Chinese and English text recognition. First-time language package loading may take longer, but subsequent uses will be faster. To use the tool: 1. Upload an image using the drag-and-drop area or file selector 2. Wait for the OCR processing to complete (progress shown in real-time) 3. View the extracted text in the results area 4. Copy the text to your clipboard with the "Copy Text" button The console in the bottom-right of the preview shows detailed logs of the OCR process. You can copy these logs and paste them back into the chat for debugging if needed.
▼ Code
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Image to Text OCR Tool</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <script>tailwind.config = { darkMode: 'class' }</script>
</head>
<body class="min-h-screen bg-slate-50 dark:bg-slate-900 text-slate-900 dark:text-slate-100">
    <!-- Theme toggle button -->
    <button id="theme-toggle-btn" class="fixed top-4 right-4 z-10 p-2 rounded-md hover:bg-gray-200 dark:hover:bg-gray-700 text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100 transition-colors flex items-center justify-center" aria-label="Toggle theme" onclick="toggleTheme()">
        <svg id="icon-moon" class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true"><path d="M21.752 15.002A9.72 9.72 0 0 1 18 15.75c-5.385 0-9.75-4.365-9.75-9.75 0-1.33.266-2.597.748-3.752A9.753 9.753 0 0 0 3 11.25C3 16.635 7.365 21 12.75 21a9.753 9.753 0 0 0 9.002-5.998z"/></svg>
        <svg id="icon-sun" class="w-5 h-5" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24" aria-hidden="true" style="display:none"><circle cx="12" cy="12" r="4"></circle><path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M6.34 17.66l-1.41 1.41M19.07 4.93l-1.41 1.41"></path></svg>
    </button>
    <script>
        function toggleTheme(){ var el=document.documentElement; var isDark=!el.classList.contains('dark'); el.classList.toggle('dark',isDark); localStorage.setItem('theme',isDark?'dark':'light'); applyTheme(isDark); }
        function applyTheme(isDark){ document.getElementById('icon-moon').style.display=isDark?'none':'block'; document.getElementById('icon-sun').style.display=isDark?'block':'none'; }
        document.addEventListener('DOMContentLoaded',function(){ var saved=localStorage.getItem('theme'); var isDark=saved==='dark'||(!saved&&window.matchMedia('(prefers-color-scheme: dark)').matches); document.documentElement.classList.toggle('dark',isDark); applyTheme(isDark); });
    </script>

    <div class="container mx-auto px-4 py-12 max-w-4xl">
        <header class="text-center mb-12">
            <h1 class="text-3xl md:text-4xl font-bold text-slate-900 dark:text-slate-100 mb-3">Image to Text OCR Tool</h1>
            <p class="text-lg text-slate-700 dark:text-slate-300 max-w-2xl mx-auto">
                Upload an image and extract text from it using advanced OCR technology. Supports both Chinese and English.
            </p>
        </header>

        <main>
            <div class="bg-white dark:bg-slate-800 rounded-xl shadow-lg p-6 mb-8 border border-slate-200 dark:border-slate-700">
                <div class="mb-6">
                    <label class="block text-slate-700 dark:text-slate-300 font-medium mb-2" for="image-upload">
                        Upload Image
                    </label>
                    <div class="flex items-center justify-center w-full">
                        <label for="image-upload" class="flex flex-col items-center justify-center w-full h-64 border-2 border-dashed rounded-xl cursor-pointer border-slate-300 dark:border-slate-600 hover:border-blue-500 dark:hover:border-blue-400 transition-colors bg-slate-50 dark:bg-slate-700/50">
                            <div class="flex flex-col items-center justify-center pt-5 pb-6">
                                <svg class="w-10 h-10 mb-3 text-slate-400 dark:text-slate-500" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
                                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"></path>
                                </svg>
                                <p class="mb-2 text-sm text-slate-500 dark:text-slate-400">
                                    <span class="font-semibold">Click to upload</span> or drag and drop
                                </p>
                                <p class="text-xs text-slate-500 dark:text-slate-400">
                                    PNG, JPG, JPEG (MAX. 10MB)
                                </p>
                            </div>
                            <input id="image-upload" type="file" class="hidden" accept="image/*" />
                        </label>
                    </div>
                </div>

                <div id="image-preview-container" class="hidden mb-6">
                    <h3 class="text-lg font-medium text-slate-800 dark:text-slate-200 mb-3">Image Preview</h3>
                    <div class="flex justify-center">
                        <img id="image-preview" src="" alt="Preview" class="max-h-64 rounded-lg shadow-md">
                    </div>
                </div>

                <div id="progress-container" class="hidden mb-6">
                    <h3 class="text-lg font-medium text-slate-800 dark:text-slate-200 mb-3">Processing Image</h3>
                    <div class="w-full bg-slate-200 dark:bg-slate-700 rounded-full h-2.5">
                        <div id="progress-bar" class="bg-blue-600 dark:bg-blue-500 h-2.5 rounded-full" style="width: 0%"></div>
                    </div>
                    <p id="progress-status" class="text-slate-600 dark:text-slate-400 text-sm mt-2">Initializing OCR...</p>
                </div>

                <div id="result-container" class="hidden">
                    <div class="flex justify-between items-center mb-3">
                        <h3 class="text-lg font-medium text-slate-800 dark:text-slate-200">Extracted Text</h3>
                        <button id="copy-button" class="text-sm bg-blue-600 hover:bg-blue-700 dark:bg-blue-500 dark:hover:bg-blue-600 text-white px-3 py-1.5 rounded-lg transition-colors">
                            Copy Text
                        </button>
                    </div>
                    <div class="relative">
                        <textarea id="result-text" class="w-full h-48 p-4 bg-slate-50 dark:bg-slate-700 text-slate-800 dark:text-slate-200 border border-slate-300 dark:border-slate-600 rounded-lg resize-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500" readonly></textarea>
                    </div>
                </div>
            </div>

            <div class="bg-white dark:bg-slate-800 rounded-xl shadow-lg p-6 border border-slate-200 dark:border-slate-700">
                <h2 class="text-xl font-semibold text-slate-900 dark:text-slate-100 mb-4">How to Use This Tool</h2>
                <ul class="space-y-3 text-slate-700 dark:text-slate-300">
                    <li class="flex items-start">
                        <span class="text-blue-600 dark:text-blue-400 font-bold mr-2">1.</span>
                        <span>Click the upload area or drag and drop an image file</span>
                    </li>
                    <li class="flex items-start">
                        <span class="text-blue-600 dark:text-blue-400 font-bold mr-2">2.</span>
                        <span>Wait for the OCR processing to complete (may take 10-30 seconds for first use)</span>
                    </li>
                    <li class="flex items-start">
                        <span class="text-blue-600 dark:text-blue-400 font-bold mr-2">3.</span>
                        <span>Review the extracted text in the result box</span>
                    </li>
                    <li class="flex items-start">
                        <span class="text-blue-600 dark:text-blue-400 font-bold mr-2">4.</span>
                        <span>Click "Copy Text" to copy the result to your clipboard</span>
                    </li>
                </ul>
                <div class="mt-4 p-4 bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-800 rounded-lg">
                    <p class="text-amber-700 dark:text-amber-300 text-sm">
                        <span class="font-semibold">Note:</span> First-time language package loading may take longer. Subsequent uses will be faster.
                    </p>
                </div>
            </div>
        </main>

        <footer class="mt-12 text-center text-slate-600 dark:text-slate-400 text-sm">
            <p>© 2023 OCR Text Extraction Tool. All processing happens in your browser - no images are uploaded to any server.</p>
        </footer>
    </div>

    <!-- Custom modal for messages -->
    <div id="custom-modal" class="fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4 hidden" aria-hidden="true">
        <div class="rounded-xl bg-white dark:bg-slate-800 p-6 shadow-xl max-w-sm w-full border border-slate-200 dark:border-slate-700">
            <p id="custom-modal-msg" class="text-slate-700 dark:text-slate-200 mb-4"></p>
            <button type="button" onclick="hideModal()" class="w-full rounded-lg bg-blue-600 px-4 py-2 text-white hover:bg-blue-700 dark:bg-blue-500 dark:hover:bg-blue-600">OK</button>
        </div>
    </div>
    <script>
        function showModal(msg){ 
            var el=document.getElementById('custom-modal'); 
            document.getElementById('custom-modal-msg').textContent=msg||''; 
            el.classList.remove('hidden'); 
        }
        function hideModal(){ 
            document.getElementById('custom-modal').classList.add('hidden'); 
        }
    </script>

    <!-- Tesseract.js for OCR -->
    <script src="https://cdn.jsdelivr.net/npm/tesseract.js@4/dist/tesseract.min.js"></script>
    
    <script>
        // DOM Elements
        const imageUpload = document.getElementById('image-upload');
        const imagePreviewContainer = document.getElementById('image-preview-container');
        const imagePreview = document.getElementById('image-preview');
        const progressContainer = document.getElementById('progress-container');
        const progressBar = document.getElementById('progress-bar');
        const progressStatus = document.getElementById('progress-status');
        const resultContainer = document.getElementById('result-container');
        const resultText = document.getElementById('result-text');
        const copyButton = document.getElementById('copy-button');

        // Handle image upload
        imageUpload.addEventListener('change', function(e) {
            const file = e.target.files[0];
            if (!file) return;

            // Validate file type
            if (!file.type.match('image.*')) {
                showModal('Please select a valid image file (PNG, JPG, JPEG)');
                return;
            }

            // Preview image
            const reader = new FileReader();
            reader.onload = function(event) {
                imagePreview.src = event.target.result;
                imagePreviewContainer.classList.remove('hidden');
                
                // Reset previous results
                resultContainer.classList.add('hidden');
                progressContainer.classList.add('hidden');
                
                // Process image with OCR
                processImageWithOCR(event.target.result);
            };
            reader.readAsDataURL(file);
        });

        // Process image with Tesseract.js
        function processImageWithOCR(imageSrc) {
            // Show progress container
            progressContainer.classList.remove('hidden');
            progressBar.style.width = '0%';
            progressStatus.textContent = 'Initializing OCR...';
            
            console.log('Starting OCR processing');
            
            Tesseract.recognize(
                imageSrc,
                'chi_sim+eng', // Language for Chinese and English
                { 
                    logger: (m) => {
                        console.log('OCR Progress:', m);
                        if (m.status === 'loading tesseract core') {
                            progressStatus.textContent = 'Loading OCR engine...';
                        } else if (m.status === 'initializing api') {
                            progressStatus.textContent = 'Initializing OCR API...';
                        } else if (m.status === 'loading language traineddata') {
                            progressStatus.textContent = 'Loading language data (may take a moment for first use)...';
                        } else if (m.status === 'recognizing text') {
                            const progress = Math.min(99, Math.floor(m.progress * 100));
                            progressBar.style.width = `${progress}%`;
                            progressStatus.textContent = `Recognizing text... ${progress}%`;
                        }
                    }
                }
            ).then(result => {
                console.log('OCR completed successfully');
                progressBar.style.width = '100%';
                progressStatus.textContent = 'OCR completed!';
                
                // Show results
                resultText.value = result.data.text;
                resultContainer.classList.remove('hidden');
                
                // Hide progress after a delay
                setTimeout(() => {
                    progressContainer.classList.add('hidden');
                }, 1500);
            }).catch(err => {
                console.error('OCR Error:', err);
                progressStatus.textContent = 'Error occurred during OCR processing';
                showModal('OCR processing failed. Please try another image.');
            });
        }

        // Copy text to clipboard
        copyButton.addEventListener('click', function() {
            resultText.select();
            document.execCommand('copy');
            
            // Show feedback
            const originalText = copyButton.textContent;
            copyButton.textContent = 'Copied!';
            setTimeout(() => {
                copyButton.textContent = originalText;
            }, 2000);
        });
    </script>
</body>
</html>
02-25 09:02

登录 后可以评论

Comments

登录 后可以评论