OCR-сканер Card2Contact | Кодементор

Это демонстрационное учебное приложение для создания сканера OCR для визитных карточек и сохранения информации в списке контактов телефона. В этом случае я буду ориентироваться только на систему iOS, но это можно сделать и для Android. я звоню в это приложение Card2Контакты и это часть Аламеда Дев Исследования

Основные пакеты, которые нам понадобятся, это пакет для чтения изображений с камеры (react-native-camera).

Создание базового приложения React Native

react-native init Card2Contact

Установить зависимости

yarn add react-native-camera --save

Настройте пакет реактивной камеры

react-native link react-native-camera

Для iOS мы должны установить разрешения.
в Информация.plist файл добавить описание для NSCameraUsageОписание ключ. Это требуется Apple, и в нем говорится, почему вам нужен доступ к камере.
Вам также нужно NSPhotoLibraryUsageDescription клавиша для сохранения изображения в библиотеке телефона.

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

Основной экран компонента камеры

  import React, {Component} from 'react';
  import {StyleSheet, Dimensions, Text, View} from 'react-native';
  import Camera from 'react-native-camera';

  export default class App extends Component<Props> {
    takePicture() { 
      this.camera.capture()
        .then((data) => console.log(data))
        .catch(err => console.error(err));
    }

    render() {
      return (
        <View style={styles.container}>
          <Camera
            ref={cam => { this.camera = cam }}
            style={styles.preview}
            aspect={Camera.constants.Aspect.fill}>
              <Text style={styles.capture} onPress={this.takePicture.bind(this)}> [CAPTURE CARD]</Text>
          </Camera>
        </View>
      );
    }
  }

  const styles = StyleSheet.create({
    container: {
      flex: 1,
      justifyContent: 'center',
      alignItems: 'center',
      backgroundColor: '#F5FCFF',
    },
    preview: { 
      flex: 1,
      justifyContent: 'flex-end',
      alignItems: 'center',
      height: Dimensions.get('window').height,
      width: Dimensions.get('window').width
    },
    capture: {
      flex: 0,
      backgroundColor: '#fff',
      borderRadius: 5,
      color: '#000',
      padding: 10,
      margin: 40
    }
  });


Добавить навигацию, чтобы показать экран фотографий для обработки

yarn add react-navigation --save
yarn add react-native-gesture-handler --save
react-native link react-native-gesture-handler

Реорганизуйте код, чтобы добавить навигацию

App.js

  import React, {Component} from 'react';
  import {StyleSheet, Dimensions, Text, View} from 'react-native';

  import CameraScreen from './src/screens/CameraScreen'
  import ContactScreen from './src/screens/ContactScreen'

  import {createStackNavigator, createAppContainer} from 'react-navigation';

  const AppNavigator = createStackNavigator({
    CameraScreen: {
      screen: CameraScreen
    },
    ContactScreen: {
      screen: ContactScreen
    }
  });

  const AppContainer = createAppContainer(AppNavigator);

  export default class App extends React.Component {
    render() {
      return <AppContainer />;
    }
  }

CameraScreen.js

  import React, { Component } from 'react';
  import { StyleSheet, Dimensions, Text, View } from 'react-native';
  import { RNCamera } from 'react-native-camera';

  export default class CameraScreen extends Component {
    takePicture = async function() {
      if (this.camera) {
        const options = { quality: 0.5, base64: true };
        const data = await this.camera.takePictureAsync(options)
        console.log(data.uri);
      }
    };

    render() {
      return (
        <View style={styles.container}>
          <RNCamera
            ref={cam => { this.camera = cam }}
            style={styles.preview}
            >
              <Text style={styles.capture} onPress={this.takePicture.bind(this)}> [CAPTURE CARD]</Text>
          </RNCamera>
        </View>
      );
    }
  }

  const styles = StyleSheet.create({
    container: {
      flex: 1,
      justifyContent: 'center',
      alignItems: 'center',
      backgroundColor: '#F5FCFF',
    },
    preview: { 
      flex: 1,
      justifyContent: 'flex-end',
      alignItems: 'center',
      height: Dimensions.get('window').height,
      width: Dimensions.get('window').width
    },
    capture: {
      flex: 0,
      backgroundColor: '#fff',
      borderRadius: 5,
      color: '#000',
      padding: 10,
      margin: 40
    }
  });

ContactScreen.js

  import React, { Component } from 'react';
  import { StyleSheet, Text, View } from 'react-native';

  export default class ContactScreen extends Component {
    render() {
      return (
        <View style={styles.container}>
          <Text>ContactScreen</Text>
        </View>
      );
    }
  }

  const styles = StyleSheet.create({
    container: {
      flex: 1,
      justifyContent: 'center',
      alignItems: 'center',
      backgroundColor: '#F5FCFF',
    }
  });

У Google есть отличный API для обнаружения и извлечения текста (OCR), который мы можем использовать для этой цели. Для использования этого API вам необходимо создать Проект Google Cloud Platform (GCP)

Перейдите на веб-страницу и создайте новый проект

После этого перейдите в свой проект и создайте API учетных данных для использования в вашем проекте React Native.

Скопируйте свой ключ API и сохраните его в надежном месте.

Давайте добавим Vision API для этого проекта

Найдите Vision API и нажмите ВКЛЮЧИТЬ.

Не забудьте включить биллинг для проектов, так как это НЕОБХОДИМО.

Код для обнаружения текста

Давайте изменим код в CameraScreen.js файл и добавьте новый метод для подключения к Google Vision API.

Конечная точка API для Google Vision: И вам нужно передать ключ для аутентификации.

