React Native Camera: Access snapped image - ios

I am using the react-native-camera plugin in my app. I am trying to take an image and then immediately upload it to an AWS S3 bucket via AWS Amplify.
My Code looks like this:
export default class Camera extends Component {
render() {
return (
<View style={styles.container}>
<RNCamera
ref={ref => {
this.camera = ref;
}}
style={styles.preview}
flashMode={RNCamera.Constants.FlashMode.auto}
permissionDialogTitle={'Permission to use camera'}
permissionDialogMessage={'We need your permission to use your phone\'s camera'}
/>
<TouchableOpacity
onPress={this.takePicture.bind(this)}
style={styles.capture}
>
<Text style={{fontSize: 15}}> SNAP </Text>
</TouchableOpacity>
</View>
);
}
takePicture = async function () {
if (this.camera) {
const options = {base64: true};
const data = await this.camera.takePictureAsync(options);
console.log(data.uri);
uploadPictureToS3(data.uri, "image.jpg");
}
};
}
function readFile(fileUri) {
return RNFetchBlob.fs.readFile(fileUri, 'base64').then(data => new Buffer(data, 'base64'));
}
function uploadPictureToS3(uri, key) {
readFile(uri).then(buffer => {
Storage.put(key, buffer, {
contentType: "image/jpeg"
})
})
.then(r => {
console.log(r);
})
.catch(e => {
console.error(e);
});
}
When trying to access the file using the readFile method I get the following error: Error: file not exists.
What is happening here? Why am I not able to read the image from the cache folder directly after it was taken?

Your code looks alright although there are some "weird" stuff.
You pass the option base64 to the takePictureAsync. This makes the camera return the base64 of picture taken automatically, but you do not use it for anything. You can do uploadPictureToS3(data.base64, "image.jpg"); And skip the readFile method.
Another thing is, don't know why it is like this, to get the image base64 from the uri we usually do:
const filepath = data.uri.split('//')[1];
const imageUriBase64 = await RNFS.readFile(filepath, 'base64');
So try the const filepath = data.uri.split('//')[1]; trick instead of passing data.uri directly.

i am using the RNCamera plugin in this app,this code show image tack by camera in app
import React, { Component } from 'react';
import { StyleSheet, Text, TouchableOpacity, View, Image } from 'react-native';
import { RNCamera } from 'react-native-camera';
export default class CameraPage extends Component {
constructor(props) {
super(props);
this.state = {
img : '',
}
}
takePicture = async function(camera) {
const options = { quality: 0.5, base64: true };
const data = await camera.takePictureAsync(options);
this.setState({
img: data.uri
})
};
render() {
const{img}= this.state;
return (
<View style={styles.container}>
<RNCamera
style={styles.preview}
type={RNCamera.Constants.Type.back}
flashMode={RNCamera.Constants.FlashMode.off}
permissionDialogTitle={'Permission to use camera'}
permissionDialogMessage={'We need your permission to use your camera phone'}
>
{({ camera}) => {
return (
<View style={{ flex: 0, flexDirection: 'row', justifyContent: 'center' }}>
<TouchableOpacity onPress={() => this.takePicture(camera)} style={styles.capture}>
<Text style={{ fontSize: 14 }}> SNAP </Text>
</TouchableOpacity>
</View>
);
}}
</RNCamera>
<View style={{flex:1,justifyContent: 'center', alignItems: 'center'}}>
<Image source={{uri:img}} style={{ width: 200, height: 200}}/>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'column',
backgroundColor: 'black',
},
preview: {
flex: 2,
justifyContent: 'flex-end',
alignItems: 'center',
},
capture: {
flex: 0,
backgroundColor: '#fff',
borderRadius: 5,
padding: 15,
paddingHorizontal: `**enter code here**`20,
alignSelf: 'center',
margin: 20,
},
});

Related

React Native- Touchable not working and no errors?

