How to convert blob into base64 in nextJs - reactjs

I am getting the Image from an API response. I am trying to the get the image and display in the UI.
import FileReader from 'filereader';
export default async (req, res) => {
const { method } = req;
switch (method) {
case 'GET':
try {
const response = await fetch("imagepathurl", Constants.config);
const imageBlob = await response.blob()
console.log("imageBlob", imageBlob)
return new Promise((resolve, _) => {
const reader = new FileReader();
reader.onloadend = () => resolve(reader.result);
reader.readAsDataURL(imageBlob);
});
} catch (error) {
console.log("error", error);
}
break
default:
res.setHeader('Allow', ['GET', 'PUT', 'PATCH'])
res.status(405).end(`Method ${method} Not Allowed`)
}
}
I can able to capture imageBlob but from the fileReader() i am unable to capture and convert to base64.
In File Reader i am facing Error: cannot read as File: {}.
Please let me know the way i am doing is correct or can soneone guide me in fixing it.

Related

React FileReader readAsDataURL not working: URL can't be decoded in flask backend as format == None

I'm working on a basic React web app where user can upload images, and images are send to the flask backend to be processed. I'm using FileReader class to convert the uploaded images through into URLs, and then send them to the backend, where I need to decode the URLs then converted it into an np.array for the processing.
The issue is, when I try to decode the image with image_data = base64.b64decode(image_url) and get the image with Image.open(io.BytesIO(image_data)), somehow it won't recognize the url as an image? Basically I got this error:
raise UnidentifiedImageError(
PIL.UnidentifiedImageError: cannot identify image file <_io.BytesIO object at 0x2e8950b30>
I checked the image format with image_format = imghdr.what(io.BytesIO(image_data)), and the image_format equals to None. Do I need to specify the format when encoding the image?
Here's my code:
in React App():
handleImageUploadSelect = (event) => {
let imageURLs = [];
const files = event.target.files;
for ( let i = 0; i < files.length; i++ ) {
// load file object
const file = files[i]
// file reader
const reader = new FileReader();
reader.onload = (event) => {
const dataURL = event.target.result;
// add dataURL to the state variable
imageURLs[i] = dataURL;
}
reader.readAsDataURL(file);
}
this.state.uploadImageURLs = imageURLs;
}
handleImageUpload = event => {
event.preventDefault();
// send uploadImageURLs back to flask server
const data = { images: this.state.uploadImageURLs };
console.log(data)
fetch('http://127.0.0.1:5000/add_images', {
method:'POST',
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json'
},
})
.then((response) => response.json())
.then((data) => {
// response data
console.log(data)
})
.catch((error) => {
console.error(error);
});
}
And in flask server file:
#main.route('/add_images', methods=['POST'])
#cross_origin()
def add_images():
data = request.get_json()
for imageURL in data['images']:
image_data = base64.b64decode(imageURL)
image = Image.open(io.BytesIO(image_data))
image_array = np.array(image)
# processing ...
return jsonify({"condition": "image received"})
Please Help! Thanks!

501 Not Implemented error in small web app

