Download ocrpro.html from joermd/translate: direct link, hf CLI and curl.
- Browser
- Download file 29.8 kB
-
https://huggingface.co/spaces/joermd/translate/resolve/main/ocrpro.html
- Command line
-
hf download hf://spaces/joermd/translate/ocrpro.html
-
curl -L -o ocrpro.html https://huggingface.co/spaces/joermd/translate/resolve/main/ocrpro.html
29.8 kB
| <html lang="ar" dir="rtl"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>موندو لينجوا - نظام OCR</title> | |
| <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet"> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.4.120/pdf.min.js"></script> | |
| <style> | |
| body { | |
| font-family: Arial, sans-serif; | |
| margin: 0; | |
| padding: 20px; | |
| background-color: #f8f9fa; | |
| } | |
| .header { | |
| background-color: #3b82f6; | |
| color: white; | |
| padding: 15px; | |
| border-radius: 10px; | |
| margin-bottom: 20px; | |
| text-align: center; | |
| } | |
| .container { | |
| max-width: 800px; | |
| margin: 0 auto; | |
| } | |
| .card { | |
| background-color: white; | |
| border-radius: 10px; | |
| box-shadow: 0 2px 5px rgba(0,0,0,0.1); | |
| padding: 20px; | |
| margin-bottom: 20px; | |
| } | |
| .pdf-grid { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); | |
| gap: 10px; | |
| margin-top: 15px; | |
| } | |
| .pdf-page { | |
| border: 1px solid #ddd; | |
| border-radius: 5px; | |
| padding: 5px; | |
| position: relative; | |
| cursor: pointer; | |
| transition: all 0.2s; | |
| } | |
| .pdf-page:hover { | |
| transform: translateY(-3px); | |
| box-shadow: 0 3px 10px rgba(0,0,0,0.1); | |
| } | |
| .pdf-page.selected { | |
| border: 2px solid #3b82f6; | |
| } | |
| .pdf-page img { | |
| width: 100%; | |
| height: auto; | |
| border-radius: 3px; | |
| } | |
| .page-number { | |
| position: absolute; | |
| bottom: 0; | |
| left: 0; | |
| right: 0; | |
| background-color: rgba(0,0,0,0.6); | |
| color: white; | |
| text-align: center; | |
| font-size: 12px; | |
| padding: 2px; | |
| } | |
| .btn-primary { | |
| background-color: #3b82f6; | |
| border-color: #3b82f6; | |
| } | |
| .btn-success { | |
| background-color: #10b981; | |
| border-color: #10b981; | |
| } | |
| .result-text { | |
| max-height: 300px; | |
| overflow-y: auto; | |
| white-space: pre-wrap; | |
| direction: rtl; | |
| border: 1px solid #ddd; | |
| padding: 10px; | |
| border-radius: 5px; | |
| background-color: #f8f9fa; | |
| } | |
| .spinner-border { | |
| width: 1.5rem; | |
| height: 1.5rem; | |
| margin-left: 0.5rem; | |
| } | |
| .logo { | |
| font-weight: bold; | |
| font-size: 24px; | |
| display: inline-block; | |
| margin-bottom: 5px; | |
| } | |
| .logo span { | |
| color: #bfdbfe; | |
| } | |
| .stats-badge { | |
| background-color: #3b82f6; | |
| color: white; | |
| font-size: 14px; | |
| padding: 5px 10px; | |
| border-radius: 20px; | |
| margin-right: 10px; | |
| } | |
| .stats-container { | |
| display: flex; | |
| align-items: center; | |
| margin-bottom: 15px; | |
| } | |
| .page-preview { | |
| margin-bottom: 10px; | |
| border: 1px solid #ddd; | |
| border-radius: 5px; | |
| padding: 10px; | |
| } | |
| .page-preview h4 { | |
| background-color: #f0f8ff; | |
| padding: 5px; | |
| border-radius: 3px; | |
| margin-bottom: 10px; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <div class="header"> | |
| <div class="logo">مـوندو <span>لينجـوا</span></div> | |
| <h1>نظام التعرف الضوئي على النصوص</h1> | |
| <p class="mb-0">استخراج النصوص من الصور والملفات متعددة الصفحات</p> | |
| </div> | |
| <!-- بطاقة الإحصائيات --> | |
| <div class="card" id="statsCard"> | |
| <h3>إحصائيات النظام</h3> | |
| <div class="stats-container"> | |
| <div class="stats-badge"> | |
| عدد الصفحات المعالجة: <span id="ocrCounter">0</span> | |
| </div> | |
| <div class="stats-badge"> | |
| تاريخ آخر معالجة: <span id="lastOcrDate">-</span> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- بطاقة تحميل الملف --> | |
| <div class="card"> | |
| <h3>تحميل الملف</h3> | |
| <div class="mb-3"> | |
| <input type="file" class="form-control" id="fileInput" accept=".pdf,.jpg,.jpeg,.png"> | |
| <div class="form-text">يمكنك تحميل ملف PDF (حتى 100 صفحة) أو صورة</div> | |
| </div> | |
| <button id="processBtn" class="btn btn-primary">معالجة الملف</button> | |
| </div> | |
| <!-- عرض حالة المعالجة --> | |
| <div id="processingStatus" class="card d-none"> | |
| <h3>حالة المعالجة</h3> | |
| <div class="alert alert-info"> | |
| <div class="d-flex align-items-center"> | |
| <div class="spinner-border text-primary" role="status"></div> | |
| <span id="statusText" class="ms-2">جاري معالجة الملف...</span> | |
| </div> | |
| </div> | |
| <div class="progress mt-2"> | |
| <div id="progressBar" class="progress-bar" role="progressbar" style="width: 0%"></div> | |
| </div> | |
| </div> | |
| <!-- عرض صفحات PDF --> | |
| <div id="pdfPagesCard" class="card d-none"> | |
| <h3>صفحات الملف</h3> | |
| <p>اختر الصفحات التي تريد معالجتها (انقر للتحديد)</p> | |
| <div class="mb-3"> | |
| <button id="selectAllBtn" class="btn btn-sm btn-outline-primary me-2">تحديد الكل</button> | |
| <button id="deselectAllBtn" class="btn btn-sm btn-outline-secondary">إلغاء تحديد الكل</button> | |
| </div> | |
| <div id="pdfPagesContainer" class="pdf-grid"></div> | |
| <div class="mt-3"> | |
| <button id="extractImagesBtn" class="btn btn-success me-2">تحويل إلى صور</button> | |
| <button id="extractTextBtn" class="btn btn-primary">استخراج النص</button> | |
| </div> | |
| </div> | |
| <!-- عرض النتائج --> | |
| <div id="resultsCard" class="card d-none"> | |
| <h3>النص المستخرج</h3> | |
| <div id="resultPreview"></div> | |
| <div id="resultText" class="result-text mt-3"> | |
| لم يتم استخراج نص بعد. | |
| </div> | |
| <div class="mt-3"> | |
| <button id="copyTextBtn" class="btn btn-outline-primary me-2">نسخ النص</button> | |
| <button id="downloadTextBtn" class="btn btn-success me-2">تنزيل النص</button> | |
| <button id="downloadWordBtn" class="btn btn-success">تنزيل النص إلى Word</button> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| // تهيئة PDF.js | |
| pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.4.120/pdf.worker.min.js'; | |
| // إعدادات API4AI OCR | |
| const RAPIDAPI_KEY = 'eb11693cddmshb8bd157e05b74acp1f6aa4jsn4369fa546e55'; | |
| const OCR_API_URL = 'https://ocr43.p.rapidapi.com/v1/results'; | |
| // متغيرات عامة | |
| let documentPages = []; | |
| let selectedPages = []; | |
| let extractedTexts = []; | |
| let extractedPageNumbers = []; | |
| let ocrPagesCount = 0; // عداد لعدد الصفحات المعالجة | |
| // استرداد العداد من localStorage عند تحميل الصفحة | |
| document.addEventListener('DOMContentLoaded', function() { | |
| const savedCount = localStorage.getItem('ocrPagesCount'); | |
| const lastDate = localStorage.getItem('lastOcrDate'); | |
| if (savedCount) { | |
| ocrPagesCount = parseInt(savedCount); | |
| document.getElementById('ocrCounter').textContent = ocrPagesCount; | |
| } | |
| if (lastDate) { | |
| document.getElementById('lastOcrDate').textContent = lastDate; | |
| } | |
| }); | |
| // عناصر DOM | |
| const fileInput = document.getElementById('fileInput'); | |
| const processBtn = document.getElementById('processBtn'); | |
| const processingStatus = document.getElementById('processingStatus'); | |
| const statusText = document.getElementById('statusText'); | |
| const progressBar = document.getElementById('progressBar'); | |
| const pdfPagesCard = document.getElementById('pdfPagesCard'); | |
| const pdfPagesContainer = document.getElementById('pdfPagesContainer'); | |
| const selectAllBtn = document.getElementById('selectAllBtn'); | |
| const deselectAllBtn = document.getElementById('deselectAllBtn'); | |
| const extractImagesBtn = document.getElementById('extractImagesBtn'); | |
| const extractTextBtn = document.getElementById('extractTextBtn'); | |
| const resultsCard = document.getElementById('resultsCard'); | |
| const resultText = document.getElementById('resultText'); | |
| const resultPreview = document.getElementById('resultPreview'); | |
| const copyTextBtn = document.getElementById('copyTextBtn'); | |
| const downloadTextBtn = document.getElementById('downloadTextBtn'); | |
| const downloadWordBtn = document.getElementById('downloadWordBtn'); | |
| const ocrCounter = document.getElementById('ocrCounter'); | |
| const lastOcrDate = document.getElementById('lastOcrDate'); | |
| // إضافة مستمعات الأحداث | |
| document.addEventListener('DOMContentLoaded', function() { | |
| processBtn.addEventListener('click', processFile); | |
| selectAllBtn.addEventListener('click', selectAllPages); | |
| deselectAllBtn.addEventListener('click', deselectAllPages); | |
| extractImagesBtn.addEventListener('click', extractImages); | |
| extractTextBtn.addEventListener('click', extractText); | |
| copyTextBtn.addEventListener('click', copyText); | |
| downloadTextBtn.addEventListener('click', downloadText); | |
| downloadWordBtn.addEventListener('click', downloadWord); | |
| }); | |
| // تحديث عداد OCR | |
| function updateOcrCounter(count) { | |
| ocrPagesCount += count; | |
| ocrCounter.textContent = ocrPagesCount; | |
| // حفظ العداد في localStorage | |
| localStorage.setItem('ocrPagesCount', ocrPagesCount); | |
| // تحديث تاريخ آخر معالجة | |
| const now = new Date(); | |
| const formattedDate = `${now.getFullYear()}-${(now.getMonth()+1).toString().padStart(2, '0')}-${now.getDate().toString().padStart(2, '0')} ${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}`; | |
| lastOcrDate.textContent = formattedDate; | |
| localStorage.setItem('lastOcrDate', formattedDate); | |
| } | |
| // معالجة الملف | |
| async function processFile() { | |
| if (!fileInput.files || fileInput.files.length === 0) { | |
| alert('الرجاء اختيار ملف أولاً'); | |
| return; | |
| } | |
| const file = fileInput.files[0]; | |
| // إظهار حالة المعالجة | |
| processingStatus.classList.remove('d-none'); | |
| statusText.textContent = 'جاري معالجة الملف...'; | |
| progressBar.style.width = '0%'; | |
| // إخفاء بطاقات أخرى | |
| pdfPagesCard.classList.add('d-none'); | |
| resultsCard.classList.add('d-none'); | |
| // إفراغ مصفوفات الصفحات | |
| documentPages = []; | |
| selectedPages = []; | |
| extractedTexts = []; | |
| extractedPageNumbers = []; | |
| try { | |
| const fileType = file.name.split('.').pop().toLowerCase(); | |
| if (fileType === 'pdf') { | |
| await processPdf(file); | |
| } else if (['jpg', 'jpeg', 'png'].includes(fileType)) { | |
| await processImage(file); | |
| } else { | |
| throw new Error('نوع الملف غير مدعوم. يرجى اختيار ملف PDF أو صورة.'); | |
| } | |
| // إظهار بطاقة صفحات PDF | |
| pdfPagesCard.classList.remove('d-none'); | |
| // إخفاء حالة المعالجة | |
| processingStatus.classList.add('d-none'); | |
| } catch (error) { | |
| console.error('Error processing file:', error); | |
| statusText.textContent = `خطأ: ${error.message}`; | |
| } | |
| } | |
| // معالجة ملف PDF | |
| async function processPdf(file) { | |
| try { | |
| // تحميل ملف PDF | |
| const arrayBuffer = await file.arrayBuffer(); | |
| const pdfDoc = await pdfjsLib.getDocument({ data: arrayBuffer }).promise; | |
| // التحقق من عدد الصفحات | |
| const numPages = pdfDoc.numPages; | |
| if (numPages > 100) { | |
| alert('هذا الملف يحتوي على أكثر من 100 صفحة. سيتم معالجة أول 100 صفحة فقط.'); | |
| } | |
| // مسح حاوية الصفحات | |
| pdfPagesContainer.innerHTML = ''; | |
| // عرض أول 100 صفحة كصور مصغرة | |
| const maxPages = Math.min(numPages, 100); | |
| for (let i = 1; i <= maxPages; i++) { | |
| // تحديث شريط التقدم | |
| progressBar.style.width = `${(i / maxPages) * 100}%`; | |
| statusText.textContent = `جاري معالجة الصفحة ${i} من ${maxPages}...`; | |
| // تحويل الصفحة إلى صورة | |
| const pageImage = await convertPdfPageToImage(pdfDoc, i); | |
| // إضافة الصفحة إلى المصفوفة | |
| documentPages.push({ | |
| pageNumber: i, | |
| imageData: pageImage.imageData, | |
| width: pageImage.width, | |
| height: pageImage.height | |
| }); | |
| // إنشاء عنصر للصفحة في واجهة المستخدم | |
| createPageElement(pageImage.imageData, i); | |
| } | |
| } catch (error) { | |
| console.error('Error processing PDF:', error); | |
| throw error; | |
| } | |
| } | |
| // معالجة ملف صورة | |
| async function processImage(file) { | |
| try { | |
| // قراءة الصورة كـ Data URL | |
| const imageData = await readFileAsDataURL(file); | |
| // إنشاء صورة لقياس أبعادها | |
| const img = new Image(); | |
| await new Promise((resolve, reject) => { | |
| img.onload = resolve; | |
| img.onerror = reject; | |
| img.src = imageData; | |
| }); | |
| // مسح حاوية الصفحات | |
| pdfPagesContainer.innerHTML = ''; | |
| // إضافة الصورة إلى المصفوفة | |
| documentPages = [{ | |
| pageNumber: 1, | |
| imageData: imageData, | |
| width: img.width, | |
| height: img.height | |
| }]; | |
| // إنشاء عنصر للصورة في واجهة المستخدم | |
| createPageElement(imageData, 1); | |
| // تحديث شريط التقدم | |
| progressBar.style.width = '100%'; | |
| statusText.textContent = 'تمت معالجة الصورة بنجاح'; | |
| } catch (error) { | |
| console.error('Error processing image:', error); | |
| throw error; | |
| } | |
| } | |
| // تحويل صفحة PDF إلى صورة | |
| async function convertPdfPageToImage(pdfDoc, pageNumber, scale = 1.5) { | |
| try { | |
| // الحصول على الصفحة من مستند PDF | |
| const page = await pdfDoc.getPage(pageNumber); | |
| // إنشاء عنصر canvas لرسم الصفحة | |
| const canvas = document.createElement('canvas'); | |
| const context = canvas.getContext('2d'); | |
| // ضبط حجم الـ canvas بناءً على حجم الصفحة ومقياس التكبير | |
| const viewport = page.getViewport({ scale }); | |
| canvas.width = viewport.width; | |
| canvas.height = viewport.height; | |
| // رسم الصفحة على الـ canvas | |
| await page.render({ | |
| canvasContext: context, | |
| viewport: viewport | |
| }).promise; | |
| // تحويل الـ canvas إلى صورة بصيغة PNG | |
| return { | |
| imageData: canvas.toDataURL('image/png'), | |
| width: viewport.width, | |
| height: viewport.height, | |
| pageNumber: pageNumber | |
| }; | |
| } catch (error) { | |
| console.error(`Error converting PDF page ${pageNumber} to image:`, error); | |
| throw error; | |
| } | |
| } | |
| // إنشاء عنصر للصفحة في واجهة المستخدم | |
| function createPageElement(imageData, pageNumber) { | |
| const pageDiv = document.createElement('div'); | |
| pageDiv.className = 'pdf-page'; | |
| pageDiv.dataset.page = pageNumber; | |
| const img = document.createElement('img'); | |
| img.src = imageData; | |
| img.alt = `صفحة ${pageNumber}`; | |
| const pageNumberDiv = document.createElement('div'); | |
| pageNumberDiv.className = 'page-number'; | |
| pageNumberDiv.textContent = `صفحة ${pageNumber}`; | |
| pageDiv.appendChild(img); | |
| pageDiv.appendChild(pageNumberDiv); | |
| // إضافة حدث النقر للتحديد | |
| pageDiv.addEventListener('click', function() { | |
| this.classList.toggle('selected'); | |
| // تحديث مصفوفة الصفحات المحددة | |
| const page = parseInt(this.dataset.page); | |
| if (this.classList.contains('selected')) { | |
| if (!selectedPages.includes(page)) { | |
| selectedPages.push(page); | |
| } | |
| } else { | |
| const index = selectedPages.indexOf(page); | |
| if (index > -1) { | |
| selectedPages.splice(index, 1); | |
| } | |
| } | |
| }); | |
| pdfPagesContainer.appendChild(pageDiv); | |
| } | |
| // قراءة ملف كـ Data URL | |
| function readFileAsDataURL(file) { | |
| return new Promise((resolve, reject) => { | |
| const reader = new FileReader(); | |
| reader.onload = e => resolve(e.target.result); | |
| reader.onerror = reject; | |
| reader.readAsDataURL(file); | |
| }); | |
| } | |
| // تحديد كل الصفحات | |
| function selectAllPages() { | |
| document.querySelectorAll('.pdf-page').forEach(page => { | |
| page.classList.add('selected'); | |
| const pageNumber = parseInt(page.dataset.page); | |
| if (!selectedPages.includes(pageNumber)) { | |
| selectedPages.push(pageNumber); | |
| } | |
| }); | |
| } | |
| // إلغاء تحديد كل الصفحات | |
| function deselectAllPages() { | |
| document.querySelectorAll('.pdf-page').forEach(page => { | |
| page.classList.remove('selected'); | |
| }); | |
| selectedPages = []; | |
| } | |
| // استخراج الصور | |
| function extractImages() { | |
| if (documentPages.length === 0) { | |
| alert('لا توجد صفحات للمعالجة'); | |
| return; | |
| } | |
| // اختيار الصفحات المحددة فقط أو كل الصفحات إذا لم يتم تحديد أي صفحة | |
| const pagesToExtract = selectedPages.length > 0 | |
| ? documentPages.filter(page => selectedPages.includes(page.pageNumber)) | |
| : documentPages; | |
| if (pagesToExtract.length === 0) { | |
| alert('الرجاء تحديد صفحة واحدة على الأقل'); | |
| return; | |
| } | |
| // إنشاء وتنزيل كل صورة | |
| pagesToExtract.forEach(page => { | |
| const a = document.createElement('a'); | |
| a.href = page.imageData; | |
| a.download = `mondo_lingua_page_${page.pageNumber}.png`; | |
| document.body.appendChild(a); | |
| a.click(); | |
| document.body.removeChild(a); | |
| }); | |
| // إظهار رسالة نجاح | |
| alert(`تم استخراج ${pagesToExtract.length} صورة بنجاح`); | |
| } | |
| // استخراج النص | |
| async function extractText() { | |
| if (documentPages.length === 0) { | |
| alert('لا توجد صفحات للمعالجة'); | |
| return; | |
| } | |
| // اختيار الصفحات المحددة فقط أو كل الصفحات إذا لم يتم تحديد أي صفحة | |
| const pagesToProcess = selectedPages.length > 0 | |
| ? documentPages.filter(page => selectedPages.includes(page.pageNumber)) | |
| : documentPages; | |
| if (pagesToProcess.length === 0) { | |
| alert('الرجاء تحديد صفحة واحدة على الأقل'); | |
| return; | |
| } | |
| // إظهار حالة المعالجة | |
| processingStatus.classList.remove('d-none'); | |
| statusText.textContent = 'جاري استخراج النص...'; | |
| progressBar.style.width = '0%'; | |
| try { | |
| extractedTexts = []; | |
| extractedPageNumbers = []; | |
| // معالجة كل صفحة | |
| for (let i = 0; i < pagesToProcess.length; i++) { | |
| const page = pagesToProcess[i]; | |
| // تحديث التقدم | |
| progressBar.style.width = `${((i + 1) / pagesToProcess.length) * 100}%`; | |
| statusText.textContent = `جاري معالجة الصفحة ${i + 1} من ${pagesToProcess.length}...`; | |
| // استخراج النص من الصورة باستخدام OCR API | |
| const pageText = await extractTextFromImage(page.imageData, page.pageNumber); | |
| extractedTexts.push(pageText); | |
| extractedPageNumbers.push(page.pageNumber); | |
| } | |
| // تحديث عداد OCR | |
| updateOcrCounter(pagesToProcess.length); | |
| // جمع النصوص المستخرجة | |
| const combinedText = extractedTexts.join('\n\n'); | |
| // عرض النص المستخرج | |
| resultText.textContent = combinedText; | |
| // عرض معاينة مرئية منظمة للصفحات | |
| generateResultPreview(); | |
| resultsCard.classList.remove('d-none'); | |
| // إخفاء حالة المعالجة | |
| processingStatus.classList.add('d-none'); | |
| // التمرير إلى النتائج | |
| resultsCard.scrollIntoView({ behavior: 'smooth' }); | |
| } catch (error) { | |
| console.error('Error extracting text:', error); | |
| statusText.textContent = `خطأ: ${error.message}`; | |
| } | |
| } | |
| // إنشاء معاينة منظمة للنتائج | |
| function generateResultPreview() { | |
| resultPreview.innerHTML = ''; | |
| if (extractedTexts.length === 0) { | |
| return; | |
| } | |
| // عرض أول ثلاث صفحات كمعاينة | |
| const previewPages = Math.min(extractedTexts.length, 3); | |
| for (let i = 0; i < previewPages; i++) { | |
| const pageText = extractedTexts[i]; | |
| const pageNumber = extractedPageNumbers[i]; | |
| // إنشاء معاينة للصفحة | |
| const previewDiv = document.createElement('div'); | |
| previewDiv.className = 'page-preview'; | |
| const pageTitle = document.createElement('h4'); | |
| pageTitle.textContent = `صفحة ${pageNumber}`; | |
| const textPreview = document.createElement('p'); | |
| // عرض أول 100 حرف من كل صفحة | |
| const textContent = pageText.replace(`=== صفحة ${pageNumber} ===\n`, ''); | |
| textPreview.textContent = textContent.length > 100 ? | |
| textContent.substring(0, 100) + '...' : | |
| textContent; | |
| previewDiv.appendChild(pageTitle); | |
| previewDiv.appendChild(textPreview); | |
| resultPreview.appendChild(previewDiv); | |
| } | |
| // إضافة رسالة إذا كان هناك المزيد من الصفحات | |
| if (extractedTexts.length > 3) { | |
| const morePages = document.createElement('p'); | |
| morePages.className = 'text-muted'; | |
| morePages.textContent = `+ ${extractedTexts.length - 3} صفحات أخرى...`; | |
| resultPreview.appendChild(morePages); | |
| } | |
| } | |
| // استخراج النص من صورة باستخدام API4AI OCR | |
| async function extractTextFromImage(imageData, pageNumber) { | |
| try { | |
| // تحويل Data URL إلى Blob | |
| const response = await fetch(imageData); | |
| const blob = await response.blob(); | |
| // إنشاء FormData وإضافة الصورة | |
| const formData = new FormData(); | |
| formData.append('image', blob, `page_${pageNumber}.png`); | |
| // طلب OCR | |
| const ocrResponse = await fetch(OCR_API_URL, { | |
| method: 'POST', | |
| headers: { | |
| 'X-RapidAPI-Key': RAPIDAPI_KEY, | |
| 'X-RapidAPI-Host': 'ocr43.p.rapidapi.com' | |
| }, | |
| body: formData | |
| }); | |
| if (!ocrResponse.ok) { | |
| throw new Error(`فشل في طلب OCR: ${ocrResponse.status}`); | |
| } | |
| const data = await ocrResponse.json(); | |
| try { | |
| // استخراج النص من الاستجابة | |
| const text = data.results[0].entities[0].objects[0].entities[0].text; | |
| return `=== صفحة ${pageNumber} ===\n${text}`; | |
| } catch (e) { | |
| console.error('Error parsing OCR response:', e); | |
| return `=== صفحة ${pageNumber} ===\n[خطأ في معالجة النص]`; | |
| } | |
| } catch (error) { | |
| console.error(`Error in OCR for page ${pageNumber}:`, error); | |
| throw error; | |
| } | |
| } | |
| // نسخ النص | |
| function copyText() { | |
| const text = resultText.textContent; | |
| if (!text || text === 'لم يتم استخراج نص بعد.') { | |
| alert('لا يوجد نص للنسخ'); | |
| return; | |
| } | |
| navigator.clipboard.writeText(text) | |
| .then(() => alert('تم نسخ النص بنجاح')) | |
| .catch(err => alert('حدث خطأ أثناء نسخ النص: ' + err)); | |
| } | |
| // تنزيل النص | |
| function downloadText() { | |
| const text = resultText.textContent; | |
| if (!text || text === 'لم يتم استخراج نص بعد.') { | |
| alert('لا يوجد نص للتنزيل'); | |
| return; | |
| } | |
| const blob = new Blob([text], { type: 'text/plain;charset=utf-8' }); | |
| const url = URL.createObjectURL(blob); | |
| const a = document.createElement('a'); | |
| a.href = url; | |
| a.download = 'mondo_lingua_ocr_text.txt'; | |
| document.body.appendChild(a); | |
| a.click(); | |
| document.body.removeChild(a); | |
| URL.revokeObjectURL(url); | |
| } | |
| // تنزيل النص إلى Word بصورة منظمة ومقسمة | |
| function downloadWord() { | |
| const text = resultText.textContent; | |
| if (!text || text === 'لم يتم استخراج نص بعد.') { | |
| alert('لا يوجد نص للتنزيل'); | |
| return; | |
| } | |
| // تقسيم النص إلى صفحات بناءً على علامات الصفحات | |
| const pageTexts = []; | |
| let currentPageText = ''; | |
| const lines = text.split('\n'); | |
| for (let i = 0; i < lines.length; i++) { | |
| const line = lines[i]; | |
| // إذا كان السطر يشير إلى بداية صفحة جديدة | |
| if (line.startsWith('=== صفحة ') && line.endsWith(' ===')) { | |
| // إذا كان هناك نص تم استخراجه بالفعل، قم بإضافته إلى المصفوفة | |
| if (currentPageText) { | |
| pageTexts.push(currentPageText); | |
| currentPageText = ''; | |
| } | |
| // ابدأ النص الجديد بعنوان الصفحة | |
| currentPageText = line + '\n'; | |
| } else { | |
| // إضافة السطر إلى النص الحالي | |
| currentPageText += line + '\n'; | |
| } | |
| } | |
| // إضافة آخر صفحة | |
| if (currentPageText) { | |
| pageTexts.push(currentPageText); | |
| } | |
| // إنشاء مستند Word | |
| let wordContent = ` | |
| <!DOCTYPE html> | |
| <html xmlns:o='urn:schemas-microsoft-com:office:office' | |
| xmlns:w='urn:schemas-microsoft-com:office:word' | |
| xmlns='http://www.w3.org/TR/REC-html40'> | |
| <head> | |
| <meta charset='utf-8'> | |
| <title>موندو لينجوا - نص OCR</title> | |
| <style> | |
| @page { | |
| size: 21cm 29.7cm; | |
| margin: 2cm; | |
| } | |
| body { | |
| font-family: 'Arial', sans-serif; | |
| direction: rtl; | |
| text-align: right; | |
| } | |
| .page-title { | |
| font-size: 18px; | |
| font-weight: bold; | |
| color: #3b82f6; | |
| margin-bottom: 15px; | |
| padding-bottom: 5px; | |
| border-bottom: 1px solid #ccc; | |
| } | |
| .page-content { | |
| margin-bottom: 15px; | |
| line-height: 1.5; | |
| page-break-after: always; | |
| } | |
| .footer { | |
| font-size: 10px; | |
| text-align: center; | |
| color: #666; | |
| margin-top: 20px; | |
| } | |
| .header { | |
| text-align: center; | |
| margin-bottom: 20px; | |
| } | |
| .header h1 { | |
| color: #3b82f6; | |
| margin-bottom: 5px; | |
| } | |
| .date { | |
| font-size: 12px; | |
| color: #666; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="header"> | |
| <h1>فاست برو - نص مستخرج بتقنية OCR</h1> | |
| <div class="date">تاريخ الاستخراج: ${new Date().toLocaleDateString('ar-EG')}</div> | |
| </div> | |
| `; | |
| // إضافة كل صفحة إلى المستند | |
| pageTexts.forEach((pageText, index) => { | |
| // استخراج رقم الصفحة من العنوان | |
| const titleMatch = pageText.match(/=== صفحة (\d+) ===/); | |
| const pageNumber = titleMatch ? titleMatch[1] : (index + 1); | |
| // استبدال عنوان الصفحة بتنسيق أفضل | |
| const formattedPageText = pageText.replace(/=== صفحة \d+ ===\n/, ''); | |
| // إضافة صفحة جديدة إلى المستند | |
| wordContent += ` | |
| <div class="page-content"> | |
| <div class="page-title">صفحة ${pageNumber}</div> | |
| <div>${formattedPageText.replace(/\n/g, '<br>')}</div> | |
| </div> | |
| `; | |
| }); | |
| // إضافة تذييل المستند | |
| wordContent += ` | |
| <div class="footer"> | |
| تم إنشاء هذا المستند بواسطة نظام شركة فاست برو للتعرف الضوئي على النصوص | |
| </div> | |
| </body> | |
| </html> | |
| `; | |
| // تنزيل المستند | |
| const blob = new Blob(['\ufeff', wordContent], { type: 'application/msword' }); | |
| const url = URL.createObjectURL(blob); | |
| const a = document.createElement('a'); | |
| a.href = url; | |
| a.download = 'mondo_lingua_ocr_text.doc'; | |
| document.body.appendChild(a); | |
| a.click(); | |
| document.body.removeChild(a); | |
| URL.revokeObjectURL(url); | |
| } | |
| </script> | |
| </body> | |
| </html> |