I am trying to detect touch on a view in React Native. I followed this link and incorporated the Touchable around my styled view like so:
<TouchableWithoutFeedback onPress={cardPressed}>
<View style={styles.card}>
<Text style={styles.card_Head}>What is Something?</Text>
<Text style={styles.card_Body}>Something</Text>
</View>
</TouchableWithoutFeedback>
I am using a functional component, so after export default function App() { I have:
function cardPressed()
{
console.log('pressed');
}
No errors, but I get nothing. What is wrong w this implementation?
Check your import. You should import TouchableWithoutFeedback from react-native and not from react-native-gesture-handler
Check out this code.
import React, { useState } from "react";
import { StyleSheet, TouchableWithoutFeedback, Text, View } from "react-native";
const App = () => {
const [count, setCount] = useState(0);
const cardPressed = () => {
console.log('pressed');
setCount(count + 1);
};
return (
<View style={styles.container}>
<View style={styles.countContainer}>
<Text style={styles.countText}>Count: {count}</Text>
</View>
<TouchableWithoutFeedback onPress={cardPressed}>
<View style={styles.button}>
<Text style={styles.card_Head}>What is Something?</Text>
<Text style={styles.card_Body}>Something</Text>
</View>
</TouchableWithoutFeedback>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
paddingHorizontal: 10
},
button: {
alignItems: "center",
backgroundColor: "#DDDDDD",
padding: 10
},
countContainer: {
alignItems: "center",
padding: 10
},
countText: {
color: "#FF00FF"
},
card_Head: {
fontWeight: 'bold',
fontSize: 24
},
card_Body: {
fontStyle: 'italic'
}
});
export default App;

ipfs.cat returns "undefined" object in React-native

On React-native:
When I add a buffered string(i.e. Buffer(str) ) to IPFS using ipfs.add, the buffered string is added successfully and IPFS returns the hash.
When I try to retrieve the buffered string via ipfs.cat and the hash, ipfs.cat returns "undefined".
On Node.jS and ReactJs:
I do not have this problem. Both ipfs.add and ipfs.cat works.
Is the problem related to pinning in IPFS? or would changing the ipfs-api version in packag.json help?
Any help would be highly appreciated.
Below is the app.js code used for React-Native
import React, {useState, useRef} from 'react';
import {StyleSheet, Text, View, StatusBar, Button} from 'react-native';
const CryptoJS = require('crypto-js');
const ipfsAPI = require('ipfs-api');
// Connceting to the ipfs network via infura gateway
const ipfs = ipfsAPI('ipfs.infura.io', '5001', {protocol: 'https'});
export default function App() {
const [number, setNumber] = useState(0);
const [hash, setHash] = useState(' ');
console.log('printing: ', number);
//console.log('testing:', ipfs);
const handleCaseAdd = () => {
setNumber(1);
// Encrypt
const ciphertext = CryptoJS.AES.encrypt(
JSON.stringify('my message'),
'secret key 1234',
).toString();
console.log(' Ciphertext: ', ciphertext); // 'ciphertext
console.log('Buffered ciphertext: ', Buffer(ciphertext));
// Adding the encrpyted file to IPFS
ipfs.add(Buffer(ciphertext), {pin: true}, (error, result) => {
if (error) {
console.log(error);
return;
}
setHash(result[0].hash);
console.log('File added succesfully');
console.log('IPFS result: ', result);
});
}; // end of the function
const handleCaseGet = fileHash => {
//const fileHash = hash;
console.log('fileHash (before) :', fileHash);
ipfs.files.cat(fileHash, function(err, bufferedCiphertext) {
console.log('fileHash (after) :', fileHash);
console.log('Getting Buffered ciphertext: ', bufferedCiphertext);
});
}; // end of the function
//let confirmed;
//confirmed = true;
return (
<View style={styles.container}>
<View style={styles.first}>
<View style={styles.box1} />
<View style={styles.box2} />
</View>
<View>
<Button title="Add" onPress={handleCaseAdd} />
</View>
<Text> Number: {number} </Text>
<Text> Hash: {hash} </Text>
<View>
<Button title="Get" onPress={handleCaseGet.bind(this, hash)} />
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'white',
//alignItems: "center",
//justifyContent: "center",
paddingTop: StatusBar.currentHeight,
},
first: {
backgroundColor: 'green',
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'flex-start',
},
box1: {
backgroundColor: 'dodgerblue',
width: 50,
height: 50,
//flex: 1,
},
box2: {
backgroundColor: 'gold',
width: 50,
height: 50,
//alignSelf: "flex-start",
},
});
ipfs-api has been deprecated for two years, the replacement is ipfs-http-client - could you please try with that module instead?
https://www.npmjs.com/package/ipfs-http-client

