如何在React Native中实现图片内文本选取功能
实现Vision Camera图片内文本选取功能(类似iPhone效果)

核心思路
避开Firebase ML Kit的前提下,优先借助原生系统自带的文本识别能力(iOS Vision框架、Android Google Play Services文本识别),结合Vision Camera获取的图片数据,完成文本识别、坐标转换,最后在RN层实现选框交互与文本复制功能。
分步实现方案
1. 配置Vision Camera基础环境
- 安装依赖:
npm install react-native-vision-camera - 配置项目权限:在
Info.plist(iOS)添加相机、照片访问权限;AndroidManifest.xml(Android)添加<uses-permission android:name="android.permission.CAMERA" />等权限 - 在RN组件中初始化相机,设置必要参数:
import { Camera, useCameraDevices } from 'react-native-vision-camera'; import { View, StyleSheet } from 'react-native'; import { useRef } from 'react'; function CameraScreen() { const devices = useCameraDevices('back'); const device = devices.back; const cameraRef = useRef(null); if (device == null) return <View />; return ( <Camera style={StyleSheet.absoluteFill} device={device} isActive={true} ref={cameraRef} /> ); }
2. 封装原生文本识别模块
iOS端(基于Vision框架)
- 创建RN原生模块,使用
VNRecognizeTextRequest处理图片:- 将图片URI转为
CIImage - 发起文本识别请求,获取每个文本块的
boundingBox和transcript - 将结果转为JSON格式返回给RN
- 将图片URI转为
Android端(基于Google Play Services文本识别)
- 集成依赖:在
build.gradle添加implementation 'com.google.android.gms:play-services-mlkit-text-recognition:16.0.0' - 创建RN原生模块,调用
TextRecognition.getClient()识别图片,提取文本块的位置与内容,返回给RN
3. 拍摄图片并触发文本识别
在RN组件中调用Vision Camera的拍照API,将图片URI传给原生识别模块:
import { Alert } from 'react-native'; import Clipboard from '@react-native-clipboard/clipboard'; import { useState } from 'react'; const [textBlocks, setTextBlocks] = useState([]); const [capturedPhotoUri, setCapturedPhotoUri] = useState(null); const handleTakePhoto = async () => { if (!cameraRef.current) return; const photo = await cameraRef.current.takePhotoAsync({ quality: 0.8 }); setCapturedPhotoUri(photo.uri); // 调用原生识别模块(需自行封装NativeTextRecognizer) const results = await NativeTextRecognizer.recognize(photo.uri); setTextBlocks(results); };
4. RN层实现文本选取交互
- 坐标转换:原生识别返回的坐标基于图片原始尺寸,需根据RN显示容器的缩放比例调整:
// 假设图片原始尺寸为originalWidth/originalHeight,显示容器尺寸为containerWidth/containerHeight const scale = Math.min(containerWidth / originalWidth, containerHeight / originalHeight); const adjustedBlocks = textBlocks.map(block => ({ ...block, x: block.x * scale, y: block.y * scale, width: block.width * scale, height: block.height * scale }));
- 绘制选框:使用
View渲染文本块选框,添加点击事件实现复制:
import { Image, TouchableOpacity } from 'react-native'; return ( <View style={{ position: 'relative', flex: 1 }}> {capturedPhotoUri && ( <Image source={{ uri: capturedPhotoUri }} style={{ width: '100%', height: '100%', resizeMode: 'contain' }} onLayout={(e) => { // 获取图片显示尺寸,用于计算缩放比例 setContainerWidth(e.nativeEvent.layout.width); setContainerHeight(e.nativeEvent.layout.height); }} /> )} {adjustedBlocks.map((block, index) => ( <TouchableOpacity key={index} style={{ position: 'absolute', left: block.x, top: block.y, width: block.width, height: block.height, borderWidth: 2, borderColor: '#007AFF', backgroundColor: 'rgba(0,122,255,0.1)' }} onPress={() => { Clipboard.setString(block.text); Alert.alert('已复制', block.text); }} /> ))} </View> );
5. 快速验证替代方案(纯JS层)
如果不想编写原生模块,可先用纯JS的OCR库tesseract.js-react-native做功能验证(注意移动端性能较差):
- 安装依赖:
npm install tesseract.js-react-native - 识别示例:
import { TesseractOcr } from 'tesseract.js-react-native'; const recognizeText = async (imageUri) => { const result = await TesseractOcr.recognize(imageUri, 'eng+chi_sim'); return result.blocks.map(block => ({ text: block.text, x: block.bbox.x0, y: block.bbox.y0, width: block.bbox.x1 - block.bbox.x0, height: block.bbox.y1 - block.bbox.y0 })); };
内容的提问来源于stack exchange,提问作者PietroPutelli
相关产品推荐
相关产品推荐

