CoffeAbuser
CoffeAbuser

Reputation: 476

Best way to compress an image Javascript React Web App

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

Answers (4)

Dhrupad Patel
Dhrupad Patel

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

Maheshvirus
Maheshvirus

Reputation: 7523

Best npm package you can use for image compression is browser-image-compression. Tested in React and Redux.

  • Install 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

Jagdish Bhatt
Jagdish Bhatt

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

elsyr
elsyr

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

Related Questions