Google SignIn for IOS with React-native (expo)

I'm setting up a page where I can Id with a Google account. This is my code:
import React from "react"
import { StyleSheet, Text, View, Image, Button } from "react-native"
import * as Google from "expo-google-app-auth";
export default class App extends React.Component {
constructor(props) {
super(props)
this.state = {
signedIn: false,
name: "",
photoUrl: ""
}
}
signIn = async () => {
try {
const result = await Google.logInAsync({
androidClientId:
"1051966217196.apps.googleusercontent.com",
iosClientId:
"1051966217196.apps.googleusercontent.com",
scopes: ["profile", "email"]
})
if (result.type === "success") {
this.setState({
signedIn: true,
name: result.user.name,
photoUrl: result.user.photoUrl
})
} else {
console.log("cancelled")
}
} catch (e) {
console.log("error", e)
}
}
render() {
return (
<View style={styles.container}>
{this.state.signedIn ? (
<LoggedInPage name={this.state.name} photoUrl={this.state.photoUrl} />
) : (
<LoginPage signIn={this.signIn} />
)}
</View>
)
}
}
const LoginPage = props => {
return (
<View>
<Text style={styles.header}>Sign In With Google</Text>
<Button title="Sign in with Google" onPress={() => props.signIn()} />
</View>
)
}
const LoggedInPage = props => {
return (
<View style={styles.container}>
<Text style={styles.header}>Welcome:{props.name}</Text>
<Image style={styles.image} source={{ uri: props.photoUrl }} />
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center"
},
header: {
fontSize: 25
},
image: {
marginTop: 15,
width: 150,
height: 150,
borderColor: "rgba(0,0,0,0.2)",
borderWidth: 3,
borderRadius: 150
}
})
On Android it's ok, everything is fine but in IOS I have that mistake :
Google 400 - That's an error - Error : redirect_uri_mismatch
Where is it goes wrong? I'm new to react native so I need detailed explanations.
I changed the bundle identifier to host.exp.exponent in Google credentials and it works. It's weird because I didn't change it in app.json. But it works.

react-native: image won't rerender when state changes

