Security News
Research
Data Theft Repackaged: A Case Study in Malicious Wrapper Packages on npm
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
react-image-crop
Advanced tools
The react-image-crop package is a React component for cropping images with a user-friendly interface. It allows users to select and crop images within a defined area, providing a variety of customization options for the cropping process.
Basic Image Cropping
This code demonstrates the basic usage of the react-image-crop package. It allows users to upload an image and then crop it using a resizable and draggable crop area.
import React, { useState } from 'react';
import ReactCrop from 'react-image-crop';
import 'react-image-crop/dist/ReactCrop.css';
function ImageCropper() {
const [crop, setCrop] = useState({ aspect: 16 / 9 });
const [src, setSrc] = useState(null);
const onImageLoaded = (image) => {
// Perform actions when the image is loaded
};
const onCropComplete = (crop) => {
// Perform actions when the crop is complete
};
const onCropChange = (crop) => {
setCrop(crop);
};
const handleFileChange = (e) => {
const file = e.target.files[0];
const reader = new FileReader();
reader.onload = () => setSrc(reader.result);
reader.readAsDataURL(file);
};
return (
<div>
<input type="file" accept="image/*" onChange={handleFileChange} />
{src && (
<ReactCrop
src={src}
crop={crop}
onImageLoaded={onImageLoaded}
onComplete={onCropComplete}
onChange={onCropChange}
/>
)}
</div>
);
}
export default ImageCropper;
Aspect Ratio Locking
This code demonstrates how to lock the aspect ratio of the crop area. In this example, the aspect ratio is set to 1:1, meaning the crop area will always be a square.
import React, { useState } from 'react';
import ReactCrop from 'react-image-crop';
import 'react-image-crop/dist/ReactCrop.css';
function AspectRatioCropper() {
const [crop, setCrop] = useState({ aspect: 1 / 1 });
const [src, setSrc] = useState(null);
const onImageLoaded = (image) => {
// Perform actions when the image is loaded
};
const onCropComplete = (crop) => {
// Perform actions when the crop is complete
};
const onCropChange = (crop) => {
setCrop(crop);
};
const handleFileChange = (e) => {
const file = e.target.files[0];
const reader = new FileReader();
reader.onload = () => setSrc(reader.result);
reader.readAsDataURL(file);
};
return (
<div>
<input type="file" accept="image/*" onChange={handleFileChange} />
{src && (
<ReactCrop
src={src}
crop={crop}
onImageLoaded={onImageLoaded}
onComplete={onCropComplete}
onChange={onCropChange}
/>
)}
</div>
);
}
export default AspectRatioCropper;
Custom Crop Area Styling
This code demonstrates how to apply custom styling to the crop area. By importing a custom CSS file, you can style the crop area to fit your application's design requirements.
import React, { useState } from 'react';
import ReactCrop from 'react-image-crop';
import 'react-image-crop/dist/ReactCrop.css';
import './CustomCrop.css'; // Custom CSS for crop area
function CustomStyledCropper() {
const [crop, setCrop] = useState({ aspect: 16 / 9 });
const [src, setSrc] = useState(null);
const onImageLoaded = (image) => {
// Perform actions when the image is loaded
};
const onCropComplete = (crop) => {
// Perform actions when the crop is complete
};
const onCropChange = (crop) => {
setCrop(crop);
};
const handleFileChange = (e) => {
const file = e.target.files[0];
const reader = new FileReader();
reader.onload = () => setSrc(reader.result);
reader.readAsDataURL(file);
};
return (
<div>
<input type="file" accept="image/*" onChange={handleFileChange} />
{src && (
<ReactCrop
src={src}
crop={crop}
onImageLoaded={onImageLoaded}
onComplete={onCropComplete}
onChange={onCropChange}
className="custom-crop"
/>
)}
</div>
);
}
export default CustomStyledCropper;
react-easy-crop is another React component for cropping images. It provides a simple and intuitive interface for image cropping, with support for touch devices and various customization options. Compared to react-image-crop, react-easy-crop offers a more modern and responsive design, making it a good choice for mobile-friendly applications.
react-avatar-editor is a React component specifically designed for editing and cropping profile pictures. It allows users to zoom, rotate, and crop images, making it ideal for applications that require user profile image editing. While it offers similar cropping functionality to react-image-crop, it also includes additional features like image rotation and zooming.
cropperjs is a JavaScript image cropping library that can be used with React through a wrapper component. It provides a rich set of features, including aspect ratio locking, zooming, rotating, and more. Compared to react-image-crop, cropperjs offers a more comprehensive set of image manipulation tools, making it suitable for more advanced image editing needs.
An image cropping tool for React with no dependencies.
If React Crop doesn't cover your requirements then take a look at Pintura (our sponsor). It features cropping, rotating, filtering, annotation, and lots more.
npm i react-image-crop --save
yarn add react-image-crop
pnpm add react-image-crop
This library works with all modern browsers. It does not work with IE.
Include the main js module:
import ReactCrop from 'react-image-crop'
Include either dist/ReactCrop.css
or ReactCrop.scss
.
import 'react-image-crop/dist/ReactCrop.css'
// or scss:
import 'react-image-crop/src/ReactCrop.scss'
import ReactCrop, { type Crop } from 'react-image-crop'
function CropDemo({ src }) {
const [crop, setCrop] = useState<Crop>()
return (
<ReactCrop crop={crop} onChange={c => setCrop(c)}>
<img src={src} />
</ReactCrop>
)
}
See the sandbox demo for a more complete example.
<link href="https://unpkg.com/react-image-crop/dist/ReactCrop.css" rel="stylesheet" />
<script src="https://unpkg.com/react-image-crop/dist/index.umd.cjs"></script>
Note when importing the script globally using a <script>
tag access the component with ReactCrop.Component
.
onChange: (crop: PixelCrop, percentCrop: PercentCrop) => void
A callback which happens for every change of the crop (i.e. many times as you are dragging/resizing). Passes the current crop state object.
Note you must implement this callback and update your crop state, otherwise nothing will change!
<ReactCrop crop={crop} onChange={(crop, percentCrop) => setCrop(crop)} />
crop
and percentCrop
are interchangeable. crop
uses pixels and percentCrop
uses percentages to position and size itself. Percent crops are resistant to image/media resizing.
crop?: Crop
Starting with no crop:
const [crop, setCrop] = useState<Crop>()
<ReactCrop crop={crop} onChange={c => setCrop(c)}>
<img src={src} />
</ReactCrop>
Starting with a preselected crop:
const [crop, setCrop] = useState<Crop>({
unit: '%', // Can be 'px' or '%'
x: 25,
y: 25,
width: 50,
height: 50
})
<ReactCrop crop={crop} onChange={c => setCrop(c)}>
<img src={src} />
</ReactCrop>
⚠️ You must ensure the crop is in bounds and correct to the aspect ratio if manually setting. Aspect ratios can be tricky when using %. You can make use of centerCrop
and makeAspectCrop
helpers. See How can I center the crop? or the CodeSanbox Demo for examples.
aspect?: number
The aspect ratio of the crop, e.g. 1
for a square or 16 / 9
for landscape. Omit/pass undefined for a free-form crop.
minWidth?: number
A minimum crop width, in pixels.
minHeight?: number
A minimum crop height, in pixels.
maxWidth?: number
A maximum crop width, in pixels.
maxHeight?: number
A maximum crop height, in pixels.
keepSelection?: boolean
If true is passed then selection can't be disabled if the user clicks outside the selection area.
disabled?: boolean
If true then the user cannot resize or draw a new crop. A class of ReactCrop--disabled
is also added to the container for user styling.
locked?: boolean
If true then the user cannot create or resize a crop, but can still drag the existing crop around. A class of ReactCrop--locked
is also added to the container for user styling.
className?: string
A string of classes to add to the main ReactCrop
element.
style?: React.CSSProperties
Inline styles object to be passed to the image wrapper element.
onComplete?: (crop: PixelCrop, percentCrop: PercentCrop) => void
A callback which happens after a resize, drag, or nudge. Passes the current crop state object.
percentCrop
is the crop as a percentage. A typical use case for it would be to save it so that the user's crop can be restored regardless of the size of the image (for example saving it on desktop, and then using it on a mobile where the image is smaller).
onDragStart?: (e: PointerEvent) => void
A callback which happens when a user starts dragging or resizing. It is convenient to manipulate elements outside this component.
onDragEnd?: (e: PointerEvent) => void
A callback which happens when a user releases the cursor or touch after dragging or resizing.
renderSelectionAddon?: (state: ReactCropState) => React.ReactNode
Render a custom element inside the crop selection.
ruleOfThirds?: boolean
Show rule of thirds lines in the cropped area. Defaults to false
.
circularCrop?: boolean
Show the crop area as a circle. If your aspect
is not 1
(a square) then the circle will be warped into an oval shape. Defaults to false
.
This isn't part of the library but there is an example over here CodeSandbox Demo.
You might find that some images are rotated incorrectly. Unfortunately this is a browser wide issue not related to this library. You need to fix your image before passing it in.
You can use the following library to load images, which will correct the rotation for you: https://github.com/blueimp/JavaScript-Load-Image/
You can read an issue on this subject here: https://github.com/sekoyo/react-image-crop/issues/181
If you're looking for a complete out of the box image editor which already handles EXIF rotation then consider using Pintura.
This library is deliberately lightweight and minimal for you to build features on top of. If you wish to perform more advanced image editing out of the box then consider using Pintura.
The easiest way is to use the percentage unit:
crop: {
unit: '%',
width: 50,
height: 50,
x: 25,
y: 25
}
Centering an aspect ratio crop is trickier especially when dealing with %
. However two helper functions are provided:
<ReactCrop crop={crop} aspect={16 / 9}>
<img src={src} onLoad={onImageLoad} />
</ReactCrop>
makeAspectCrop
to create your desired aspect and then centerCrop
to center it:function onImageLoad(e) {
const { naturalWidth: width, naturalHeight: height } = e.currentTarget
const crop = centerCrop(
makeAspectCrop(
{
// You don't need to pass a complete crop into
// makeAspectCrop or centerCrop.
unit: '%',
width: 90,
},
16 / 9,
width,
height
),
width,
height
)
setCrop(crop)
}
Also remember to set your crop using the percentCrop on changes:
const onCropChange = (crop, percentCrop) => setCrop(percentCrop)
And your aspect
prop should be set to the same value: <ReactCrop aspect={16 / 9} ... />
.
To develop run pnpm install && pnpm dev
and open the localhost server in your browser. Update code and it will reload. When you're ready, open a pull request.
FAQs
A responsive image cropping tool for React
The npm package react-image-crop receives a total of 362,218 weekly downloads. As such, react-image-crop popularity was classified as popular.
We found that react-image-crop demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Research
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Research
Security News
Attackers used a malicious npm package typosquatting a popular ESLint plugin to steal sensitive data, execute commands, and exploit developer systems.
Security News
The Ultralytics' PyPI Package was compromised four times in one weekend through GitHub Actions cache poisoning and failure to rotate previously compromised API tokens.