React Native: a Simple OCR scanner



At InflightIT, we studied about OCR (Optical Character Recognition) to implement in upcoming projects and additional features to our ongoing projects. For example, reading invoices from restaurants/shops.

In this OCR sample we can select or take a photo from our device. For that we’ll use:

  • react-native-image-picker (picking images)

  • rn-text-detector (text recognization from photo)


1. React-Native

First we need to create a react-native project and choose between a javascript or typescript based-project. Personally i’m opting for typescript every time I can, regardless if the project is a large or a small one. Typescript does give more comfort when debugging and helps to have a good structure.


npx react-native init ocrSampleApp --template react-native-template-typescript

2. Install dependencies

npm i react-native-image-picker --save && npm i rn-text-detector --save
npx pod-install 

3. Additional configurations

iOS

For iOS we need to add this code to Info.plist. It is required by Apple and we need to say why we need camera access.


<key>NSCameraUsageDescription</key>
<string>App needs permission to access your phone camera.</string><key>NSPhotoLibraryAddUsageDescription</key>
<string>App store photos in your phone library.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>App store photos in your phone library.</string>

Android


For Android we also need to add permissions in AndroidManifest.xml


<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO"/>

4. Basic usage

Import main packages to work with.

import { launchCamera, launchImageLibrary } from "react-native-image-picker";
import RNTextDetector from "rn-text-detector";

Create a state to our app.

const [state, setState] = useState<{
  loading: boolean;
  image: string | null;
  toast: { 
   message: string;
   isVisible: boolean;
  };
  textRecognition: [] | null; 
 }>({
  loading: false,
  image: null,
  textRecognition: null,
  toast: {
  message: "",
  isVisible: false,
  },
 });

Add the following functions in order to perform a simple string.

function onPress(type: "capture" | "library") {
 setState({ ...state, loading: true });
 type === "capture"
  ? launchCamera({ mediaType: "image" }, onImageSelect)
  : launchImageLibrary({ mediaType: "image" }, onImageSelect);
}async function onImageSelect(media: { assets: [{ uri: string }] }) {
 if (!media) {
  setState({ ...state, loading: false });
  return;
 }
 if (!!media && media.assets) {
  const file = media.assets[0].uri; 
  const textRecognition = await RNTextDetector.detectFromUri(file);
  const INFLIGHT_IT = "Inflight IT";
  //if match toast will appear 
  const matchText = textRecognition.findIndex((item: { text: string      
  }) => item.text.match(INFLIGHT_IT));
  setState({
   ...state,
   textRecognition,
   image: file,
   toast: {
   message: matchText > -1 ? "Ohhh i love this company!!" : "",
   isVisible: matchText > -1, 
   },
   loading: false,
  });
}}

Make your view to display text and image.

return (
  <SafeAreaView style={styles.container}>
   <View style={styles.content}>
    <Text style={styles.title}>RN OCR SAMPLE</Text>
   <View style={getSpace(20)}>
    <TouchableOpacity style={[styles.button, styles.shadow]}
    onPress={() => onPress("capture")}>
     <Text>Take Photo</Text>
    </TouchableOpacity>
   <View style={getSpace(20)}> 
    <TouchableOpacity
     style={[styles.button, styles.shadow]}
     onPress={() => onPress("library")}
    >
     <Text>Pick a Photo</Text>
    </TouchableOpacity>
   </View>
   <View style={getSpace(50)}>
    <WrapLoading loading={state.loading}>
     <View style={{ alignItems: "center" }}>
      <Image style={[styles.image, styles.shadow]}
       source={{ uri: state.image }} />
     </View> 
   {!!state.textRecognition && 
    state.textRecognition.map(
     (item: { text: string }, i: number) => (
      <Text key={i} style={getSpace(10)}>
       {item.text}
      </Text>
     ))}
     </WrapLoading>
    </View>
   </View>
   {state.toast.isVisible &&
    ToastAndroid.showWithGravityAndOffset(
      state.toast.message,
      ToastAndroid.LONG,
      ToastAndroid.BOTTOM,
      25,
      50
    )}
   </View>
  </SafeAreaView>
);

Then just try it! 🚀




5. Conclusion

With a few steps you can achieve text-recognition with only 2 libraries without using Firebase at all. Hope you enjoy it!