I have an icon as an image and I want to change the icon when a state property changes. Here is the relevant code:
<TouchableHighlight underlayColor="rgba(0,0,0,0)" style={styles.playButton} onPress={this._handleStartPress}>
<Image source={(this.state.started) ? require('./Control-pause.png') : require('./Control-play.png')} resizeMode="contain" style={styles.icon}/>
</TouchableHighlight>
The state changes correctly as expected (verifed by some console logs), but somehow the Image won't re render and change when this.state.started changes. The path to the images is also correct.
Any Ideas what's the problem?
EDIT: The whole component:
import React, {
AppRegistry,
Component,
StyleSheet,
Text,
TouchableHighlight,
View,
ScrollView,
Vibration,
AlertIOS,
Image
} from 'react-native'
/*import Icon from 'react-native-vector-icons/FontAwesome';*/
const timer = require('react-native-timer');
const Button = require('./components/Button.js');
const PlayIcon = require('./Control-play.png');
const PauseIcon = require('./Control-pause.png');
class Project extends Component {
constructor(props) {
super(props);
this.state = {
timerValue: 25*60,
count: 0,
started: false,
};
this._tick = this._tick.bind(this);
this._runClock = this._runClock.bind(this);
this._stopClock = this._stopClock.bind(this);
this._handlePomodoroPress = this._handlePomodoroPress.bind(this);
this._handlePausePress = this._handlePausePress.bind(this);
this._getMinsSecs = this._getMinsSecs.bind(this);
this._finishedTimer = this._finishedTimer.bind(this);
this._handleStartPress = this._handleStartPress.bind(this);
}
_tick() {
if (this.state.timerValue > 0) {
this.setState({timerValue: this.state.timerValue - 1});
} else {
this._finishedTimer();
}
}
_finishedTimer() {
this.setState({started: false});
timer.clearInterval('timer');
Vibration.vibrate();
AlertIOS.alert("Time's up!");
}
_runClock() {
this.setState({started: true});
console.log("running: ", this.state.started);
timer.setInterval('timer', this._tick, 1000);
}
_stopClock() {
this.setState({started: false});
console.log("running: ", this.state.started);
timer.clearInterval('timer');
}
_getMinsSecs(seconds) {
let mins = Math.floor(seconds / 60);
let secs = seconds - mins * 60;
return (mins < 10 ? "0" : "") + mins + ":" + (secs <10 ? "0" : "") + secs;
}
_handleStartPress() {
if (!this.state.started) {
this._runClock();
} else {
this._stopClock();
}
}
_handlePomodoroPress() {
if (!this.state.started) {
this.setState({timerValue: 25*60});
}
}
_handlePausePress() {
if(!this.state.started) {
this.setState({ timerValue: 5*60 });
}
}
render() {
return (
<View style={styles.container}>
<View style={styles.timeWrapper}>
<View style={styles.line}/>
<Text style={styles.time}>{this._getMinsSecs(this.state.timerValue)}</Text>
<View style={styles.line}/>
</View>
<TouchableHighlight underlayColor="rgba(0,0,0,0)" style={styles.playButton} onPress={this._handleStartPress}>
<Image source={(this.state.started) ? require('./Control-pause.png') : require('./Control-play.png')} resizeMode="contain" style={styles.icon}/>
</TouchableHighlight>
<View style={styles.buttonWrapper}>
<Button
value="Pomodoro"
onPress={this._handlePomodoroPress}/>
<Button value="Pause" onPress={this._handlePausePress}/>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "space-around",
alignItems: 'center',
backgroundColor: "#7CCF9E"
},
time: {
fontSize: 74,
color: '#fff',
fontWeight: '200'
},
buttonWrapper: {
justifyContent: 'center',
alignItems: 'center'
},
playButton: {
width: 79,
height: 79,
borderRadius: 100,
borderWidth: 3,
borderColor: '#fff',
alignItems: 'center',
justifyContent: 'center'
},
line: {
marginTop: 10,
height: 3,
width: 200,
backgroundColor: '#fff'
},
timeWrapper: {
alignItems: 'center'
},
icon: {
height: 42,
}
});
AppRegistry.registerComponent('Project', () => Project);
something like this works easily:
<TouchableHighlight underlayColor="rgba(0,0,0,0)" style={styles.playButton} onPress={this._handleStartPress}>
<Text>{this.state.started ? "started" : "stopped"}</Text>
</TouchableHighlight>
EDIT2:
I found what causes the picture not to rerender!!!!
When I style the size in the StyleSheet it won't rerender ... If it has no size style everything is fine!
require calls are not dynamic. They are statically analyzed and bundled. https://github.com/facebook/react-native/issues/2481 . As Andrew Axton suggested, load them in separate variables outside of render and using that in the conditional should work.

React Native with Redux- Problems updating state correctly

I'm trying to upload images that I've base64 encoded but it doesn't seem to save the state to the app so I can upload the images to my server. The state only seems to save within the function and not to the entire component. Any suggestions as to what I'm doing wrong?
_selectImage(uri) {
NativeModules.ReadImageData.readImage(uri, (image) => {
this.state = {
selected: image
};
console.log(this.state)
});
}
render() {
return (
<View style={styles.container}>
<View style={{ flex: 1, flexDirection: 'row', alignItems: 'center', justifyContent: 'center', }}>
<TouchableOpacity style={ styles.button } onPress={ this._addImage.bind( this ) }>
<Text>Add Image</Text>
</TouchableOpacity>
<TouchableOpacity style={ styles.button } onPress={this._uploadImage} >
<Text>Upload Image</Text>
</TouchableOpacity>
</View>
<ScrollView style={styles.container}>
<View style={styles.imageGrid}>
{ this.state.images.map((image) => {
return (
<TouchableHighlight onPress={this._selectImage.bind(null, image.uri)}>
<Image key={ _generateUUID() } style={styles.image} source={{ uri: image.uri }} />
</TouchableHighlight>
);
})
}
</View>
</ScrollView>
</View>
);
}
};
First, this-bind your _selectImage-method in constructor. Then use "setState" instead of this.state = {...}
You need only once to create the state object, best in constructor. Use then setState instead for further modifications.
constructor(props) {
super(props);
this.state = {selected: null};
this._selectImage = this._selectImage.bind(this);
}
_selectImage(uri) {
NativeModules.ReadImageData.readImage(uri, (image) => {
this.setState({
selected: image
});
console.log(this.state)
});
}

Resources