How to upload image using ReactJS and save into local storage? - javascript

Here is my code is like:
<input
type="file"
id="imageFile"
name='imageFile'
onChange={this.imageUpload} />
Now I want to store this image in local storage and display it at another side. So I want to store the image in local storage. My code is inside of image upload function.
My function is like:
imageUpload(e) {
console.log(e.target.value);
}
My console print is like C:\fakepath\user-bg.jpg

First, you should be aware that:
LocalStorage can only store strings, so you can store files using a string representation only (like base64)
LocalStorage is not really made for storing files, because browsers only offer you limited capacity
If this is really what you want to achieve, here's the solution:
class Hello extends React.Component {
imageUpload = (e) => {
const file = e.target.files[0];
getBase64(file).then(base64 => {
localStorage["fileBase64"] = base64;
console.debug("file stored",base64);
});
};
render() {
return <input
type="file"
id="imageFile"
name='imageFile'
onChange={this.imageUpload} />;
}
}
const getBase64 = (file) => {
return new Promise((resolve,reject) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result);
reader.onerror = error => reject(error);
reader.readAsDataURL(file);
});
}
JsFiddle

One implementation to upload files, using Java in the backend and Google App Engine that uses blob Blobstore. First try to call a function in your button that sends the file name:
<input id="btn-chooseImage" className="btn-file"
onChange={() => this.handleUploadSession()}
After that, call a get function in backend to save the file uploaded and save as a img state to render it.
Js:
handleUploadImg(redirectAction){
var file = $('#btn-chooseImage')[0].files[0]
var formData = new FormData();
formData.append("uploaded_files", file);
var request = new XMLHttpRequest();
request.open("POST", redirectAction, true);
request.send(formData);
request.onload = function() {
if (request.status === 200) {
var response = JSON.parse(request.responseText);
this.setState({
img: '/serve?blob-key=' +response.blobKey.toString()
});
}
}.bind(this);
};
handleUploadSession(){
var request = new XMLHttpRequest();
request.open("GET", "/uploadSession");
request.send();
request.onload = function () {
if(request.status === 200){
var redirectAction = JSON.parse(request.responseText);
this.handleUploadImg(redirectAction);
}
}.bind(this);
}
Java:
#RequestMapping(value = {"/uploadSession"}, method = RequestMethod.GET)
protected void GetUploadSession(HttpServletRequest request,
HttpServletResponse response) throws IOException {
BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();
String redirectAction = blobstoreService.createUploadUrl("/myView");
String json = new Gson().toJson(redirectAction);
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
response.getWriter().write(json);
}

Related

Convert Image URL to base 64 String

I have image URL like this - https://graph.facebook.com/3938027626271800/picture?type=normal.
I want to create a helper function in which I will pass the image URL as a parameter and it will return base 64 string. Right now I am following this approach but this approach converts the URL to base64 but it is not returning the base 64.
function toDataUrl(url, callback) {
var xhr = new XMLHttpRequest();
xhr.onload = function() {
var reader = new FileReader();
reader.onloadend = function() {
callback(reader.result);
}
reader.readAsDataURL(xhr.response);
};
xhr.open('GET', url);
xhr.responseType = 'blob';
xhr.send();
}
toDataUrl('https://graph.facebook.com/3938027626271800/picture?type=normal', function(myBase64) {
console.log(myBase64); // myBase64 is the base64 string
});
What do you mean return base64 not base 64?
What's the expected output?
It seems your code works well, i wrote in another approach got same results as you did.
async function getBase64ImageFromUrl(imageUrl) {
var res = await fetch(imageUrl);
var blob = await res.blob();
return new Promise((resolve, reject) => {
var reader = new FileReader();
reader.addEventListener("load", function () {
resolve(reader.result);
}, false);
reader.onerror = () => {
return reject(this);
};
reader.readAsDataURL(blob);
})
}
getBase64ImageFromUrl('https://graph.facebook.com/3938027626271800/picture?type=normal')
.then(result => console.log(result))
.catch(err => console.error(err));
As images may contain sensitive data, it's not possible to read images loaded from a different domain unless they allow it with CORS by specifying header
Allow-Content-Allow-Origin: *
Your example works just fine because the facebook image provides this header but it will not work for all images from external domains.
Your second thought may be to try to draw an image into canvas and then get data back but luckily for user's safety this is also prohibited:
https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image
The only way is to create a proxy on your domain to download the image from external source, it can already convert it to base64 for you on the backend as well. This is secure because the image is no longer downloaded in the browser user context, will not use his private cookies and IP address and so will not contain any sensitive data.
In HTML file:
<input type="file" (change)="selectedImage($event)" accept="image/*" name="Image">
In TS file:
public async selectedImage(event) {
const reader = new FileReader();
if (event.target.files && event.target.files.length) {
const [file] = event.target.files;
reader.readAsDataURL(file);
reader.onload = async () => {
reader.result // This is Image base64
};
}
}

How to pass Base64 encoded image to WCF REST endpoint