CameraScreen.js

  takePicture = async function() {
    if (this.camera) {
      const options = { quality: 0.5, base64: true };
      const data = await this.camera.takePictureAsync(options)
      this.detectText(data.base64)
    }
  };

  detectText(base64){
    fetch("?key=" + "YOUR API KEY", {
        method: 'POST',
        body: JSON.stringify({
          "requests": [{
            "image": { "content": base64 },
            "features": [
                { "type": "TEXT_DETECTION" }
            ]}]
      })
    })
    .then(response => { return response.json()})
    .then(jsonRes => {
      let text = jsonRes.responses[0].fullTextAnnotation.text
      this.props.navigation.navigate('ContactScreen', { text: text })
    }).catch(err => {
      console.log('Error', err)
    })
  }

ConatctScreen.js

  import React, { Component } from 'react';
  import { StyleSheet, Text, View } from 'react-native';

  export default class ContactScreen extends Component {
    constructor(props){
      super(props)

      const { navigation } = this.props
      const text  = navigation.getParam('text')
      const lines = text.match(/[^\r\n]+/g)

      this.state = {
        text: text,
        lines: lines
      }

      console.log('text', text)
      console.log('lines', lines)
    }

    render() {
      return (
        <View style={styles.container}>
          <Text>ContactScreen</Text>
        </View>
      );
    }
  }

  const styles = StyleSheet.create({
    container: {
      flex: 1,
      justifyContent: 'center',
      alignItems: 'center',
      backgroundColor: '#F5FCFF',
    }
  });

Давайте отобразим список текста, возвращаемый API Google, и вместе с ним форму для выбора типа текста, чтобы классифицировать его для контакта.

npm install react-native-picker-select

А также добавить внизу кнопку для сохранения информации.

  import React, { Component } from 'react';
  import { StyleSheet, Text, View, ScrollView, TouchableOpacity} from 'react-native';
  import RNPickerSelect from 'react-native-picker-select';

  export default class ContactScreen extends Component {
    static navigationOptions = {
      title: 'New Contact'
    }

    constructor(props){
      super(props)
      const { navigation } = this.props
      const text  = navigation.getParam('text')
      const lines = text.match(/[^\r\n]+/g)

      this.state = {
        text: text,
        lines: lines,
        contact: {
          familyName: null,
          givenName: null,
          phoneNumbers: [],
          emailAddresses: [],
          company: null
        },

        lineTypes: [
          {label: 'Last Name', value: 'familyName'},
          {label: 'First Name', value: 'givenName'},
          {label: 'Phone Number', value: 'phoneNumbers'},
          {label: 'Email Address', value: 'emailAddresses'},
          {label: 'Company', value: 'company'}
        ]
      }

      this.selectedType = this.selectedType.bind(this)
    }

    selectedType(type, value) {
      var updatedContact = Object.assign({}, this.state.contact)

      if (type == 'phoneNumbers') {
        updatedContact[type].push({label: "mobile", number: value.replace(/ /g,'')})
      } else if (type == 'emailAddresses'){
        updatedContact[type].push({label: "work", email: value.replace(/ /g,'')})
      } else {
        updatedContact[type] = value
      }

      this.setState({contact:updatedContact});
    }

    render() {
      console.log('state', this.state)
      return (
        <View style={{ flex:1 }}>
          <ScrollView style={styles.container}>
            {
              this.state.lines.map((line, index) => {
                return (
                  <View style={styles.lineContainer} key={index}>
                    <Text style={styles.lineText}>{line}</Text>
                    <View style={styles.lineType}>
                      <RNPickerSelect
                        placeholder={{
                            label: 'Select type or nothing to discard',
                            value: null
                        }}
                        onValueChange={(type) => this.selectedType(type, line)}
                        items={this.state.lineTypes}
                        style={styles.picker}
                      />
                    </View>
                  </View>
                )
              })
            }
          </ScrollView>
          <TouchableOpacity
            style={styles.saveButton}
          >
            <Text>Save Contact</Text>
          </TouchableOpacity>
        </View>
      );
    }
  }

  const styles = StyleSheet.create({
    container: {
      flex: 1,
      backgroundColor: '#F5FCFF',
    },
    lineContainer: {
      flex: 1,
      borderColor: '#666666',
      borderWidth: 1,
      padding: 10
    },
    picker: {
      fontSize: 16,
      borderWidth: 1,
      borderColor: 'gray',
      borderRadius: 4,
      backgroundColor: 'white',
      color: 'black',
    },
    saveButton: {
      alignContent: 'center',
      alignSelf: 'center',
      paddingVertical: 15
    }
  });

npm install react-native-contacts --save
react-native link

Добавьте специальные ключи «разрешения» набора в свой Xcode. Информация.plist файл, чтобы заставить requestPermission работать. В противном случае ваше приложение аварийно завершает работу при запросе определенного разрешения.

Откройте Xcode> откройте ios/yourApp.xcodeproj> Info.plist> Добавить ключ Конфиденциальность — Описание использования контактов с вашим специальным разрешением. Значение ключа является необязательным при разработке. Если вы отправляете в App Store, значение должно объяснять, почему вам нужно это разрешение.

  saveContact() {
      let contact = this.state.contact

      if (contact.givenName == null || contact.phoneNumbers.length == 0) {
        alert('Select at least an option for Name and Phone')
      } else {
        Contacts.openContactForm(this.state.contact, (err) => {
          if (err) {
            alert('Select an option')
          }
          this.props.navigation.navigate('ContactScreen', { text: this.state.lines })
        })
      }
    }

И мы закончили!!




Похожие записи

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *