mirror of
https://github.com/tesseract-ocr/tesseract.git
synced 2025-06-07 18:02:40 +08:00
..
This commit is contained in:
parent
492ca96937
commit
1a243af925
BIN
.next/cache/webpack/client-development/1.pack.gz
vendored
BIN
.next/cache/webpack/client-development/1.pack.gz
vendored
Binary file not shown.
BIN
.next/cache/webpack/client-development/2.pack.gz
vendored
BIN
.next/cache/webpack/client-development/2.pack.gz
vendored
Binary file not shown.
BIN
.next/cache/webpack/client-development/3.pack.gz
vendored
BIN
.next/cache/webpack/client-development/3.pack.gz
vendored
Binary file not shown.
BIN
.next/cache/webpack/client-development/4.pack.gz
vendored
BIN
.next/cache/webpack/client-development/4.pack.gz
vendored
Binary file not shown.
BIN
.next/cache/webpack/client-development/index.pack.gz
vendored
BIN
.next/cache/webpack/client-development/index.pack.gz
vendored
Binary file not shown.
Binary file not shown.
BIN
.next/cache/webpack/server-development/0.pack.gz
vendored
BIN
.next/cache/webpack/server-development/0.pack.gz
vendored
Binary file not shown.
BIN
.next/cache/webpack/server-development/1.pack.gz
vendored
BIN
.next/cache/webpack/server-development/1.pack.gz
vendored
Binary file not shown.
BIN
.next/cache/webpack/server-development/2.pack.gz
vendored
BIN
.next/cache/webpack/server-development/2.pack.gz
vendored
Binary file not shown.
BIN
.next/cache/webpack/server-development/3.pack.gz
vendored
BIN
.next/cache/webpack/server-development/3.pack.gz
vendored
Binary file not shown.
BIN
.next/cache/webpack/server-development/4.pack.gz
vendored
BIN
.next/cache/webpack/server-development/4.pack.gz
vendored
Binary file not shown.
BIN
.next/cache/webpack/server-development/5.pack.gz
vendored
BIN
.next/cache/webpack/server-development/5.pack.gz
vendored
Binary file not shown.
BIN
.next/cache/webpack/server-development/index.pack.gz
vendored
BIN
.next/cache/webpack/server-development/index.pack.gz
vendored
Binary file not shown.
Binary file not shown.
@ -1,5 +1,5 @@
|
||||
{
|
||||
"node": {},
|
||||
"edge": {},
|
||||
"encryptionKey": "tSamhz5T2h7ahFqh+YSxMpWNSqXYzyFQavfWbDAznG4="
|
||||
"encryptionKey": "5bSgyi9JzZrdWPWIOnposJ8ES7uP+I1sTxcA6KjnyC0="
|
||||
}
|
29
.next/trace
29
.next/trace
File diff suppressed because one or more lines are too long
36
app/components/CameraCapture.jsx
Normal file
36
app/components/CameraCapture.jsx
Normal file
@ -0,0 +1,36 @@
|
||||
import React, { useRef, useState } from 'react';
|
||||
import Webcam from 'react-webcam';
|
||||
|
||||
const CameraCapture = ({ onCapture }) => {
|
||||
const webcamRef = useRef(null);
|
||||
const [capturedImages, setCapturedImages] = useState([]);
|
||||
|
||||
const handleCameraCapture = async () => {
|
||||
const imageSrc = webcamRef.current.getScreenshot();
|
||||
if (imageSrc) {
|
||||
const response = await fetch(imageSrc);
|
||||
const blob = await response.blob();
|
||||
const file = new File([blob], `webcam-capture-${Date.now()}.jpg`, { type: 'image/jpeg' });
|
||||
setCapturedImages(prev => [...prev, file]);
|
||||
onCapture(file);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
<Webcam
|
||||
ref={webcamRef}
|
||||
screenshotFormat="image/jpeg"
|
||||
className="w-full rounded"
|
||||
/>
|
||||
<button
|
||||
onClick={handleCameraCapture}
|
||||
className="mt-2 px-4 py-2 bg-green-500 text-white rounded hover:bg-green-600 transition-colors w-full"
|
||||
>
|
||||
Capture Photo ({capturedImages.length} captured)
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CameraCapture;
|
@ -1,38 +1,36 @@
|
||||
'use client';
|
||||
|
||||
import React, { useState, useRef } from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import axios from 'axios';
|
||||
import { saveAs } from 'file-saver';
|
||||
import Webcam from 'react-webcam';
|
||||
import CameraCapture from './CameraCapture';
|
||||
|
||||
const ImageUploader = () => {
|
||||
const [selectedFile, setSelectedFile] = useState(null);
|
||||
const [result, setResult] = useState('');
|
||||
const [selectedFiles, setSelectedFiles] = useState([]);
|
||||
const [results, setResults] = useState([]);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [showCamera, setShowCamera] = useState(false);
|
||||
const webcamRef = useRef(null);
|
||||
const [currentProcessingIndex, setCurrentProcessingIndex] = useState(0);
|
||||
|
||||
const handleFileChange = (event) => {
|
||||
if (event.target.files && event.target.files.length > 0) {
|
||||
setSelectedFile(event.target.files[0]);
|
||||
handleFileUpload(event.target.files[0]);
|
||||
const newFiles = Array.from(event.target.files);
|
||||
setSelectedFiles(prev => [...prev, ...newFiles]);
|
||||
processFiles(newFiles);
|
||||
}
|
||||
};
|
||||
|
||||
const handleCameraCapture = async () => {
|
||||
const imageSrc = webcamRef.current.getScreenshot();
|
||||
if (imageSrc) {
|
||||
// Convert base64 to blob
|
||||
const response = await fetch(imageSrc);
|
||||
const blob = await response.blob();
|
||||
const file = new File([blob], "webcam-capture.jpg", { type: 'image/jpeg' });
|
||||
setSelectedFile(file);
|
||||
handleFileUpload(file);
|
||||
const processFiles = async (files) => {
|
||||
setIsLoading(true);
|
||||
|
||||
for (const file of files) {
|
||||
await handleFileUpload(file);
|
||||
}
|
||||
|
||||
setIsLoading(false);
|
||||
};
|
||||
|
||||
const handleFileUpload = async (file) => {
|
||||
setIsLoading(true);
|
||||
const formData = new FormData();
|
||||
formData.append('image', file);
|
||||
|
||||
@ -40,19 +38,18 @@ const ImageUploader = () => {
|
||||
const response = await axios.post('/api/ocr', formData, {
|
||||
headers: { 'Content-Type': 'multipart/form-data' },
|
||||
});
|
||||
setResult(response.data.text);
|
||||
setResults(prev => [...prev, { file: file.name, text: response.data.text }]);
|
||||
} catch (error) {
|
||||
console.error('Error uploading image:', error);
|
||||
alert('An error occurred while processing the image');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
setResults(prev => [...prev, { file: file.name, text: 'Error processing image' }]);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDownload = () => {
|
||||
if (result) {
|
||||
const blob = new Blob([result], { type: 'application/msword' });
|
||||
saveAs(blob, 'ocr_result.doc');
|
||||
if (results.length > 0) {
|
||||
const combinedText = results.map(r => `File: ${r.file}\n${r.text}\n\n`).join('---\n');
|
||||
const blob = new Blob([combinedText], { type: 'application/msword' });
|
||||
saveAs(blob, 'ocr_results.doc');
|
||||
}
|
||||
};
|
||||
|
||||
@ -61,58 +58,81 @@ const ImageUploader = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="max-w-md mx-auto mt-8">
|
||||
<div className="space-y-4">
|
||||
<div className="flex space-x-2">
|
||||
<input
|
||||
type="file"
|
||||
accept="image/*"
|
||||
onChange={handleFileChange}
|
||||
className="block w-full text-sm text-gray-500
|
||||
file:mr-4 file:py-2 file:px-4
|
||||
file:rounded-full file:border-0
|
||||
file:text-sm file:font-semibold
|
||||
file:bg-violet-50 file:text-violet-700
|
||||
hover:file:bg-violet-100"
|
||||
/>
|
||||
<button
|
||||
onClick={toggleCamera}
|
||||
className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 transition-colors"
|
||||
>
|
||||
{showCamera ? 'Hide Camera' : 'Use Camera'}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{showCamera && (
|
||||
<div className="relative">
|
||||
<Webcam
|
||||
ref={webcamRef}
|
||||
screenshotFormat="image/jpeg"
|
||||
className="w-full rounded"
|
||||
/>
|
||||
<button
|
||||
onClick={handleCameraCapture}
|
||||
className="mt-2 px-4 py-2 bg-green-500 text-white rounded hover:bg-green-600 transition-colors w-full"
|
||||
>
|
||||
Capture Photo
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isLoading && <p className="mt-4">Processing...</p>}
|
||||
<div className="min-h-screen bg-gray-50 py-12 px-4 sm:px-6 lg:px-8">
|
||||
<div className="max-w-2xl mx-auto bg-white rounded-lg shadow-lg p-8">
|
||||
<h2 className="text-2xl font-bold text-gray-900 mb-8 text-center">
|
||||
Image Text Extractor
|
||||
</h2>
|
||||
|
||||
{result && (
|
||||
<div className="mt-4">
|
||||
<h3 className="font-bold">OCR Result:</h3>
|
||||
<pre className="mt-2 p-2 bg-gray-100 rounded">{result}</pre>
|
||||
<div className="space-y-6">
|
||||
<div className="flex flex-col sm:flex-row sm:space-x-4 space-y-4 sm:space-y-0">
|
||||
<div className="flex-1">
|
||||
<input
|
||||
type="file"
|
||||
accept="image/*"
|
||||
onChange={handleFileChange}
|
||||
multiple
|
||||
className="block w-full text-sm text-gray-500
|
||||
file:mr-4 file:py-3 file:px-4
|
||||
file:rounded-lg file:border-0
|
||||
file:text-sm file:font-semibold
|
||||
file:bg-violet-100 file:text-violet-700
|
||||
hover:file:bg-violet-200
|
||||
cursor-pointer
|
||||
border border-gray-300 rounded-lg"
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
onClick={handleDownload}
|
||||
className="mt-4 px-4 py-2 bg-green-500 text-white rounded hover:bg-green-600 transition-colors"
|
||||
onClick={toggleCamera}
|
||||
className="px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700
|
||||
transition-colors duration-200 font-medium shadow-sm"
|
||||
>
|
||||
Download as .doc
|
||||
{showCamera ? 'Hide Camera' : 'Use Camera'}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{showCamera && (
|
||||
<div className="border-2 border-dashed border-gray-300 rounded-lg p-4">
|
||||
<CameraCapture onCapture={(file) => processFiles([file])} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isLoading && (
|
||||
<div className="text-center py-4">
|
||||
<div className="animate-spin rounded-full h-10 w-10 border-b-2 border-blue-600 mx-auto"></div>
|
||||
<p className="mt-2 text-gray-600">Processing images...</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{results.length > 0 && (
|
||||
<div className="mt-8 space-y-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<h3 className="text-xl font-bold text-gray-900">OCR Results</h3>
|
||||
<button
|
||||
onClick={handleDownload}
|
||||
className="inline-flex items-center px-4 py-2 bg-green-600 text-white rounded-lg
|
||||
hover:bg-green-700 transition-colors duration-200 font-medium shadow-sm"
|
||||
>
|
||||
<svg className="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2}
|
||||
d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" />
|
||||
</svg>
|
||||
Download Results
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
{results.map((result, index) => (
|
||||
<div key={index} className="bg-gray-50 rounded-lg p-4 shadow-sm">
|
||||
<h4 className="font-medium text-gray-900 mb-2">{result.file}</h4>
|
||||
<pre className="bg-white p-4 rounded-lg border border-gray-200 text-sm text-gray-700
|
||||
overflow-x-auto">{result.text}</pre>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user