我正在制作一个带有博览会的应用程序,希望让用户拍照或从相机卷中挑选一张应用并将其上传到我的服务器。我该怎么做?
使用EXPO ImagePicker
API显示相机或相机卷,并获取有关所选图像的信息:
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,
headers: {
'content-type': 'multipart/form-data',
},
});
}
有关包括服务器代码在内的更全面的示例,请参阅此回购:https://github.com/expo/image-upload-example。
官方示例使用node.js,以下是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',
},
});
}
upload.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,
}
});
对于博览会,除了使用Expo Filesystem uploadasync
之外,对我没有任何帮助uploadImage = async ({ imageUri } }) => FileSystem.uploadAsync(
apiUrl,
imageUri,
{
headers: {
// Auth etc
},
uploadType: FileSystem.FileSystemUploadType.MULTIPART,
fieldName: 'files',
mimeType: 'image/png',
});
注意 - imageuri以file的格式:///mypath/to/image.png
由于所选的解决方案实际上对我不起作用,这是我制作的文件上传的方式与expo和django rest框架一起使用。
const blobToBase64 = blob => {
const reader = new FileReader();
reader.readAsDataURL(blob);
return new Promise(resolve => {
reader.onloadend = () => {
resolve(reader.result);
};
});
};
const formData = new FormData();
const base64 = await blobToBase64(blob);
formData.append('file', base64);
formData.append('data', JSON.stringify(payload)); // additional data (I parse the string as json in the backend to get my payload back)
// same code as chosen answer, this was not part of the problem
return await fetch(YOUR_SERVER_URL, {
method: 'POST',
body: formData,
headers: {
'content-type': 'multipart/form-data',
},
});
在django中,我可以使用自定义解析器将base64字符串解码为字节,然后使用它创建一个SimpleUploadedFile
对象。
class MultipartJsonParser(parsers.MultiPartParser):
def parse(self, stream, media_type=None, parser_context=None):
result = super().parse(
stream,
media_type=media_type,
parser_context=parser_context
)
base64_file = result.data.get('file')
file_parts = base64_file.split(',')
mime_type = re.sub(r'^data:([w/]+);base64$', '\1', file_parts[0])
file = SimpleUploadedFile('file', base64.b64decode(file_parts[1]), mime_type)
data = json.loads(result.data["data"]) or {} # additional data sent by Expo app
qdict = QueryDict('', mutable=True)
qdict.update(data)
return parsers.DataAndFiles(qdict, {'file': file})
class MyUploadView(ModelViewSet):
parser_classes = (MultipartJsonParser, parsers.JSONParser)
def create(self, request, *args, **kwargs):
# request.data should have a 'file' property with a SimpleUploadedFile object
...
,因为谁找不到或解决了这个问题。我花了三天的时间找到解决方案,我明白了。就我而言,这是数据对象的命名元素。Android版本10,Expo 4.11.0,
这是Front
async function uploadImage(uploadFile){
const data = new FormData()
data.append('name',{
name: image_name, {/* name your image whatever you want*/}
type: 'image/jpeg', {/* type of image that you're uploading*/}
uri: uploadFile {/*data, file or image from ImagePicker here you should pass uri data but not all data from ImagePicker*/}
})
{/*names of data object should be like this: name, type, uri*/}
const response = await fetch(my_upload_api.php,{
method: 'POST',
body: data,
headers: {
'Content-Type': 'multipart/form-data'
}
})
}
这是PHP
上的后卫if(!empty($_FILES['name']['name'])){
$target_dir = 'my folder where I put all images';
if(!file_exists($target_dir)){
$data = array(
(object)array(
'code' => '400',
'message' => 'Can't fined folder.'
)
);
$json = json_encode($data);
echo $json;
die();
}
$target_file = $target_dir . basename($_FILES['name']['name']);
$image_file_type = pathinfo($target_file,PATHINFO_EXTENSION);
if(file_exists($target_file)){
$data = array(
(object)array(
'code' => '400',
'message' => 'Sorry. File already exists.'
)
);
$json = json_encode($data);
echo $json;
die();
}
if($_FILES['name']['size'] > 50000000){
$data = array(
(object)array(
'code' => '400',
'message' => 'Sorry. Your file is too large.'
)
);
$json = json_encode($data);
echo $json;
die();
}
if(move_uploaded_file($_FILES['name']['tmp_name'], $target_file)){
$data = array(
(object)array(
'code' => '200',
'message' => 'Successfuly your file has been uploaded.',
'name' => $_FILES['name']
)
);
$json = json_encode($data);
echo $json;
die();
}else{
$data = array(
(object)array(
'code' => '400',
'message' => 'Sorry. There was something wrong. Try it again.'
)
);
$json = json_encode($data);
echo $json;
die();
}
}
这是我尝试找到解决方案的第一个博客。如果解决方案在这里,我也许会花费一段时间或更短的时间来解决这个问题。我希望我可以帮助某人。