I am getting uri from react-native-image-picker and I am storing the image data in an array then sending the images Array in in network call.
When I'm taking all images and save uri in state without cancelling the react-native-image-picker CameraActivity and sending all images through network call, that works perfectly.
But when I take one or more image and save uri in state, later if I open camera and go back from the react-native-image-picker cameraActivity without taking any picture, it gives me this error during network call:
Could not retrieve file for contentUri file:///storage/emulated/0/Pictures/images/image-e4da20e6-25a3-4e0f-a84c-d42ad9be7226.jpg
java.io.FileNotFoundException: /storage/emulated/0/Pictures/images/image-e4da20e6-25a3-4e0f-a84c-d42ad9be7226.jpg: open failed: ENOENT (No such file or directory)
at libcore.io.IoBridge.open(IoBridge.java:496)
at java.io.FileInputStream.<init>(FileInputStream.java:159)
This behaviour is really confusing to me.
I am using this function to take image and store it in state:
RNCamera()
.then(({ uri }) => {
setImages((prev) => [...prev, { uri: uri }]);
})
And I am sending request with the image object as FormData:
export const uploadFile = async (file: any, authToken?: any) => {
try{
const formData = new FormData();
formData.append('file', file);
let token = authToken;
if(!authToken) token = await AsyncStorage.getItem('userToken');
const res = await customFetch(FILE_UPLOAD_URL, {
method: "POST",
body: formData,
headers: {
'authorization': token ? `Bearer ${token}` : '',
}
});
if(!res.ok) throw new Error(res.statusText || `Error: Status is ${res.status}`)
return await res.json();
}catch(error: any){
throw new Error(error.message || "Error uploading file")
}
};
I am sending the file to uploadFile like this:
const fileIds = await Promise.all(images?.map(async img => {
const randomName = dateString + '_photo_' + Math.random() + ".jpg";
const file = {
uri: img.uri,
name: randomName,
type: 'image/jpg'
};
const res = await uploadFile(file, storeState?.userToken);
return res?.id
}))
Related
I am using MediaCapture library but getting 403. Below is my code:
MediaCapture.captureImage(options).then(
async (data: any) => {
const contents: any = await Filesystem.readFile({
path: data[0].fullPath,
});
setPreviewImage(contents);
let blobData: any = {};
let formdata = new FormData();
formdata.append(
"file",
`data:${data[0].type};base64,${contents.data}`
);
const response = (await axios.post(
Endpoints.userCover,
formdata
)) as ServerResponse;
if (response.status) {
console.log(response);
console.log("-------------------- IMAGE Camera");
}
},
(err) => console.error(err, " error")
);
enter image description here
Getting 403 on MediaCapture library when using Camera but it's working when selecting image from the android Gallery.
I'm using Firestore v9 within Expo/React Native. I use XMLHttpRequest to convert a base64 image into a blob file. Then I send/upload that blob file to Firebase Storage. It works perfectly with iOS but not with Android. In Android it returns {istrusted: false}, like the network request is not sent or something went wrong during converting the base64 image into a blob file.
I tried to use react-native-fetch-blob library as mentioned here but it's not supported by Expo.
This is my code:
const getBlob = async (photo) => {
return await new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.onload = function () {
resolve(xhr.response);
};
xhr.onerror = function (e) {
console.log("consoleloge",e);
reject(new TypeError("Network request failed"));
};
xhr.responseType = "blob";
xhr.open("GET", photo, true);
xhr.send(null);
});
}
const upload64BaseImage = async (photo, newDocRef) => {
try {
const blob = await getBlob(photo)
const imageRef = ref(storage, `images/${newDocRef}.jpg`);
const metadata = {
contentType: "image/jpeg",
};
const snapshot = await uploadBytes(imageRef, blob, metadata);
const downloadUrl = await getDownloadURL(snapshot.ref);
return downloadUrl;
} catch (error) {
console.log(`error`, error.message);
}
};
I'm trying to send/upload image file to my back-end serve using fetch multipart upload in react-native, but fetch multipart form data upload is not working for android, however I tried different examples.
Image upload multipart form data API is based on php and its working for iOS react-native app.
I am using react-native-photo-upload library for taking image.
storePicture(PicturePath:string) {
console.warn(PicturePath);
if (PicturePath) {
const apiUrl = `${Constants.APIHOST}updateprofileimage.php`;
// Create the form data object
var data = new FormData();
data.append('profileimage', { uri:PicturePath, name: 'profileimage.jpg', type: 'image/jpg/jpeg' });
data.append('accesstoken', this.state.user.sAccessToken);
data.append('react-native', 1);
// Create the config object for the POST // You typically have an OAuth2 token that you use for authentication
const config = { method: 'POST', headers: { Accept: 'application/json', 'Content-Type': 'multipart/form-data;' }, body: data };
fetch(apiUrl, config)
.then(responseData => { // Log the response form the server
// Here we get what we sent to Postman back
console.warn(`response:${responseData}`);
})
.catch(err => {
console.warn(err);
});
}}
Here is the example how I am calling storePicture() function.
<PhotoUpload onResizedImageUri={
avatar => {
if (avatar) {
this.storePicture(avatar.path);
}
}}
>
<Image source={{uri: this.state.user.sProfileImageUrl}} style={{resizeMode:"cover", marginTop:8.0, backgroundColor:'transparent', height:120.0, width:120, borderRadius:60.0, borderWidth:0.0, borderColor:'transparent'}}/>
</PhotoUpload>
uploadProfileImage = async (image:var) => {
this.setState({
loading: true
});
var RNFS = require('react-native-fs');
const path = Style.IS_IOS ? image.uri : image.path;
var fileName = path.split('/').pop();
var fileType = fileName.split('.').pop();
var filePath = Style.IS_IOS ? path : 'file://' + path;
const apiURL = `${Constants.APIHOST}updateprofileimage.php`;
const formData = new FormData();
formData.append('accesstoken', this.state.user.sAccessToken);
formData.append('reactnative', 1);
formData.append('profileimage', {
uri:filePath,
name: fileName,
type: `image/${fileType}`,
});
try {
const response = await fetch(apiURL, {
body: formData,
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data',
'Accept': 'application/json',
},
})
const json = await response.json()
this.handleUploadImageResponse(json);
} catch (err) {
this.setState({
loading: false
},console.log('catch Error: '+ err));
}
}
I am answering my own question as I haven't found any valid answer for the sake of other users, who are facing same issue.
Please let me know if I can improve my answer/post or in case any help is needed from me.
Image Upload to an API by Multipart FormData
uploadPicture = () => {
console.log(
"Image Upload urI = " + JSON.stringify(this.state.imageSourceUri.uri)
);
this.setState({ loading: true });
const form = new FormData();
form.append("fileToUpload", {
uri: this.state.imageSourceUri.uri,
type: "image/jpg",
name: "12334"
});
fetch("http://119.82.97.221/HPBSProjectApi2/api/HPBS/PostFormData", {
method: "post",
body: form
})
.then(response => response.json())
.then(response => {
console.log("response = " + response);
this.setState({
loading: false
});
});
};
the problem is the type field in the FormData, use mime to resolve it. Images must be image/jpeg.
const formData = new FormData();
formData.append("image",{..., name, uri, type: mime.getType(uri)}));
I have a react-native app on Android and a backend server written in NodeJS + Express and I'm using multer to handle file uploads.
const multer = require('multer');
const mime = require('mime');
const crypto = require('crypto');
const storage = multer.diskStorage({
destination: (req, file, cb) => cb(null, config.uploads),
filename: (req, file, cb) => {
crypto.pseudoRandomBytes(16, (err, raw) => {
cb(null, raw.toString('hex') + Date.now() + '.' + mime.extension(file.mimetype));
});
}
});
const upload = multer({ storage });
const Router = require('express').Router;
const controller = require('./upload.controller');
const router = new Router();
const auth = require('./../../auth/auth.service');
router.post('/', [auth.isAuthenticated(), upload.any()], controller.create);
module.exports = router;
And on my react-native app I try to do like this:
ImagePicker.launchCamera(options, image => {
let { uri } = image
const API_URL = 'http://192.168.1.2:9000/api/uploads'
var form = new FormData();
form.append("FormData", true)
form.append("access_token", "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjU3YjgyZGQ2MTEwZDcwYmEwYjUxZjM5YyIsImlzTWVkaWMiOnRydWUsImlhdCI6MTQ3MTY4ODE1MiwiZXhwIjoxNDcxNzA2MTUyfQ.gPeql5g66Am4Txl1WqnbvOWJaD8srTK_6vihOJ6kFbY")
form.append("Content-Type", "image/jpg")
form.append('image', uri)
fetch(API_URL, {body: form, mode: "FormData", method: "post", headers: {"Content-Type": "multipart/form-data"}})
.then((response) => console.log(response))
.catch((error) => {
console.log("ERROR " + error)
})
.then((responseData) => {
console.log("Succes "+ responseData)
})
.done();
})
But when I try to upload I recive the following error
multipart body must have at least one part
I am doing something wrong?
Does anybody knows a better solution to do this?
Fetch may not support Blob and FormData at this moment, but you can use XMLHttpRequest polyfill instead.
let xhr = new XMLHttpRequest()
xhr.open('post', `http://myserver.com/upload-form`)
xhr.send(form)
xhr.onerror = function(e) {
console.log('err', e)
}
xhr.onreadystatechange = function() {
if(this.readyState === this.DONE) {
console.log(this.response)
}
}
I tried to insert an image to db and get back as json data for mobile developing. I can successfully insert the path and retrieve the path as json but when i my friend tried to access the url it shows no such file or found.
This is the code
var express=require("express");
var app=express();
var fs = require("fs");
var sql=require('mysql');
var http = require("http");
var server = http.createServer();
var bodyParser = require('body-parser');
// app.use(bodyParser());
var multer = require('multer');
// var upload=multer({dest:'tmp/'});
// app.use(express.static('public'));
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'C:/Users/Ramachandran/Desktop/File/tmp/upload')
},
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now())
}
})
var upload = multer({ storage: storage })
app.use(bodyParser.urlencoded({extended: true}));
var con=sql.createConnection({
host:"localhost",
user:"root",
password:'',
database:'test'
});
app.get('/',function (req,res){
con.connect(function(err){
if(err){
console.log(err);
return;
}
console.log("connection established");
res.send("connection established");
});
})
app.get('/index',function(req,res){
res.sendFile('index.html',{'root': __dirname });
})
app.post('/insert', upload.single("myfile"), function (req,res){
var tes = __dirname + "/" + req.file.originalname;
fs.writeFile(tes, data, function (err) {
if (err) {
console.log(err);
} else {
var response = {
message: 'File uploaded successfully',
filename: req.file.originalname
};
}
console.log(response);
});
var data = {
uid:req.body.RollNo,
pat:req.file.path
};
con.query("insert into src set ?",data, function (err,rows){
if(err) throw err;
res.send("Value has bee inserted");
})
})
app.get('/test',function(req,res){
con.query('select * from src',function (err,rows){
if(err) throw err;
console.log("data receive from db");
console.log(rows);
res.send(rows);
})
})
app.listen(8888);
This my Json data
[{"uid":78965,"pat":"C:\\Users\\Vasanth\\Desktop\\File\\tmp\\upload\\myfile-1467012273947"},{"uid":987,"pat":"C:\\Users\\Vasanth\\Desktop\\File\\tmp\\upload\\myfile-1467012387236"}]
This will not work as you are returning a local path. The file is present on your machine, but when your friend tries to download it, he is trying to find it in C:\\Users\\Vasanth\\Desktop\\File\\tmp\\upload\\myfile-1467012273947 on his machine. You need to save the file on a folder, that is exposed by the server and provide the file from there, i.e. - http://localhost:8888/files/myfile-1467012273947 The easiest way to achieve this is using the express.static middleware: http://expressjs.com/en/starter/static-files.html