Reputation: 476
I'm looking for the best solution to compress images that's I receive and need to store in my database.
Actually, I convert an image in base64 and then send it to the server.
handleImage = e => {
e.preventDefault();
let reader = new FileReader();
let file = e.target.files[0];
reader.onloadend = () => {
this.setState({
file: file,
image: reader.result
});
}
this.setState({ imgchange: true })
}
And then send the current image in state to the server. But with the low quality image it's fine but when I try to upload a medium-high quality I can't save it on the server, I need a method to compress the image.
Have you any idea to achieve this? Can you show me an example?
Upvotes: 15
Views: 44351
Reputation: 61
import React from "react";
import imageCompression from "browser-image-compression";
function imageOrientation(image) {
var img = new Image();
img.src = image;
return { width: img.naturalWidth, height: img.naturalHeight };
}
const imageCompressionFile = async (image) => {
const options = {
maxSizeMB: 5,
maxWidthOrHeight: 1080,
useWebWorker: true,
};
let { width, height } = imageOrientation(URL.createObjectURL(image));
let compress_file;
if (width > height) {
if (width > 400) {
// landscape
let compressedFile = await imageCompression(image, options);
compress_file = await compressedFile;
} else {
// No landscape
compress_file = await image;
}
} else if (width < height) {
// portrait
if (height > 400) {
let compressedFile = await imageCompression(image, options);
compress_file = await compressedFile;
} else {
// No portrait
compress_file = await image;
}
} else {
const compressedFile = await imageCompression(image, options);
compress_file = await compressedFile;
}
return await compress_file;
};
function APP() {
async function handleImageUpload(event) {
const image = event.target.files[0];
let fileData = await imageCompressionFile(image);
}
return (
<>
<div>
<input
type="file"
accept="image/*"
onChange={(event) => handleImageUpload(event)}
/>
</div>
</>
);
}
export default APP;
Upvotes: 0
Reputation: 7523
Best npm package you can use for image compression is browser-image-compression
. Tested in React and Redux.
npm install browser-image-compression --save
async await syntax:
import React from "react";
import imageCompression from 'browser-image-compression';
function photoUpload() {
async function handleImageUpload(event) {
const imageFile = event.target.files[0];
console.log('originalFile instanceof Blob', imageFile instanceof Blob); // true
console.log(`originalFile size ${imageFile.size / 1024 / 1024} MB`);
const options = {
maxSizeMB: 1,
maxWidthOrHeight: 1920,
useWebWorker: true
}
try {
const compressedFile = await imageCompression(imageFile, options);
console.log('compressedFile instanceof Blob', compressedFile instanceof Blob); // true
console.log(`compressedFile size ${compressedFile.size / 1024 / 1024} MB`); // smaller than maxSizeMB
await uploadToServer(compressedFile); // write your own logic
} catch (error) {
console.log(error);
}
}
return (
<>
<div>
<input type="file" accept="image/*" onChange={event => handleImageUpload(event)}/>
</div>
</>
);
}
export default photoUpload;
For more in details can check on NPM
Upvotes: 20
Reputation: 91
you can use react-image-file-resizer library to compress image
import Resizer from 'react-image-file-resizer';
Resizer.imageFileResizer(
file, //is the file of the new image that can now be uploaded...
maxWidth, // is the maxWidth of the new image
maxHeight, // is the maxHeight of the new image
compressFormat, // is the compressFormat of the new image
quality, // is the quality of the new image
rotation, // is the rotatoion of the new image
responseUriFunc, // is the callBack function of the new image URI
outputType // is the output type of the new image
);
For Example:
import React, { Component } from 'react';
import Resizer from 'react-image-file-resizer';
class App extends Component {
constructor(props) {
super(props);
this.fileChangedHandler = this.fileChangedHandler.bind(this);
}
fileChangedHandler(event) {
var fileInput = false
if(event.target.files[0]) {
fileInput = true
}
if(fileInput) {
Resizer.imageFileResizer(
event.target.files[0],
300,
300,
'JPEG',
100,
0,
uri => {
console.log(uri)
},
'base64'
);
}
}
render() {
return (
<div className="App">
<input type="file" onChange={this.fileChangedHandler}/>
</div>
);
}
}
export default App;
For Details you can read this documentation
Upvotes: 1
Reputation: 796
I've done this in a React/Redux app before with image libraries that ultimately produce a compressed JPG file - if that works for you, then using something like Jimp is an option. It was made for node, but I installed it for use in the browser, and used it like so:
Jimp.read('image.jpg').then((image) => {
if (image.bitmap.data.length > MAX_IMAGE_SIZE) {
image.quality(80); // some value of 'quality'
}
// do something else with the image
});
You can do some fiddling to figure out what the right quality of JPG is right for your app, and adjust accordingly.
When I was using this, I threw together an onDrop
function that processed images a lot like you do - I won't guarantee that this code is super clean or super efficient - it came from a throwaway prototype - but it should get you started on the right path:
handleFileDrop(e) {
e.stopPropagation();
e.preventDefault();
var file = e.dataTransfer.files[0];
var reader = new FileReader();
reader.onload = (function(inputFile) {
return function(e) {
var imageBlob = new Blob([e.target.result], {type: inputFile.type});
var src = URL.createObjectURL(imageBlob)
Jimp.read(src, (err, image) => {
// do stuff here
});
})(file);
reader.readAsArrayBuffer(file);
}
Upvotes: 3