Je crée une application avec Expo et je souhaite que l'utilisateur prenne une photo ou en prenne une dans sa pellicule et la télécharge sur mon serveur. Comment puis-je faire cela?
Utilisez l'API Expo ImagePicker
pour afficher la caméra ou la pellicule et récupérer des informations sur l'image sélectionnée:
async function takeAndUploadPhotoAsync() {
// Display the camera to the user and wait for them to take a photo or to cancel
// the action
let result = await ImagePicker.launchCameraAsync({
allowsEditing: true,
aspect: [4, 3],
});
if (result.cancelled) {
return;
}
// ImagePicker saves the taken photo to disk and returns a local URI to it
let localUri = result.uri;
let filename = localUri.split('/').pop();
// Infer the type of the image
let match = /\.(\w+)$/.exec(filename);
let type = match ? `image/${match[1]}` : `image`;
// Upload the image using the fetch and FormData APIs
let formData = new FormData();
// Assume "photo" is the name of the form field the server expects
formData.append('photo', { uri: localUri, name: filename, type });
return await fetch(YOUR_SERVER_URL, {
method: 'POST',
body: formData,
header: {
'content-type': 'multipart/form-data',
},
});
}
Pour un exemple plus complet comprenant le code du serveur, consultez ce dépôt: https://github.com/exponent/image-upload-example .
Les exemples officiels utilisent Node.js, voici comment avec PHP:
Expo
async function takePhotoAndUpload() {
let result = await ImagePicker.launchCameraAsync({
allowsEditing: false, // higher res on iOS
aspect: [4, 3],
});
if (result.cancelled) {
return;
}
let localUri = result.uri;
let filename = localUri.split('/').pop();
let match = /\.(\w+)$/.exec(filename);
let type = match ? `image/${match[1]}` : `image`;
let formData = new FormData();
formData.append('photo', { uri: localUri, name: filename, type });
return await fetch('http://example.com/upload.php', {
method: 'POST',
body: formData,
header: {
'content-type': 'multipart/form-data',
},
});
}
pload.php
<?php
move_uploaded_file($_FILES['photo']['tmp_name'], './photos/' . $_FILES['photo']['name']);
?>
import React, { Component } from 'react';
import {
ActivityIndicator,
Button,
Clipboard,
Image,
Share,
StatusBar,
StyleSheet,
Text,
TouchableOpacity,
View,
} from 'react-native';
import { Constants } from 'expo';
import * as Permissions from 'expo-permissions';
import * as ImagePicker from 'expo-image-picker';
export default class App extends Component {
state = {
image: null,
uploading: false,
};
render() {
let {
image
} = this.state;
return (
<View style={styles.container}>
<StatusBar barStyle="default" />
<Text
style={styles.exampleText}>
Example: Upload ImagePicker result
</Text>
<Button
onPress={this._pickImage}
title="Pick an image from camera roll"
/>
<Button onPress={this._takePhoto} title="Take a photo" />
{this._maybeRenderImage()}
{this._maybeRenderUploadingOverlay()}
</View>
);
}
_maybeRenderUploadingOverlay = () => {
if (this.state.uploading) {
return (
<View
style={[StyleSheet.absoluteFill, styles.maybeRenderUploading]}>
<ActivityIndicator color="#fff" size="large" />
</View>
);
}
};
_maybeRenderImage = () => {
let {
image
} = this.state;
if (!image) {
return;
}
return (
<View
style={styles.maybeRenderContainer}>
<View
style={styles.maybeRenderImageContainer}>
<Image source={{ uri: image }} style={styles.maybeRenderImage} />
</View>
<Text
onPress={this._copyToClipboard}
onLongPress={this._share}
style={styles.maybeRenderImageText}>
{image}
</Text>
</View>
);
};
_share = () => {
Share.share({
message: this.state.image,
title: 'Check out this photo',
url: this.state.image,
});
};
_copyToClipboard = () => {
Clipboard.setString(this.state.image);
alert('Copied image URL to clipboard');
};
_takePhoto = async () => {
const {
status: cameraPerm
} = await Permissions.askAsync(Permissions.CAMERA);
const {
status: cameraRollPerm
} = await Permissions.askAsync(Permissions.CAMERA_ROLL);
// only if user allows permission to camera AND camera roll
if (cameraPerm === 'granted' && cameraRollPerm === 'granted') {
let pickerResult = await ImagePicker.launchCameraAsync({
allowsEditing: true,
aspect: [4, 3],
});
if (!pickerResult.cancelled) {
this.setState({ image: pickerResult.uri });
}
this.uploadImageAsync(pickerResult.uri);
}
};
_pickImage = async () => {
const {
status: cameraRollPerm
} = await Permissions.askAsync(Permissions.CAMERA_ROLL);
// only if user allows permission to camera roll
if (cameraRollPerm === 'granted') {
let pickerResult = await ImagePicker.launchImageLibraryAsync({
allowsEditing: true,
base64: true,
aspect: [4, 3],
});
if (!pickerResult.cancelled) {
this.setState({ image: pickerResult.uri});
}
this.uploadImageAsync(pickerResult.uri);
}
};
uploadImageAsync(pictureuri) {
let apiUrl = 'http://123.123.123.123/ABC';
var data = new FormData();
data.append('file', {
uri: pictureuri,
name: 'file',
type: 'image/jpg'
})
fetch(apiUrl, {
headers: {
'Accept': 'application/json',
'Content-Type': 'multipart/form-data'
},
method: 'POST',
body: data
}).then(
response => {
console.log('succ ')
console.log(response)
}
).catch(err => {
console.log('err ')
console.log(err)
} )
}
}
const styles = StyleSheet.create({
container: {
alignItems: 'center',
flex: 1,
justifyContent: 'center',
},
exampleText: {
fontSize: 20,
marginBottom: 20,
marginHorizontal: 15,
textAlign: 'center',
},
maybeRenderUploading: {
alignItems: 'center',
backgroundColor: 'rgba(0,0,0,0.4)',
justifyContent: 'center',
},
maybeRenderContainer: {
borderRadius: 3,
elevation: 2,
marginTop: 30,
shadowColor: 'rgba(0,0,0,1)',
shadowOpacity: 0.2,
shadowOffset: {
height: 4,
width: 4,
},
shadowRadius: 5,
width: 250,
},
maybeRenderImageContainer: {
borderTopLeftRadius: 3,
borderTopRightRadius: 3,
overflow: 'hidden',
},
maybeRenderImage: {
height: 250,
width: 250,
},
maybeRenderImageText: {
paddingHorizontal: 10,
paddingVertical: 10,
}
});
import React,{Component} from 'react';
import {
Text,
View,
Dimensions,
ActivityIndicator,
Platform,
Alert,
Linking,
StyleSheet,
Image,
TouchableOpacity,
} from 'react-native';
import { ImagePicker, Permissions } from 'expo';
import uid from 'uuid/v4';
export default class UploadImage extends Component{
constructor(props){
super(props)
this.state={
endpoint:this.props.endpoint
}
defaultProps = {
onSuccess: undefined,
onFailure: undefined,
onStartUpload: undefined,
alertTitle: 'Please Allow Access',
alertMessage: [
'This applicaton needs access to your photo library to upload images.',
'\n\n',
'Please go to Settings of your device and grant permissions to Photos.',
].join(''),
alertNo: 'Not Now',
alertYes: 'Settings',
};
}
render(){
return(
<View style={style.imgwrapper}>
{this.props.callbackUrl != null ? <Image source={{uri: this.state.uploaded_photo ? this.state.uploaded_photo : this.props.callbackUrl}} style={{width: 80, height: 80,borderRadius: 40}}/> : <Image source={{uri:'https://www.royaleboost.com/template/default-profile-img.png'}} style={{width: 80, height: 80}}/> }
<TouchableOpacity
style={style.circleWrapper}
onPress={()=>{
this.uploadResult();
}}
>
<View />
</TouchableOpacity>
</View>
)
}
}
const style = StyleSheet.create({
imgwrapper:{
justifyContent: 'center',
alignItems: 'center',
position:'relative',
marginBottom: 80,
},
circleWrapper:{
backgroundColor:'#ECECEC',
height:22,
width:22,
borderWidth:3,
borderColor: '#ffffff',
borderRadius:11,
marginLeft:70,
marginTop: -80,
},
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
})