Image Crop in React JS

Today, I will teach You How to crop an Image in React Js using the react-image-crop Package. Image Crop in React JS.

I will show you How to crop an Image and Download the Image to You Local Computer. So First I will choose the File then Try to crop it.

See our More Tutorials on React

Display Selected Row record in Material UI Model Box using React

Form Validation in React Material

Photo Capture in React

OTP countdown timer in react

You can download the Image Crop package from here: https://www.npmjs.com/package/react-image-crop.

This image has an empty alt attribute; its file name is maxresdefault-1024x576.jpg

Installation Process

1 ) Install Material UI Package and ICONS

First, install the Material UI Package because I am using Material UI not Bootstrap. To Install Material UI and Icons You can use the below commands

npm install @material-ui/core // Using npm

yarn add @material-ui/core // Using yarn

2 ) Install React Image Crop Package

You can install REACT Image Crop package using npm or yarn.

Using npm

npm i react-image-crop –save

Using Yarn

yarn add react-image-crop

You can Import React Image Crop package in your project using this line

import ReactCrop from 'react-image-crop';

Code Part Starts Here

src/ImageCrop.js

import React from 'react';
import { withStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';
import Alert from '@material-ui/lab/Alert';
import Dialog from '@material-ui/core/Dialog';
import MuiDialogTitle from '@material-ui/core/DialogTitle';
import MuiDialogContent from '@material-ui/core/DialogContent';
import MuiDialogActions from '@material-ui/core/DialogActions';
import IconButton from '@material-ui/core/IconButton';
import CloseIcon from '@material-ui/icons/Close';
import Box from '@material-ui/core/Box';
import Typography from '@material-ui/core/Typography';
import PublishIcon from '@material-ui/icons/Publish';

import {useState,useEffect,useCallback, useRef} from 'react';

import CloudUploadIcon from '@material-ui/icons/CloudUpload';

import { useHistory } from "react-router-dom";

import 'react-image-crop/dist/ReactCrop.css';
import ReactCrop from 'react-image-crop';
import Snackbar from '@material-ui/core/Snackbar';
import { makeStyles } from "@material-ui/core/styles";

const styless = makeStyles((theme) => ({
  root: {
    background: '#4caf50'
  }
}));
// Code for Image crop 

function generateDownload(canvas, crop) {
  if (!crop || !canvas) {
    return;
  }

  canvas.toBlob(
    (blob) => {
      const previewUrl = window.URL.createObjectURL(blob);

      const anchor = document.createElement('a');
      anchor.download = 'cropPreview.png';
      anchor.href = URL.createObjectURL(blob);
      anchor.click();

      window.URL.revokeObjectURL(previewUrl);
    },
    'image/png',
    1
  );
}

// End of Image crop 

const styles = (theme) => ({
  root: {
    margin: 0,
    padding: theme.spacing(2),
  },
  closeButton: {
    position: 'absolute',
    right: theme.spacing(1),
    top: theme.spacing(1),
    color: theme.palette.grey[500],
  },
});

const DialogTitle = withStyles(styles)((props) => {
  const { children, classes, onClose, ...other } = props;
  return (
    <MuiDialogTitle disableTypography className={classes.root} {...other}>
      <Typography variant="h6">{children}</Typography>
      {onClose ? (
        <IconButton aria-label="close" className={classes.closeButton} onClick={onClose}>
          <CloseIcon />
        </IconButton>
      ) : null}
    </MuiDialogTitle>
  );
});

const DialogContent = withStyles((theme) => ({
  root: {
    padding: theme.spacing(2),
  },
}))(MuiDialogContent);

const DialogActions = withStyles((theme) => ({
  root: {
    margin: 0,
    padding: theme.spacing(1),
  },
}))(MuiDialogActions);

export default function CustomizedDialogs(props) {

  // More Code for Image Crop 
  const [upImg, setUpImg] = useState();
  const imgRef = useRef(null);
  const previewCanvasRef = useRef(null);
  const [crop, setCrop] = useState({ unit: '%', width: 30, aspect: 16 / 9 });
  const [completedCrop, setCompletedCrop] = useState(null);


  const classes = styless();
  

  const onSelectFile = (e) => {


    if (e.target.files && e.target.files.length > 0) {
      const reader = new FileReader();
      reader.addEventListener('load', () => setUpImg(reader.result));
      reader.readAsDataURL(e.target.files[0]);
    }
  };

  const onLoad = useCallback((img) => {
    imgRef.current = img;
  }, []);

  useEffect(() => {
    if (!completedCrop || !previewCanvasRef.current || !imgRef.current) {
      return;
    }

    const image = imgRef.current;
    const canvas = previewCanvasRef.current;
    const crop = completedCrop;

    const scaleX = image.naturalWidth / image.width;
    const scaleY = image.naturalHeight / image.height;
    const ctx = canvas.getContext('2d');
    const pixelRatio = window.devicePixelRatio;

    canvas.width = crop.width * pixelRatio;
    canvas.height = crop.height * pixelRatio;

    ctx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
    ctx.imageSmoothingQuality = 'high';

    ctx.drawImage(
      image,
      crop.x * scaleX,
      crop.y * scaleY,
      crop.width * scaleX,
      crop.height * scaleY,
      0,
      0,
      crop.width,
      crop.height
    );
  }, [completedCrop]);
  
  // End of Crop Image code 

  const [open, setOpen] = React.useState(false);

  const handleClickOpen = () => {
    setOpen(true);
  };
  const handleClose = () => {
    setOpen(false);
  };

  const file = new File(["foo"], "", {
    type: "text/plain",
  });

  const [selectedFile, setSelectedFile] = useState();
	const [isFilePicked, setIsFilePicked] = useState(false);

  const changeHandler = (event) => {
		setSelectedFile(event.target.files[0]);
		//setIsSelected(true);
	};
   

  const [fileList, setFileList] = useState();

  useEffect(() => {
    console.log(fileList);
  });

  const onDropzoneAreaChange = (files,e) => {
  
    setFileList(files);
    //console.log(fileList);
    //console.log("Files:", files);

  //   if (!e.target.files[0].name.match(/.(jpg|jpeg|png|gif)$/i)){
  //     alert('not an image');
  // }
  }; 

  const history = useHistory();
  const[filename,setFileName]= useState([]);
  const[filesNa,setFilesNa]= useState([]);
  const[modelImg,setModelImg] = useState('');

  const handleChange = (e) =>
  {
      if(!e.target.files[0].name.match(/.(pdf|docx)$/i))
      { 
          const reader = new FileReader();
          reader.addEventListener('load', () => setFileName(reader.result));
          reader.readAsDataURL(e.target.files[0]);
          setFileName(e.target.files[0].name)
          }
        else
        {
          setFilesNa(handleClicks) // Code for Alert message show below 
          setFilesNa(e.target.files[0].name)
        }
  }
  
   // Code for Snackbar 

   const [opens, setOpens] = React.useState(false);

   const handleClicks = () => {
     setOpens(true);
   };
 
   const handleCloses = (event, reason) => {
     if (reason === 'clickaway') {
       return;
     }
 
     setOpens(false);
   };
  return (
    <div>
     <Box mt={4}><Typography align="center" variant="h4">Image Upload and Image Crop</Typography></Box>
    <Button onClick={handleClickOpen} variant="contained" style={{background:"#2121a5",color:"white",marginTop:"50px"}} ><PublishIcon/>Chooce File</Button>
      <div>  
      <Dialog onClose={handleClose} aria-labelledby="customized-dialog-title" open={open}>
      <DialogTitle id="customized-dialog-title" onClose={handleClose}>
       <div> {filename != '' ? <Typography><b> Image Crop </b></Typography> : <Typography><b> File Upload </b></Typography> } </div>
      </DialogTitle>
       
          <DialogContent dividers>
            <Box >
            <div className="File" style={{width:"300px"}}>
              <Box align="center" mt={2}>
                
              {filename != '' ? <p></p> : <CloudUploadIcon color="disabled" fontSiz="large"  style={{width:40, height:40,}}/>  }</Box >

              {filename != '' ? <Typography align="center">Click and drag for cropping</Typography> : <Typography align="center">{ filesNa != '' ? <p><Alert>{filesNa}</Alert> </p> : <h4>No File Selected</h4>}</Typography>  }
                       
            </div>
 
            <div className="Image" style={{marginTop:"10px"}}>
             <form>
              <ReactCrop
                src={filename}
                onImageLoaded={onLoad}
                crop={crop}
                onChange={(c) => setCrop(c)}
                onComplete={(c) => setCompletedCrop(c)}
                style={{height:"120px",width:"200px"}}
              />
               <div>
                <canvas
                  ref={previewCanvasRef}
                  // Rounding is important so the canvas width and height matches/is a multiple for sharpness.
                  style={{
                    width: Math.round(completedCrop?.width ?? 0),
                    height: Math.round(completedCrop?.height ?? 0)
                  }}
                />
             </div>
            
              </form>
            </div>  
            {filename != '' ?
            
            <Box align="center" mt={2}><Button type="button" size="small"  variant="contained" color="secondary"  disabled={!completedCrop?.width || !completedCrop?.height}onClick={() =>generateDownload(previewCanvasRef.current, completedCrop)}>Download</Button></Box>
            
              : <Box align="center">
                 <Button variant="contained" style={{color:"green"}} size="small" component="label" style={{marginTop:"10px"}}>
                   Choose File
                 <input  type="file" accept=".png, .jpg, .jpeg, .pdf,.docx"  hidden onChange={handleChange}/>
                 </Button>   
               </Box>
                }
              </Box>
            
        </DialogContent>
      <DialogActions>
        <Button autoFocus onClick={handleClose} style={{color:"green"}}>
         Submit
        </Button>
       
      </DialogActions>
    </Dialog>
    </div>
    <Snackbar
        anchorOrigin={{
          vertical: 'bottom',
          horizontal: 'left',
        }}
       
        open={opens}
        autoHideDuration={6000}
        onClose={handleCloses}
        message="File Uploaded Successfully"
        ContentProps={{
          classes: {
            root: classes.root
          }
        }}
        action={
          <React.Fragment>
           
            <IconButton size="small" aria-label="close" color="inherit" onClick={handleCloses}>
              <CloseIcon fontSize="small" />
            </IconButton>
          </React.Fragment>
        }
      />
    </div>
  );
}

Now Call this file in App.js

import logo from './logo.svg';
import './App.css';
import ImageCrop from './ImageCrop'

function App() {
  return (
    <div className="App">
      <ImageCrop/>
    </div>
  );
}

export default App;

Now Run the Project using the npm start command

Subscribe to My Programming YouTube Channel Before Downloading the code :

Download the Project: Image Crop in React JS

Leave a Reply

Your email address will not be published. Required fields are marked *