I am attempting to select an image on my computer and pass the data to a REST endpoint using the file element.
<input type="file" id="input">
I am able to render the image and display it in the browser. However, I get an empty string or object when passing the image to the endpoint as shown in the code below.
(function () {
const inputElement = document.getElementById("input");
inputElement.addEventListener("change", handleFiles, false);
function handleFiles() {
const reader = new FileReader();
reader.onload = (function() {
return function(e) {
sendFile(e.target.result);
};
})();
reader.readAsDataURL(this.files[0]);
}
function sendFile(file) {
let img = {
'Photo': new Blob([file], {type : 'image/png'})
};
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
alert(xhr.responseText);
}
};
xhr.open('POST', 'http://localhost/example/service.svc/AddPhoto/', true);
xhr.setRequestHeader('Content-Type', 'application/json; charset=utf-8');
xhr.send(JSON.stringify(img));
}})();
Service looks like this:
[OperationContract]
[WebInvoke(UriTemplate = "/AddPhoto/", Method = "POST",
RequestFormat = WebMessageFormat.Json, ResponseFormat =
WebMessageFormat.Json)]
void AddPhoto(BlogEntityModel blogEntityModel);
If you want to send the file as JSON, you have to take into account two things:
The value of e.target.result is a data URI.
You cannot convert Blob to JSON using the stringify method.
So, to fix it, you just should replace 'Photo': new Blob([file], {type : 'image/png'}) with 'Photo': file.
Keep in mind that in your case, the variable file is a data URI. If you want to submit only the Base64 value you have to remove the data:image/xxx;base64, prefix.

XHR Multipart File Upload Spring Boot Issue

