最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Decode QR Code Image from Camera Roll React Native - Stack Overflow

programmeradmin2浏览0评论

I'm trying to implement a feature in my app where I the user can select a picture from their camera roll and the app will decode a QR code in the image is detected.

I'm currently using react-native-camera-roll-picker: and react-native-qrcode-local-image:

The problem is the local QR code image library wants me to pass a local path and isn't compatible with the native uri provided by react-native-camera-roll-picker. I would use another library for decoding the image QR code but this one appears to be the only one that works on iOS and Android and scans from existing images rather than from the actual camera.

I've also tried implementing react-native-fetch-blob in order to temporarily save the camera roll image locally, but that's been giving me trouble as well:

This is my current attempt in a function that I call in the "callback" prop for react-native-camera-roll-picker (with previous attempts commented out):

_pickedImage(array,currentImg) {
console.log(currentImg)
var path = RNFS.DocumentDirectoryPath + '/pickedqr';
let rnfbURI = RNFetchBlob.wrap(RNFetchBlob.fs.asset(currentImg.uri))
const Blob = RNFetchBlob.polyfill.Blob
Blob.build(rnfbURI, {type:'image/jpg'}).then((b) => {
  tmpBlob = b;
  RNFetchBlob.fs.readFile(tmpBlob, 'base64').then((data) => {
    console.log("Base64", data)
    QRDecoder.decode(`data:image/gif;base64,${data}`, (error, result)=>{
      console.log("Code", result)
      console.log("Error", error)
    });
  });
})
/*fullPath = currentImg.uri.replace("assets-library://", "cdvfile://localhost/assets-library/")
QRDecoder.decode(fullPath, (error, result)=>{
  console.log("Code", result)
  console.log("Error", error)
});*/
/*let blb = Blob.build( rnfbURI, { type: 'image/jpg'})
console.log(blb)*/
/*RNFetchBlob.fs.readFile(rnfbURI, 'base64').then((data) => {
  console.log("Base64", data)
  QRDecoder.decode(`data:image/gif;base64,${data}`, (error, result)=>{
    console.log("Code", result)
    console.log("Error", error)
  });
})*/
}

I'm at a total loss at the moment so any methods or insight would be much appreciated.

I'm trying to implement a feature in my app where I the user can select a picture from their camera roll and the app will decode a QR code in the image is detected.

I'm currently using react-native-camera-roll-picker: https://github.com/jeanpan/react-native-camera-roll-picker and react-native-qrcode-local-image: https://github.com/remobile/react-native-qrcode-local-image

The problem is the local QR code image library wants me to pass a local path and isn't compatible with the native uri provided by react-native-camera-roll-picker. I would use another library for decoding the image QR code but this one appears to be the only one that works on iOS and Android and scans from existing images rather than from the actual camera.

I've also tried implementing react-native-fetch-blob in order to temporarily save the camera roll image locally, but that's been giving me trouble as well: https://github.com/wkh237/react-native-fetch-blob

This is my current attempt in a function that I call in the "callback" prop for react-native-camera-roll-picker (with previous attempts commented out):

_pickedImage(array,currentImg) {
console.log(currentImg)
var path = RNFS.DocumentDirectoryPath + '/pickedqr';
let rnfbURI = RNFetchBlob.wrap(RNFetchBlob.fs.asset(currentImg.uri))
const Blob = RNFetchBlob.polyfill.Blob
Blob.build(rnfbURI, {type:'image/jpg'}).then((b) => {
  tmpBlob = b;
  RNFetchBlob.fs.readFile(tmpBlob, 'base64').then((data) => {
    console.log("Base64", data)
    QRDecoder.decode(`data:image/gif;base64,${data}`, (error, result)=>{
      console.log("Code", result)
      console.log("Error", error)
    });
  });
})
/*fullPath = currentImg.uri.replace("assets-library://", "cdvfile://localhost/assets-library/")
QRDecoder.decode(fullPath, (error, result)=>{
  console.log("Code", result)
  console.log("Error", error)
});*/
/*let blb = Blob.build( rnfbURI, { type: 'image/jpg'})
console.log(blb)*/
/*RNFetchBlob.fs.readFile(rnfbURI, 'base64').then((data) => {
  console.log("Base64", data)
  QRDecoder.decode(`data:image/gif;base64,${data}`, (error, result)=>{
    console.log("Code", result)
    console.log("Error", error)
  });
})*/
}

I'm at a total loss at the moment so any methods or insight would be much appreciated.

Share Improve this question edited Dec 26, 2018 at 11:40 p u 1,4551 gold badge20 silver badges30 bronze badges asked Mar 11, 2017 at 13:57 ArminArmin 1,2813 gold badges18 silver badges31 bronze badges 5
  • Is it possible to use github.com/marcshilling/react-native-image-picker instead of react-native-camera-roll-picker – Tobias Lins Commented Mar 14, 2017 at 9:46
  • @TobiasLins I'd much prefer sticking with react-native-camera-roll-picker for UI purposes – Armin Commented Mar 14, 2017 at 17:29
  • @TobiasLins I noticed you commented earlier with a potential solution but it got removed before I could read it. Do you have any insight? – Armin Commented Mar 18, 2017 at 18:36
  • Problem is camera-roll-picker uses ALAsset library whose path is not absolute url of file system rather temporary path which is not recognised by qrcode-local-image library. You need to change image picker library else yo need to change code in RCTQRCodeLocalImage.m#23 with this solution http://stackoverflow.com/questions/7221167/how-to-check-if-an-alasset-still-exists-using-a-url. – Sagar Khatri Commented Mar 20, 2017 at 6:53
  • @Armin Do you found any solution? – Carolina Commented Apr 21, 2017 at 20:50
