A form I use to upload a book cover to Cloudinary has an input type='file' on it. However I'd like to allow no image upload too that is when the form submits there is no file provided to input type='file'. Cloudinary responds with Request failed with status code 400.
This is how I try to mock a file to upload it to Cloudinary inside an action.
export const addBook = (bookData, history) => (dispatch) => {
const cloudinaryUrl = 'https://api.cloudinary.com/v1_1/*****/upload';
const cloudinaryUploadPreset = '*****';
const formData = new FormData();
bookData.cover[0] && formData.append('file', bookData.cover[0]);
if (!bookData.cover[0]) {
const blob = new Blob([''], { type: 'image/png' });
blob['lastModifiedDate'] = '';
blob['name'] = 'mockImageFile';
blob['webkitRelativePath'] = '';
blob['size'] = 7654;
formData.append('file', blob);
/* const f = new File([''], 'filename', { type: 'image/jpeg' });
formData.append('file', f); */
}
formData.append('upload_preset', cloudinaryUploadPreset);
axios({
url: cloudinaryUrl,
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
data: formData
})
... ...
Still Cloudinary responds with Request failed with status code 400. How do I convince it to take a programmatically created 'file'?
The goal is to handle an upload with no file.
You need to convert blob data to a data URI which will be accepted by the file parameter to Cloudinary's upload method.
Please try below codebase to convert blob data to data URI. which you can append it to formdata.
const blob = new Blob([""],{ type: "image/png" });
blob["lastModifiedDate"] = "";
blob["name"] = "mockImageFile";
blob["webkitRelativePath"] = "";
blob["size"]=7654;
var reader = new FileReader();
var blob_base64data;
reader.readAsDataURL(blob);
reader.onloadend = function() { blob_base64data = reader.result;
};
formData.append("file", blob_base64data);
You can either perform a check for an empty file before uploading to Cloudinary and not upload to Cloudinary if there is no file or you can use a default image everytime there is no file uploaded instead of creating a blob.
Related
I used the following js code to load a file with a Chinese filename into FormData and then upload it and found the filename garbled on the server side.
export async function uploadFile(file, url) {
let formData = new FormData()
formData.append('file', file.file)
file.status = 'loading'
let response = await fetch(url, { method: 'POST', body: formData})
file.status = response.ok
return response
}
How can I solve the filename garbling problem because the filenames in formdata seem to be ASCII encoded?
This question is used to share my solution. The code is below. I encoded the file name with encodeURIComponent and created a new File Object from it.
export async function uploadFile(file, url) {
let formData = new FormData()
const file_ = new File([file.file], encodeURIComponent(file.filename), {type: file.file.type});
formData.append('file', file_)
file.status = 'loading'
let response = await fetch(url, { method: 'POST', body: formData})
file.status = response.ok
return response
}
Afterwards I decode the filename with decodeURIComponent on the server side.
This is an issue that occurred while trying to implement a profile image change using React.
Function that receives image values cropped from canvas, converts to blob, and requests it to be saved to the server
//Function that receives image values cropped from canvas, converts to blob, and requests it to be saved to the server
const onClickUploadImage = (canvas, crop) => {
if (!crop || !canvas) {
return;
}
const canvasUrl = canvas.toDataURL("image/png");
const base64Incoding = atob(canvasUrl.split(",")[1]);
const array = [];
for (let i = 0; i < base64Incoding.length; i++) {
array.push(base64Incoding.charCodeAt(i));
}
const file = new Blob([new Uint8Array(array)], { type: "image/png" });
const fd = new FormData();
fd.append("file", file);
//Verify that the blob is created as an url image
console.log("convert file >> ", window.URL.createObjectURL(file));
//conver file >> blob:http://localhost:3000/afdc0910-76bb-4e53-801c-61dc890c651f
const config = {
header: {
processData: false,
"content-type": false,
},
};
axios
.post("/api/users/update/image", fd, config)
.then(({ data }) => {
console.log("data >> ", data);
//data >> { success:true, message:"File saved successfully" }
alert("Profile upload successful.");
})
.catch((err) => {
alert("Profile upload failed.");
});
};
// On the server side, we use the filter module to store very well.
// Type is saved as file.
// The problem is that I want to read this file and display it as an image.
// To do that, I checked to see if the stored blob reads well.
// I tried to read the saved blob file using input and convert it as below code, but failed.
// input ex) <input type="file" onChange={onClickBlobToURL} />
function onClickBlobToURL(e) {
const file = e.target.files[0];
console.log("file > ", file);
//File Attach Output Result Image
const reader = new FileReader();
if (file) {
console.log("blobToURL > ", reader.readAsDataURL(file));
//blobToURL > undifined
}
}
Did you save it the wrong way?
Is it wrong to read blob?
console.log("file > ", file)
There are similar questions like this, this, this, and this, but none help.
In Node, the goal is to use the axios module to download an image from Twitter then upload this image as an image file as part of a form submission.
This code downloads the Twitter image, but the uploaded binary image is corrupted when it reaches the server (also our server).
The image must be uploaded in binary.
A form is required because other fields are also submitted with the binary image. These other form fields were removed to simplify the code sample.
const axios = require('axios');
const FormData = require('form-data');
let response = await axios.get('https://pbs.twimg.com/media/EyGoZkzVoAEpgp9.png', {
responseType: 'arraybuffer'
});
let imageBuffer = Buffer.from(response.data, 'binary');
let formData = new FormData();
formData.append('image', imageBuffer);
try {
let response = await axios({
method: 'post',
url: serverUrl,
data: formData,
});
// Do stuff with response.data
} catch (error) {
console.log(error)
}
You should pass the headers to the axios call using formData.getHeaders() to send a Content-Type header of multipart/form-data. Without it, a Content-Type header of application/x-www-form-urlencoded is sent. You could pass a responseType of stream to the axios call that downloads the image and add the stream to the form data.
You can also use axios.post to simplify the method call.
const url = 'https://pbs.twimg.com/media/EyGoZkzVoAEpgp9.png'
const { data: stream } = await axios.get(url, {
responseType: 'stream',
})
const formData = new FormData()
formData.append('image', stream)
try {
const { data } = await axios.post('http://httpbin.org/post', formData, {
headers: formData.getHeaders(),
})
console.log(data)
} catch (error) {
// handle error
}
You can use the fetch API to fetch the image as a blob object and append it to form data. Then simply upload it to its destination using Axios, ajax, or the fetch API:
const mediaUrl = "https://pbs.twimg.com/media/EyGoZkzVoAEpgp9.png"
fetch(mediaUrl)
.then((response) => response.blob())
.then((blob) => {
// you can also check the mime type before uploading to your server
if (!['image/jpeg', 'image/gif', 'image/png'].includes(blob?.type)) {
throw new Error('Invalid image');
}
// append to form data
const formData = new FormData();
formData.append('image', blob);
// upload file to server
uploadFile(formData);
})
.catch((error) => {
console.log('Invalid image')
});
I am using React-Dropzone npm to use a nicely styled drag and drop out of the box file uploader. I got stuck on the fact that React-Dropzone as of version 8.2.0 didn't include the paths to the file, e.g. shortened it with just the image name. They do however, provide a Blob Url. I can't figure out how to convert a Blob-URL to a Base64 string and then send that to Cloudinary.
Another way can be:
const url = 'blob:http://uri';
const blobToBase64 = (url) => {
return new Promise((resolve, _) => {
// do a request to the blob uri
const response = await fetch(url);
// response has a method called .blob() to get the blob file
const blob = await response.blob();
// instantiate a file reader
const fileReader = new FileReader();
// read the file
fileReader.readAsDataURL(blob);
fileReader.onloadend = function(){
resolve(fileReader.result); // Here is the base64 string
}
});
};
// now you can get the
blobToBase64(url)
.then(base64String => {
console.log(base64String) // i.e: data:image/jpeg;base64,/9j/4AAQSkZJ..
});
// or with await/async
const file = await blobToBase64(url);
console.log(file) // i.e: data:image/jpeg;base64,/9j/4AAQSkZJ..
I've figured it out:
After a few hours, and some nice people posting on StackOverflow I have pieced it together.
const getBlobData = (file) => {
axios({
method: "get",
url: file, // blob url eg. blob:http://127.0.0.1:8000/e89c5d87-a634-4540-974c-30dc476825cc
responseType: "blob",
}).then(function (response) {
var reader = new FileReader();
reader.readAsDataURL(response.data);
reader.onloadend = function () {
var base64data = reader.result;
const formData = new FormData();
formData.append("file", base64data);
formData.append("api_key", YOUR_API_KEY);
// replace this with your upload preset name
formData.append("upload_preset", YOUR_PRESET_NAME);//via cloudinary
axios({
method: "POST",
url: "https://api.cloudinary.com/v1_1/YOUR_CLOUD_NAME/upload",
data: formData,
})
.then((res) => {
const imageURL = res.data.url;
//YOU CAN SET_STATE HOWEVER YOU WOULD LIKE HERE.
})
.catch((err) => {
console.log(err);
});
};
});
};
I am sending a file like this to the server:
const fd = new FormData()
const targetFile = document.getElementById('default_file').files[0]
fd.append('file', targetFile )
fetch('url', {
method: 'POST',
body: fd,
})
I want to be able to encrypt the file with a password before uploading (client-side)
i have tried this so far but i'm not sure where to go next:
const targetFile = document.getElementById('default_file').files[0]
const reader = new FileReader()
reader.readAsArrayBuffer(targetFile)
reader.onload = () => {
console.log(reader.result)
const encrypted = CryptoJs.AES.encrypt(reader.result, "password123") <-- is this correct?
//should i convert the encrypted part to something specific?
}
reader.result returns the arraybuffer of the file, is it this part that i have to encrypt, and will the file stay in the same format so i can upload it to the server without changing code there?