import React, { useRef, useState, useEffect } from 'react'; import { extractBookData } from '../services/geminiService'; import { Book } from '../types'; interface ScannerProps { onCancel: () => void; onDetected: (data: Partial) => void; } export const Scanner: React.FC = ({ onCancel, onDetected }) => { const videoRef = useRef(null); const canvasRef = useRef(null); const [isProcessing, setIsProcessing] = useState(false); const [error, setError] = useState(null); useEffect(() => { let stream: MediaStream | null = null; async function startCamera() { try { // Try preferred environment camera first try { stream = await navigator.mediaDevices.getUserMedia({ video: { facingMode: 'environment' } }); } catch (innerErr) { console.warn("Environment camera not found, falling back to default camera..."); // Fallback to any available video source stream = await navigator.mediaDevices.getUserMedia({ video: true }); } if (videoRef.current) { videoRef.current.srcObject = stream; } } catch (err) { setError('Не удалось получить доступ к камере. Убедитесь, что разрешения предоставлены.'); console.error("Camera access error:", err); } } startCamera(); return () => { if (stream) { stream.getTracks().forEach(track => track.stop()); } }; }, []); const handleCapture = async () => { if (!videoRef.current || !canvasRef.current || isProcessing) return; // Ensure the video is actually playing and has dimensions if (videoRef.current.readyState < 2 || videoRef.current.videoWidth === 0) { setError('Камера еще не готова. Пожалуйста, подождите.'); return; } setIsProcessing(true); setError(null); const canvas = canvasRef.current; const video = videoRef.current; // Scale down large images to avoid API limits/errors while keeping readability const MAX_WIDTH = 1024; const scale = Math.min(1, MAX_WIDTH / video.videoWidth); canvas.width = video.videoWidth * scale; canvas.height = video.videoHeight * scale; const ctx = canvas.getContext('2d'); if (ctx) { ctx.drawImage(video, 0, 0, canvas.width, canvas.height); // Use standard quality for reliable extraction const base64Image = canvas.toDataURL('image/jpeg', 0.85).split(',')[1]; try { const bookData = await extractBookData(base64Image); onDetected({ ...bookData, coverUrl: canvas.toDataURL('image/jpeg') // Local preview for the form }); } catch (err: any) { console.error("OCR Error:", err); setError('Не удалось распознать книгу. Попробуйте еще раз с лучшим освещением.'); setIsProcessing(false); } } }; return (
); };