I am trying to upload images to an S3 bucket with react and expressjs. When I attempt to upload the image I get a 501 Not Implemented Error. I am using axios to contact the end point I created in the server code.
My react code:
class FileUpload extends Component {
state = {
file: null
};
submitFile = (event) => {
event.preventDefault();
const formData = new FormData();
formData.append('file', this.state.file[0]);
axios.post(`test-upload`, formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
}).then(response => {
// handle your response;
}).catch(error => {
// handle your error
});
}
handleFileUpload = (event) => {
this.setState({file: event.target.files});
}
render () {
return (
<form onSubmit={this.submitFile}>
<input label='upload file' type='file' onChange=
{this.handleFileUpload} />
<button type='submit'>Send</button>
</form>
);
}
}
export default FileUpload;
My server code:
const uploadFile = (buffer, name, type) => {
const params = {
ACL: 'public-read',
Body: buffer,
Bucket: process.env.S3_BUCKET,
ContentType: type.mime,
Key: `${name}.${type.ext}`
};
return s3.upload(params).promise();
};
app.use('/', (req,res) =>{
res.send(JSON.stringify({ greeting: `Hello!` }));
});
// Define POST route
app.post('/test-upload', (request, response) => {
const form = new multiparty.Form();
form.parse(request, async (error, fields, files) => {
if (error) throw new Error(error);
try {
const path = files.file[0].path;
const buffer = fs.readFileSync(path);
const type = fileType(buffer);
const timestamp = Date.now().toString();
const fileName = `bucketFolder/${timestamp}-lg`;
const data = await uploadFile(buffer, fileName, type);
return response.status(200).send(data);
} catch (error) {
return response.status(400).send(error);
}
});
});
This was done by following a guide on the internet but there seems to be something missing that I just can't figure out.
Figured it out in the end,
axios.post(/test-upload,
should have been
axios.post(http://localhost:3000/test-upload,

how to upload file like pdf or doc in firestore

I want to upload document files in firestore using redux. i get the file in and passed it as a state to the action file with other datas. following is my code in action file.
const createJob = (project) => {
return (dispatch, getState, {getFirebase, getFirestore}) => {
const firestore = getFirestore();
firestore.collection('Jobs').add({
...project,
postedby:'Employer1',
Documents:project.Documents.name
}).then(()=>{
dispatch({type:'CREATE_JOB', project});
}).catch((err)=>{
dispatch({type:'CREATE_JOB_ERROR', err});
})
}
};
but the data is saved as C:\fakepath\doc1.doc
how to upload the actual file in firestore
Technically you can upload an image to firestore. You need to convert it to base64 text first. Just spent some time figuring it out. I take the selected file from an upload file from browser then I upload it in the callback of the file reader. Hopefully this helps someone out.
function getBase64(file){
var n = document.getElementById('nameU').value;
//name of uploaded file from textbox
var d = document.getElementById('dateU').value;
//date of uploaded file from textbox
var reader = new FileReader();
reader.onerror = function (error) {
console.log('Error: ', error);
};
reader.readAsDataURL(file);
reader.onload = function () {
let encoded = reader.result.split(',');
//you split this to get mimetype out of your base64
addForSale(Date.now().toString(10), {uDesc: n, date: d, uFile: encoded[1]});
// I just used a timestamp as the ID
}
};
function addForSale(id, data) {
var collection = firebase.firestore().collection('forsale');
return collection.doc(id).set(data);}
Hi You cannot directly store the image in firestore.What you have to do is first store the document in firebase storage and get the url as reponse.Once the response is received add the url in documents.
First create an Storage Action in reduce:
import { storage } from '../../../firebase/firebase';
import {
ADD_DOCUMENT_STARTED,
ADD_DOCUMENT_COMPLETED,
ADD_DOCUMENT_ERROR
} from '../../actionTypes/storageActionTypes';
import { toast } from 'react-toastify';
import constants from '../../../config/constants';
export const addDocumentStart = () => ({
type: ADD_DOCUMENT_STARTED
});
export const addDocumentSuccess = () => ({
type: ADD_DOCUMENT_COMPLETED
});
export const addDocumentFailure = () => ({
type: ADD_DOCUMENT_ERROR
});
export const addDocument = (values, pathName) => {
const toastId = toast('Uploading Attachment, Please wait..', {
autoClose: false
});
return (dispatch) =>
new Promise(function(resolve, reject) {
dispatch(addDocumentStart());
const timeStamp = new Date().getTime();
const image = values.document[0];
var name;
if (values && values.documentName) {
name = timeStamp.toString().concat(values.documentName);
} else {
name = timeStamp.toString().concat(image.name);
}
const imageUpload = storage.ref(`${pathName}/${name}`).put(image);
imageUpload.on(
'state_changed',
(snapshot) => {
switch (snapshot.state) {
case 'paused':
reject('Upload is paused');
dispatch(addDocumentFailure('Upload is paused'));
break;
}
},
(error) => {
switch (error.code) {
case 'storage/unauthorized':
reject('Permission Denied');
dispatch(addDocumentFailure('Permission Denied'));
break;
case 'storage/canceled':
reject('Upload Cancelled');
dispatch(addDocumentFailure('Upload Cancelled'));
break;
case 'storage/unknown':
reject('Server Response Error');
dispatch(addDocumentFailure('Server Response Error'));
break;
}
},
() => {
toast.update(toastId, {
render: 'Attachment Uploaded successfully',
type: toast.TYPE.SUCCESS,
autoClose: constants.toastTimer
});
storage
.ref(pathName)
.child(name)
.getDownloadURL()
.then((url) => {
dispatch(addDocumentSuccess());
resolve(url);
});
}
);
});
};
Then in your onsubmit:
this.props.dispatch(addDocument(values, 'Jobs')).then((resp) => {
let documentUrl = resp;
firestore.collection('Jobs').add({
...project,
postedby:'Employer1',
Documents:documentUrl
}).then(()=>{
});

Image file getting corrupted on uploading to amazon s3 public bucket using reactjs

I am trying to upload an image using reactjs but the image is getting corrupted on upload to amazon s3.
The code is as follows.
uploadToS3 = (imageUri, fileName, fileType, file,success, failure) => {
let body = new FormData();
let url=imageServer+fileName;
body.append('key', fileName);
body.append('acl', 'public-read');
body.append('Content-Type', 'multipart/form-data');
body.append('Content-Disposition', 'inline');
body.append('file', {
name: 'file',
uri: imageUri,
type: file.type
});
return axios.post(imageServer,body,
{ headers: {
'Accept':file.type,
'Content-Type':file.type,
}}
).then(response => {
console.log('[AWS S3] Response ==> ', response)
this.props.addNewImage(url,this.props.arrayname);
return response;
}).catch(error => {
console.log('[AWS S3] Error ==> ', error)
return error;
})
}
Actually the mistake which I was making was sending the wrong value for 'file' object in formData object.The correct code is as follows-
uploadToS3 = (imageUri, fileName, fileType, file,success, failure) => {
let body = new FormData();
let url=imageServer+fileName;
body.append('acl', 'public-read');
body.append('Content-Type',file.type);
body.append('key', fileName);
body.append('file',file);
return axios.post(imageServer,body)
.then(response => {
console.log('[AWS S3] Response ==> ', response)
this.props.addNewImage(url,this.props.arrayname);
return response;
}).catch(error => {
console.log('[AWS S3] Error ==> ', error)
return error;
})
}
_handleImageChange(e){
let reader = new FileReader();
let file = e.target.files[0];
console.log(file,'file');
reader.onloadend = () => {
let uri=reader.result;
let fileType = /^data:image\/\w+;/.exec(reader.result)[0].replace(/^data:image/,"").replace("/","").replace(";","");
let fileName='img'+`${new Date().getTime()}`+'.'+fileType;
console.log("filename",fileName);
this.uploadToS3(uri,fileName,fileType,file);
}
reader.readAsDataURL(file);
}

Using redux-api-middleware to process image/jpeg content

I have an RSAA (Redux Standard API-calling Action) that I'm using to retrieve image/jpeg content. All the examples I've seen deal with JSON data so I copied the getJSON function and implemented my own getImage function to deal with this content type. The problem I'm now running into is that this blob needs to be converted to base64 and that has to be done using an async function. So, my FSA gets triggered before this async operation completes.
I suspect that I need to somehow piggyback on the existing promise chain in the RSAA payload processing but I'm not sure how to do this.
Here's the snippet of code with the line commented where I need to perform the promise resolve to return this result:
export function fetchSiteThumbnailImage(endpoint) {
return {
[CALL_API]: {
endpoint,
method: 'GET',
headers: {
'Accept': 'image/jpeg'
},
types: [
LOAD_SITE_THUMBNAIL_REQUEST,
{
type: LOAD_SITE_THUMBNAIL_SUCCESS,
payload: (action, state, res) => {
return getImage(res).then((blob) => {
const reader = new FileReader();
reader.readAsDataURL(blob);
reader.onloadend = () => {
const base64data = reader.result;
return base64data; // this needs to "resolve" - how??
}
});
},
meta: (action, state, res) => {
return {
siteId,
endpoint
}
}
},
LOAD_SITE_THUMBNAIL_FAILURE
]
}
}
}
Thanks!
You have to wrap your FileReader logic into a Promise:
function readAsBase64(blob) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => {
const base64data = reader.result;
resolve(base64data);
}
reader.onerror = (err) => {
reject(err);
}
reader.readAsDataURL(blob);
});
}
Your payload function can then just be
(action, state, res) => getImage(res).then(readAsBase64);
A couple of notes:
reader.onloadend gets called when the reading operation is completed (either in success or in failure), while reader.onload is called only on successful completion and reader.onerror only on failed completion — you want to separate the two cases.
You should set the event handlers before you start reading the blob to avoid race conditions — so put reader.readAsDataURL at the end.
I have managed to solve this so I'll answer my own question... I just needed to return a new Promise object like this:
return new Promise((resolve, reject) => {
getImage(res).then((blob) => {
const reader = new FileReader();
reader.readAsDataURL(blob);
reader.onloadend = () => {
const base64data = reader.result;
resolve(base64data);
}
reader.onerror = () => {
reject(Error('unable to process image/jpeg blob'));
}
})
});

Resources