My users should be able to upload their logo in my react APP,
Ideally what I want to do is upload the file somewhere IE host it and in the process of doing so, retrieve the URL for it so I can store that URL in the database along with the other settings!
My code for the user to drop the image is quite simple:
this.state = {
files: []
};
<DropZone
onDrop={(files, acceptedFiles, rejectedFiles) => {
this.setState({files: [...this.state.files, ...acceptedFiles]});
}}>
{uploadedFiles}
{fileUpload}
</DropZone>
Then when saving settings i want to call a function which as I said, Uploads the image somewhere and returns that URL so i can then use it to store in a DB.
saveDetails = () => {
// some code here that takes the this.state.files[0]
uploads it somewhere then returns the URL.. THEN i call a DB storage function storing that URL to then be accessed elsewhere?!
}
Is there a common, easy way to do this?
Thanks if you can help!
You want to use axios to post the image data. Use FileReader to read file. Read it as a base 64 image and send it to the server. To read file as a base 64:-
handleDrop(acceptedFiles){
const {onError,onChangeAvatar} = this.props;
const reader = new FileReader();
reader.onabort = ()=>onError("Profile picture reading is aborted!");
reader.onerror = ()=>onError("Error with uploaded file. Try again.");
reader.readAsDataURL(acceptedFiles[0]);
reader.onload = ()=>{
const base64Image = reader.result;
onChangeAvatar(base64Image);
};
}
Now you can use axios to post image:-
onChangeAvatar (base64Image){
Axios.post("/url/to?upload",base64Image).then(response=>console.log(response))
}
save the file and return saved url from server side.
Related
I am using react-easy-crop to allow users to modify their profile pictures after uploading. The problem I am experiencing is that after cropping, the image is returned in the form of a blob url like this: blob:http://localhost:3000/5e44190e-a087-4683-b3a4-dfce4a57ee62 which is unhelpful since it can only be viewed on my local machine.
I have tried converting it to a data url (which I understand can then be shared and viewed across browsers), using FileReader and the readAsDataURL() method like this:
let blob = await fetch(imageToCrop).then((r) => r.blob());
let reader = new FileReader();
reader.readAsDataURL(blob);
reader.onloadend = function () {
let base64data = reader.result;
console.log(base64data);
};
The base64data variable does return what I think I need, however all my attempts to then store this result in my state only return a null value.
Does anyone know what is the best way to handle this?
If you have this line in your code, delete it because it revoke your URL.
window.URL.revokeObjectURL(this.fileUrl);
If you need the base64 output of the cropped image, you can get it after using the canvas to crop it with canvas.toDataURL('image/jpeg'). This base64 string can then be shared to anyone or uploaded to a remote server.
This is basically the commented line in the getCroppedImg() function of this demo: https://codesandbox.io/s/q8q1mnr01w?file=/src/cropImage.js:2362-2562
BTW I guess you could also upload the blob to a remote server and store the image somewhere like AWS S3.
I have a PERN JS app and from the front (in react) a form has an input type file that sends the file (an image) to the server side. I then uploaded the image in a bucket in google cloud storage with public permission for everything to allUsers. It uploads fine, if I go to the public url provided by google storage i can see the image fine even on incognito window. The problem is when i send the path to a react component to display the image. It has a img html tag that goes to the alternative text property of img html tag and the component never displays the image i want. It uploads with a strange size of 20 B in Google Cloud Sotorage Bucket.
My code:
const router = require('express').Router();
const {Storage} = require('#google-cloud/storage');
const gc = new Storage({
projectId: GOOGLE_CLOUD_PROJECT_ID,
keyFilename: GOOGLE_CLOUD_KEYFILE,
})
getPublicUrl = (bucketName, fileName) => `https://storage.googleapis.com/best-buds/${bucketName}/${fileName}`
router.post('/', async (req, res, next) => {
try {
const file = req.files && req.files.image
const bucket = gc.bucket('best-buds');
const file_bucket = file && bucket.file(file.name)
const stream = file_bucket.createWriteStream({
resumable: false,
gzip: true
})
stream.on('finish', () => {
file.cloudStorageObject = file.name;
return file_bucket.makePublic()
.then(() => {
file.gcsUrl = getPublicUrl('best-buds',file.name);
next()
})
})
stream.end(file.buffer);
...
res.sendStatus(200);
} catch (error) {
next(error);
res.sendStatus(500);
}
});
module.exports = router;
I used devtools extension and checked my react component receives de props image with the correct url. If i go to that url using the browser i can see the image but still its not displaying in my component.
Could anyone help me?
The problem here is the upload, uploading files to google cloud storage, whether that be cloud storage or firebase storage, you will need to pass the file as blob and then you will need to assign proper extension to it with proper metadata, every filetype has its own metadata, for example: a pdf document will have document/pdf or an image will have image/png or image/jpeg. If the upload fails and you get some low byte size file then that means that the upload failed and it is due to metadata really.
var metadata = {
contentType: 'image/jpeg',
};
Firebase's doc explains how it works here
I am using a plugin called dropzone which leaves rendering the image pretty much how to the user.
so I have done this
<Dropzone
onDrop={this.handleDropChange}}>
<p>
Try dropping some files here, or click to select files to upload.
</p>
</Dropzone>
#observable files = [];
#action
handleDropChange = (files) => {
files.forEach(file => {
this.loadFile(file);
});
}
#action
loadFile(file){
const reader = new FileReader();
reader.addEventListener('load',() => {
runInAction(() => {
this.files.push({file: file, preview: reader.result, uploaded: false})
window.URL.revokeObjectURL(reader.result);
});
},false);
// reader.readAsDataURL(file.fileObject);
}
<img src={this.props.preview} />
Problem is though when I drag in say 500 images it takes awhile for them to render on the screen. I think reactjs is having a hard time as it is essentially re-rendering 500 times since each "file reader load" causes a new item to be put into the files array.
Is there away to batch this or first do all the loading then re-render?
revokeObjectURL is for object url's and not meant for other strings|urls|base64.
You can create a objectURL by calling URL.createObjectURL like so:
var url = URL.createObjectURL(file || blob)
var image = new Image()
image.src = url
document.body.appendChild(image)
There is no need to use FileReader and read all the content encode it as base64 then let the browser decode it back into binary. that is a waste of resource...
revoking the objecturl should be done when you no longer need the url
I have an image that is stored in local storage. On load the image is displayed.
componentDidMount() {
const reader = new FileReader();
reader.onload = e => {
this.setState({ blob: e.target.result });
};
reader.readAsDataURL(this.props.file);
}
render() {
return (
<div>
<img src={this.state.blob} />
</div>
)
}
The file object looks like this:
lastModified:1535424554987
name:"test.jpeg"
preview:"blob:http://localhost:8080/b52098ca-087f83c778f0"
size:41698
type:"image/jpeg"
webkitRelativePath:""
When I refresh the page and try to load the preview again, it doesn't display the image, and the file object looks different:
{preview: "blob:http://localhost:8080/b52098ca-087f83c778f0"}
Is it possible to read the image from this url? Or is it impossible to render the image without the full file object?
blob URL is temporary. if you reload the web page, the blob URL will gone.
If you want to save the image in localStorage you can save it as base64 data.
But if your image is too big localStorage won't suit because it has limits which depend on the browser from 5MB to 10MB.
It's impossible as far as i'm aware to save files to/from localStorage this is because it runs JSON.stringify over the data.
I'm using the management API to get all my installed apps and extensions. I want to send this information to server.
Every app/extension has an icon array, that has size and url.
The url is something like chrome://extension-icon/gmgpodcgeocidkeclglljo88jp9kclhhmmdacfo/32/0. I want to send it to my server in base64.
What I'm trying to do is something like:
var reader = new FileReader();
reader.onloadend = function() {
result = reader.result;
}
if (file) {
reader.readAsDataURL(file);
} else {
result = "";
}
Where file is a File object of the icon url. But I cannot find how to create an File object with this url format.
I've tried:
var fileUrlArray = ["chrome://extension-icon/gmgpodcgeocidkeclglljo88jp9kclhhmmdacfo/32/0"];
var file = new File(fileUrlArray, 'icon.png');
And as a result I got an absolutely wrong base64 string.
Any ideas about how to do it?
Thanks.