I'm using react-dropzone
package to add images to my app. and in my app i need to send the images to a firebase server. but before i do that i needed to handle image conversions.
so i saw this tutorial on youtube that shows how to convert images to webp format in javascript. but i can't integrate it with my react app.
can anyone please show me how to do just that?
const [files, setFiles] = useState([]);
const [text, setText] = useState(
"Drag and Drop or click here to upload Images"
);
const [drag, setDrag] = useState(false);
const { getRootProps, getInputProps } = useDropzone({
accept: {
"image/*": [],
},
maxFiles: 9,
onDragEnter: () => {
setText("drag your images in here");
setDrag(true);
},
onDragLeave: () => {
setText(
files.length == 0
? "Drag and Drop or click here to upload Images"
: "Edit your Image..."
);
setDrag(false);
},
onDrop: (acceptedFiles) => {
setText("Edit your Image...");
setDrag(false);
const newFiles = acceptedFiles.map((file) => {
return Object.assign(file, {
preview: URL.createObjectURL(file),
});
});
if (files.length < 9) {
setFiles((prev) => [...prev, ...newFiles]);
files.map((file) => {
newFiles.forEach((newFile) => {
if (newFile.name == file.name) {
alert(newFile.name " is a duplicate file");
setFiles(
files,
files.filter((val) => val !== newFile)
);
}
});
});
} else if (acceptedFiles.length >= 9) {
alert("select maximum of 9 images");
} else {
alert("maximum images to be selected is 9");
}
},
});
if there is any packages or methods i appreciate it.
CodePudding user response:
Image conversion is something you do server side, you shouldn't try to convert the file front-end side... consider implementing a middleware between firebase and your app, even a basic express server would do
CodePudding user response:
If the images are supposed to be uploaded to a server to be shown to other users, it's probably best to leave the conversion to server-side code. The server would have to verify the validity of the file anyway.
That being said, modern browsers offer a variety of methods to work with graphics, which can be used to preform the conversion. Here's one way to do this:
/**
* Convert between any image formats the browser supports
* @param {Blob} source A Blob (or File) containing the image to convert
* @param {string} type The MIME type of the target format
* @returns {Promise<Blob>} The converted image
*/
async function convert(source, type) {
let image = await createImageBitmap(source);
let canvas = new OffscreenCanvas(image.width, image.height);
let context = canvas.getContext("2d");
context.drawImage(image, 0, 0);
let result = await canvas.convertToBlob({ type });
image.close();
return result;
}
This requires a compatible browser. First of all, the browser needs to support WebP, which most browsers do. Second of all, it needs to support OffscreenCanvas
, which excludes Safari (as of January 2023). In that case, you can use the following method, which does not work in WebWorkers:
/**
* Convert between any image formats the browser supports
* @param {Blob} source A Blob (or File) containing the image to convert
* @param {string} type The MIME type of the target format
* @returns {Promise<Blob>} The converted image
*/
async function convertLegacy(source, type) {
let image = await createImageBitmap(source);
let canvas = document.createElement("canvas");
canvas.width = image.width;
canvas.height = image.height;
let context = canvas.getContext("2d");
context.drawImage(image, 0, 0);
let result = await new Promise((resolve, reject) => {
canvas.toBlob((blob) => {
if (blob != null) {
resolve(blob);
} else {
reject(new Error("Failed to convert file"));
}
}, type, 1);
});
image.close();
return result;
}