Add a comment  | 

5 Answers 5

Reset to default 1

you can use react-native-qrcode-scanner to scan QR from images or directly through the camera.

INSTALLATION:

install dependency by using this command:

yarn add react-native-camera react-native-qr-scanner

link those libraries by using:

react-native link react-native-camera && react-native-qr-scanner

you need to add the permission to your AndroidManifest.xml of your project. This should be found in your android/app/src/main/AndroidManifest.xml Add the following:

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

With iOS 10 and higher, you need to add the "Privacy - Camera Usage Description" key to the info.plist of your project. This should be found in your_project/ios/your_project/Info.plist. Add the following code:

<key>NSCameraUsageDescription</key>
<string/>
<key>NSPhotoLibraryUsageDescription</key>
<string/>
<key>NSMicrophoneUsageDescription</key>
<string/>
<key>NSPhotoLibraryAddUsageDescription</key>
<string/>

Usage:

import React, {Component} from 'react';
import {Platform, StyleSheet, Text, View, TouchableOpacity} from 'react-native';
import {QRreader} from 'react-native-qr-scanner';
import ImagePicker from 'react-native-image-picker';
 
export default class Scanner extends Component {
  constructor(props) {
    super(props);
    this.state = {
      reader: {
        message: null,
        data: null
      }
    };
  }
  render() {
    return (
      <View style={styles.container}>
        <TouchableOpacity onPress={()=>{
          this.openPhoto();
        }}>
          <Text style={{marginTop: 20}}>打开相册识别二维码</Text>
        </TouchableOpacity>
        <View>
        {!this.state.reader? <Text>{!this.state.reader.message?'':`${this.state.reader.message}`}</Text>: <Text>{!this.state.reader.message?'':`${this.state.reader.message}:${this.state.reader.data}`}</Text>}
        </View>
      </View>
    );
  }
  
  openPhoto(){
    console.log('ImagePicker');
    ImagePicker.launchImageLibrary({}, (response) => {
      console.log('Response = ', response);
    
      if (response.didCancel) {
        console.log('User cancelled image picker');
      }
      else if (response.error) {
        console.log('ImagePicker Error: ', response.error);
      }
      else if (response.customButton) {
        console.log('User tapped custom button: ', response.customButton);
      }
      else {
        if(response.uri){
          var path = response.path;
          if(!path){
              path = response.uri;
          }
          QRreader(path).then((data)=>{
            this.setState({reader: {
              message: '识别成功',
              data: data
            }});
            // 十秒后自动清空
            setTimeout(() => {
              this.setState({reader: {
                message: null,
                data: null
              }})
            }, 10000);
          }).catch((err)=>{
            this.setState({reader: {
              message: '识别失败',
              data: null
            }});
          });
          
      }
      }
    });
  }
}
const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff'
  }
});

you can read more about this library here: https://www.npmjs.com/package/react-native-qr-scanner

You can use react-native-camera to solve this issue easily.

Here's the simple code snippet for that.

handleCodeDetected = (data) => {
// do whatever you want to do with data    
}

...
...

<RNCamera
  type={RNCamera.Constants.Type.back}
  barCodeTypes={[RNCamera.Constants.BarCodeType.qr]}
  onBarCodeRead={this.handleCodeDetected}
  style={styles.preview}
/>

This answer solved it for me. Created native method to covert uri in path, here is my code:

    @ReactMethod
    public void getRealPathFromURI(String contentUriString, Promise promise) {
        Uri contentUri = Uri.parse(contentUriString);
        Cursor cursor = null;
        try {
            String wholeID = DocumentsContract.getDocumentId(contentUri);
            String id = wholeID.split(":")[1];

            String[] column = { MediaStore.Images.Media.DATA };

            String sel = MediaStore.Images.Media._ID + "=?";

            cursor = reactContext.getContentResolver().
                    query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                            column, sel, new String[]{ id }, null);

            int columnIndex = cursor.getColumnIndex(column[0]);

            String filePath = "";
            if (cursor.moveToFirst()) {
                filePath = cursor.getString(columnIndex);
            }
            promise.resolve(filePath);
        } catch (Throwable e) {
            promise.reject(e);
        } finally {
            if (cursor != null) {
                cursor.close();
            }
        }
    }

And js:

DocumentPicker.pick({ type }).then((document: DocumentPickerResponse) => {
    MyNativeModule.getRealPathFromURI(document.uri).then((path) => {
        QRCodeLocalImage.decode(path, (err, res) => {
            callback(err, { qrData: res });
        });
    });
});

You can just use react-native-rn-zxing:

npm i react-native-rn-zxing

then link it :

react-native link react-native-rn-zxing

Usage :

import RnZxing from 'react-native-rn-zxing';
 
...
// Pass the callback as a parameter
RnZxing.showQrReader(this.onBarcodeScanned);
 
...
// Define the callback function to handle data after scan
onBarcodeScanned = (data) => {
        this.setState({data: data});
};

You can use rn-qr-generator

It can detect QR code in image


RNQRGenerator.detect({
  uri: PATH_TO_IMAGE, // local path of the image. Can be skipped if base64 is passed.
  base64: imageBase64String, // If uri is passed this option will be skipped.
})
  .then(response => {
    const { values } = response; // Array of detected QR code values. Empty if nothing found.
  })

发布评论

评论列表(0)

  1. 暂无评论