In this article, you will learn to crop an image in JavaScript. Specifically, you will see how to achieve this goal with the react-image-crop
React library.
Over the last few years, providing users with features to deal with images has become more and more common. This is why every developer should know how to deal with basic operations on images, such as cropping. This gives them the possibility to choose only the areas they are interested in.
So, let’s see how to crop an image in React with react-image-crop
. Follow this step-by-step tutorial to achieve the following result:
Prerequisites
This is the list of all the prerequisites for the demo application you are going to build:
- Node.js and npm 5.2+ and higher
react-image-crop
>= 8.6.12
Cropping an Image with react-image-crop
You can clone the GitHub repository that supports this article and try the demo application by launching the following commands:
git clone https://github.com/imgly/Blog-How-To-Crop-an-Image-in-React-with-React-Crop-Image.git
cd Blog-How-To-Crop-an-Image-in-React-with-React-Crop-Image
npm i
npm start
Otherwise, you can continue following this tutorial and build the demo application step by step.
1. Creating a React Project
The easiest way to create an empty working project in React is by using Create React App, the officially supported way to create single-page React applications. You can create a new project called react-image-cropper-demo
with the following command:
npx create-react-app react-image-cropper-demo
You will now have a demo project located in the react-image-cropper-demo
folder with this file structure:
react-image-cropper-demo
├── README.md
├── node_modules
├── package.json
├── .gitignore
├── public
│ ├── favicon.ico
│ ├── index.html
│ ├── logo192.png
│ ├── logo512.png
│ ├── manifest.json
│ └── robots.txt
└── src
├── App.css
├── App.js
├── App.test.js
├── index.css
├── index.js
├── logo.svg
├── reportWebVitals.js
└── setupTests.js
Move into the react-image-cropper-demo
folder and launch a local server by running:
cd react-image-cropper-demo
npm start
Visit http://localhost:3000/ in your browser, and you should be able to see the default Create React App screen.
2. Installing react-image-crop
Add the react-image-crop
library to your project’s dependencies by running the following command:
npm install --save react-image-crop
Your package.json
file will be updated accordingly, and you should now be able to see react-image-crop
as a dependency.
Now, you have everything required to start developing your image cropper component.
3. Building the Image Cropper Component
First of all, create a components
folder inside src
. Then, make an ImageCropper
folder containing index.js
and index.css
. These two files will contain the cropper component definition and style respectively.
Initialize index.js
with the following lines of code:
import React from "react";
function ImageCropper() {
return (
<div>
{/*TODO*/}
</div>
);
}
export default ImageCropper;
This way, you have just created an empty ImageCropper
component.
Now, you need to import ReactCrop
, which is part of the react-image-crop
library. Add it to the ImageCropper
imports:
import ReactCrop from 'react-image-crop'
Plus, do not forget to import dist/ReactCrop.css
or ReactCrop.scss
as follows:
import 'react-image-crop/dist/ReactCrop.css';
// or scss:
import 'react-image-crop/lib/ReactCrop.scss';
This is what the final ImageCropper
will look like:
import React, {useState} from "react";
import ReactCrop from 'react-image-crop';
import 'react-image-crop/dist/ReactCrop.css';
import demoImage from "./demo-image.jpg";
function ImageCropper(props) {
const {imageToCrop, onImageCropped} = props;
const [cropConfig, setCropConfig] = useState(
// default crop config
{
unit: '%',
width: 30,
aspect: 16 / 9,
}
);
const [imageRef, setImageRef] = useState();
async function cropImage(crop) {
if (imageRef && crop.width && crop.height) {
const croppedImage = await getCroppedImage(
imageRef,
crop,
'croppedImage.jpeg' // destination filename
);
// calling the props function to expose
// croppedImage to the parent component
onImageCropped(croppedImage);
}
}
function getCroppedImage(sourceImage, cropConfig, fileName) {
// creating the cropped image from the source image
const canvas = document.createElement('canvas');
const scaleX = sourceImage.naturalWidth / sourceImage.width;
const scaleY = sourceImage.naturalHeight / sourceImage.height;
canvas.width = cropConfig.width;
canvas.height = cropConfig.height;
const ctx = canvas.getContext('2d');
ctx.drawImage(
sourceImage,
cropConfig.x * scaleX,
cropConfig.y * scaleY,
cropConfig.width * scaleX,
cropConfig.height * scaleY,
0,
0,
cropConfig.width,
cropConfig.height
);
return new Promise((resolve, reject) => {
canvas.toBlob(
(blob) => {
// returning an error
if (!blob) {
reject(new Error('Canvas is empty'));
return;
}
blob.name = fileName;
// creating a Object URL representing the Blob object given
const croppedImageUrl = window.URL.createObjectURL(blob);
resolve(croppedImageUrl);
}, 'image/jpeg'
);
});
}
return (
<ReactCrop
src={imageToCrop || demoImage}
crop={cropConfig}
ruleOfThirds
onImageLoaded={(imageRef) => setImageRef(imageRef)}
onComplete={(cropConfig) => cropImage(cropConfig)}
onChange={(cropConfig) => setCropConfig(cropConfig)}
crossorigin="anonymous" // to avoid CORS-related problems
/>
);
}
ImageCropper.defaultProps = {
onImageCropped: () => {}
}
export default ImageCropper;
imageToCrop
is the source image received from the props. The or statement used when assigning the ReactCrop
's src
props assures that either imageToCrop
or a default demo image is shown. After being loaded, a reference to the image is saved and then used when performing the cropping operation. Then, whenever a user uses the component to try to crop an image, the cropConfig
object containing the crop settings is updated accordingly. Finally, when the user stops selecting the area to crop, cropImage
is called. This function is in charge of producing the cropped image and passing it to the onImageCropped
function received from the props.
4. Putting It All Together
Now it is time to see the ImageCropper
component in action. All you need to do, is change the App.js
file as follows:
import React, {useState} from "react";
import './App.css';
import ImageCropper from "./components/ImageCropper";
function App() {
const [imageToCrop, setImageToCrop] = useState(undefined);
const [croppedImage, setCroppedImage] = useState(undefined);
const onUploadFile = (event) => {
if (event.target.files && event.target.files.length > 0) {
const reader = new FileReader();
reader.addEventListener('load', () =>
setImageToCrop(reader.result)
);
reader.readAsDataURL(event.target.files[0]);
}
};
return (
<div className="app">
<input
type="file"
accept="image/*"
onChange={onUploadFile}
/>
<div>
<ImageCropper
imageToCrop={imageToCrop}
onImageCropped={(croppedImage) => setCroppedImage(croppedImage)}
/>
</div>
{
croppedImage &&
<div>
<h2>Cropped Image</h2>
<img
alt="Cropped Image"
src={croppedImage}
/>
</div>
}
</div>
);
}
export default App;
The input
element allows users to upload an image, then stored it in imageToCrop
and passed to ImageCropper
. Each time a user crops it, the resulting image is saved thanks to the setCroppedImage
function. Then, it is finally displayed in the Cropped Image section as presented in the fiddle at the beginning of the article.
Final Considerations on react-image-crop
Cropping an image from scratch is not an easy task. This is why using a library like react-image-crop
is the recommended approach. As you have just seen, you can achieve your goal with just a few lines of code. This is great! On the other hand, these libraries are designed to achieve specific goals, like cropping an image. What if you need to perform or get users the possibility to do other image-related operations? You may be ending up with as many libraries as operations required.
Not only might they have very different UIs, but it may also be complicated to integrate them all in the same project. This is why in such a circumstance, a commercial and wider solution like PhotoEditorSDK should be the preferred approach. In fact, with only one library you get several tools to treat images as you want, while preserving the consistency of your application's UI. Also, whenever you need help, you can ask for support from the img.ly developers who built the SDK or visit one of the myriad snappy integration guides written by the developers on the blog.
Cropping an Image with PhotoEditorSDK
First, you should read this article from the official documentation on how to get started with PhotoEditorSDK
in React. Then, by using the transform tool you can perform cropping, resizing, flipping, and rotation operations with just one feature. This way, you should be able to achieve the desired result:
Conclusion
In this article, we looked at how to crop an image in React. Cropping an image can turn into a complex task and this is using a library should be the preferred approach. In particular, react-image-crop
allows you to crop an image easily and with only a handful of lines of code, as we have seen. On the other hand, it is a library with a very specific purpose. So, if you needed to perform more than one operation on your images, you might need a more advanced and complete solution like PhotoEditorSDK
.
Thanks for reading! We hope that you found this article helpful. Feel free to reach out to us on Twitter with any questions, comments, or suggestions.