import React, { useState } from 'react';
import { View, Image, Text, TouchableOpacity, StyleSheet, ScrollView } from 'react-native';
import { useOCR, OCR_ENGLISH, OCRDetection } from 'react-native-executorch';
import { launchImageLibrary } from 'react-native-image-picker';
import Svg, { Polygon } from 'react-native-svg';
function OCRDemo() {
const [imageUri, setImageUri] = useState<string | null>(null);
const [detections, setDetections] = useState<OCRDetection[]>([]);
const [imageDimensions, setImageDimensions] = useState({ width: 0, height: 0 });
const { isReady, isGenerating, error, downloadProgress, forward } = useOCR({
model: OCR_ENGLISH,
});
const selectAndExtract = async () => {
const result = await launchImageLibrary({ mediaType: 'photo' });
if (result.assets && result.assets[0]) {
const asset = result.assets[0];
setImageUri(asset.uri!);
setImageDimensions({
width: asset.width || 300,
height: asset.height || 300,
});
try {
const textDetections = await forward(asset.uri!);
setDetections(textDetections);
// Log all extracted text
const allText = textDetections.map(d => d.text).join(' ');
console.log('Extracted text:', allText);
} catch (err) {
console.error('OCR failed:', err);
}
}
};
const renderBoundingBoxes = () => {
if (!imageUri || detections.length === 0) return null;
return (
<Svg
style={StyleSheet.absoluteFill}
viewBox={`0 0 ${imageDimensions.width} ${imageDimensions.height}`}
>
{detections.map((detection, index) => {
const points = detection.bbox
.map(p => `${p.x},${p.y}`)
.join(' ');
return (
<Polygon
key={index}
points={points}
stroke="#00FF00"
strokeWidth="2"
fill="rgba(0, 255, 0, 0.1)"
/>
);
})}
</Svg>
);
};
if (error) return <Text>Error: {error.message}</Text>;
if (!isReady) {
return (
<View style={styles.container}>
<Text>Loading OCR models...</Text>
<Text>{(downloadProgress * 100).toFixed(0)}%</Text>
</View>
);
}
return (
<ScrollView style={styles.container}>
<TouchableOpacity
style={styles.button}
onPress={selectAndExtract}
disabled={isGenerating}
>
<Text style={styles.buttonText}>
{isGenerating ? 'Extracting Text...' : 'Select & Extract Text'}
</Text>
</TouchableOpacity>
{imageUri && (
<View style={styles.imageContainer}>
<Image source={{ uri: imageUri }} style={styles.image} />
{renderBoundingBoxes()}
</View>
)}
{detections.length > 0 && (
<View style={styles.results}>
<Text style={styles.title}>Extracted Text ({detections.length} regions):</Text>
{detections.map((detection, index) => (
<View key={index} style={styles.detection}>
<Text style={styles.text}>{detection.text}</Text>
<Text style={styles.confidence}>
{(detection.score * 100).toFixed(0)}% confidence
</Text>
</View>
))}
</View>
)}
</ScrollView>
);
}
const styles = StyleSheet.create({
container: { flex: 1, padding: 20 },
button: { backgroundColor: '#007AFF', padding: 15, borderRadius: 8, marginBottom: 20 },
buttonText: { color: 'white', fontSize: 16, textAlign: 'center' },
imageContainer: { width: '100%', aspectRatio: 1, marginBottom: 20, position: 'relative' },
image: { width: '100%', height: '100%', borderRadius: 8 },
results: { padding: 15, backgroundColor: '#f5f5f5', borderRadius: 8 },
title: { fontSize: 16, fontWeight: 'bold', marginBottom: 10 },
detection: { paddingVertical: 8, borderBottomWidth: 1, borderBottomColor: '#ddd' },
text: { fontSize: 16, marginBottom: 4 },
confidence: { fontSize: 12, color: '#666' },
});
export default OCRDemo;