I have an upload progress bar that works upon file input and when the bar reaches 100%, there is no error. But as I print the contents of the file in Spring Boot, I notice that the code within the for loop does not run. Here is the code. Please help and thank you!
JavaScript:
function upload(file) {
var formData = new FormData();
formData.append("newFile", file);
var xhr = new XMLHttpRequest();
xhr.open('POST', '/upload');
xhr.onload = function(e) {
console.log("xhr onload function");
};
var progressBar = document.querySelector('progress');
xhr.upload.onprogress = function(e) {
if (e.lengthComputable) {
progressBar.value = (e.loaded / e.total) * 100;
progressBar.textContext = progressBar.value;
}
};
xhr.send(formData);
}
Spring Boot:
#RequestMapping(value="/upload", method=RequestMethod.POST)
public String upload(#RequestParam("files") MultipartFile[] files) {
// This prints [Lorg.springframework.web.multipart.MultipartFile;#........].
System.out.println(files);
for (MultipartFile file : files) {
// This doesn't get printed.
System.out.println(file.getOriginalFilename());
}
return "redirect:/";
}
In JavaScript you are adding file to ‘newFile’ variable but on spring side you are extracting file from request param ‘files’.
Are you uploading multiple files? It doesn’t seems so. Try only with Multipart.
Because MultipartFile[] files were just initialized but does not contain any array of values.
Change the
public String upload(#RequestParam("files") MultipartFile[] files)
to
public String upload(#RequestPart(value = "files", required = true) MultipartFile[] files)

ReactJS Resize Base64

It works if you use the url https://i.imgur.com/6gMn1RD.png. However, when passing the string via axios, i have a network problem with the string being to large. To manage this... I want to resize the image to 100px/100px. I have been at this for 2 days and cannot find a solution anywhere.
So the steps should be as follows:
Get base64 string from url (see snippet below).
In the snippet below, before calling this.setState, convert the base64 to a smaller size of 100px/100px
Finally, we can call set state with the resized base64 string.
I have the following code snippet
convertAndSetAvatarUrlToBase64 = () => {
const url = this.state.avatarUrl;
const setAvatar = (base64) => {
// Resize base64 here
this.setState({ avatar: base64, fileAvatarImage: '' });
}
let getDataUri = function (url, callback) {
let xhr = new XMLHttpRequest();
xhr.onload = function () {
let reader = new FileReader();
reader.onloadend = function () {
callback(reader.result);
};
reader.readAsDataURL(xhr.response);
};
let proxyUrl = 'https://cors-anywhere.herokuapp.com/';
xhr.open('GET', proxyUrl + url);
xhr.responseType = 'blob';
xhr.send();
};
getDataUri(url, function (base64) {
setAvatar(base64);
})
}
Note: I've tried using the library resize-base64, but all I get is a DrawImage error relating to the canvas (something my friend said doesn't work well with react).

Convert URL to File or Blob for FileReader.readAsDataURL

Reference: FileReader.readAsDataURL
Considering the following example:
function previewFile(file) {
var reader = new FileReader();
reader.onloadend = function () {
console.log(reader.result);
}
reader.readAsDataURL(file);
}
It states:
instanceOfFileReader.readAsDataURL(blob);
blob: The Blob or File from which to read.
How can a local file URL like: 'file:///C:/path-to/root.png' be
passed to the readAsDataURL()
Is FileReader() available in a Firefox Addon?
To convert a URL to a Blob for FileReader.readAsDataURL() do this:
var request = new XMLHttpRequest();
request.open('GET', MY_URL, true);
request.responseType = 'blob';
request.onload = function() {
var reader = new FileReader();
reader.readAsDataURL(request.response);
reader.onload = function(e){
console.log('DataURL:', e.target.result);
};
};
request.send();
Expanding on Felix Turner s response, here is how I would use this approach with the fetch API.
async function createFile(){
let response = await fetch('http://127.0.0.1:8080/test.jpg');
let data = await response.blob();
let metadata = {
type: 'image/jpeg'
};
let file = new File([data], "test.jpg", metadata);
// ... do something with the file or return it
}
createFile();
The suggested edit queue is full for #tibor-udvari's excellent fetch answer, so I'll post my suggested edits as a new answer.
This function gets the content type from the header if returned, otherwise falls back on a settable default type.
async function getFileFromUrl(url, name, defaultType = 'image/jpeg'){
const response = await fetch(url);
const data = await response.blob();
return new File([data], name, {
type: data.type || defaultType,
});
}
// `await` can only be used in an async body, but showing it here for simplicity.
const file = await getFileFromUrl('https://example.com/image.jpg', 'example.jpg');
Try this I learned this from #nmaier when I was mucking around with converting to ico:
Well i dont really understand what array buffer is but it does what we need:
function previewFile(file) {
var reader = new FileReader();
reader.onloadend = function () {
console.log(reader.result); //this is an ArrayBuffer
}
reader.readAsArrayBuffer(file);
}
notice how i just changed your readAsDataURL to readAsArrayBuffer.
Here is the example #nmaier gave me:
https://stackoverflow.com/a/24253997/1828637
it has a fiddle
if you want to take this and make a file out of it i would think you would use file-output-stream in the onloadend
This information is outdated as of now, but cannot be deleted.
You can create File instances just by specifying a path when your code is chrome-privileged:
new File("/path/to/file");
File is a sub-class of Blob, so all File instances are also valid Blobs.
Please note that this requires a platform path, and not a file URL.
Yes, FileReader is available to addons.
File and FileReader are available in all windows. If you want to use them in a non-window scope (like bootstrap.js or a code module), you may use nsIDOMFile/nsIDOMFileReader.
Here is my code using async awaits and promises
const getBlobFromUrl = (myImageUrl) => {
return new Promise((resolve, reject) => {
let request = new XMLHttpRequest();
request.open('GET', myImageUrl, true);
request.responseType = 'blob';
request.onload = () => {
resolve(request.response);
};
request.onerror = reject;
request.send();
})
}
const getDataFromBlob = (myBlob) => {
return new Promise((resolve, reject) => {
let reader = new FileReader();
reader.onload = () => {
resolve(reader.result);
};
reader.onerror = reject;
reader.readAsDataURL(myBlob);
})
}
const convertUrlToImageData = async (myImageUrl) => {
try {
let myBlob = await getBlobFromUrl(myImageUrl);
console.log(myBlob)
let myImageData = await getDataFromBlob(myBlob);
console.log(myImageData)
return myImageData;
} catch (err) {
console.log(err);
return null;
}
}
export default convertUrlToImageData;
I know this is an expansion off of #tibor-udvari's answer, but for a nicer copy and paste.
async function createFile(url, type){
if (typeof window === 'undefined') return // make sure we are in the browser
const response = await fetch(url)
const data = await response.blob()
const metadata = {
type: type || 'video/quicktime'
}
return new File([data], url, metadata)
}
I ended up wanting something similar to this but without having to pass the type for the file or the filename, so I made my own example based on #Felix Turner's example. I used the content-disposition header for the filename first in case the file is coming back from an API endpoint, but use the last part of the URL path if that header doesn't exist.
function getFilenameFromContentDisposition(res) {
let filename = null;
const disposition = res.headers.get("content-disposition");
if (disposition?.includes("attachment")) {
const filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
const matches = filenameRegex.exec(disposition);
if (matches?.[1]) {
filename = matches[1].replace(/['"]/g, "");
// Sometimes the filename comes in a URI encoded format so decode it
filename = decodeURIComponent(filename);
// Sometimes the filename starts with UTF-8, remove that
filename = filename.replace(/^UTF-8/i, "").trim();
}
}
return filename;
}
async function getFileFromLink(url) {
const fileRes = await fetch(url);
const blob = await fileRes.blob();
let fileName = getFilenameFromContentDisposition(fileRes);
if (!fileName) {
fileName = url.split("/").pop();
}
const file = new File([blob], fileName, {
type: blob.type,
});
return file;
}
If you wanted to make this better, I'd use the content-disposition package on npm for the parsing as the formatting of it can get strange. I'd also probably use the mime package for ensuring that the filename from the URL has a proper file extension based on the returned content-type
Here's a simplest way to get blob or file object with vanila.js and promise
const fileURL_to_blob = (file_url) => {
return new Promise((resolve, reject) => {
let request = new XMLHttpRequest();
request.open('GET', file_url, true);
request.responseType = 'blob';
request.onload = function() {
var reader = new FileReader();
reader.readAsDataURL(request.response);
reader.onload = function(e){
//console.log('DataURL:', e.target.result);
resolve(e.target.result);
};
};
request.onerror=function(e){
reject(e);
}
request.send();
});
}

Categories

Resources