sekoyo / react-image-crop Goto Github PK
View Code? Open in Web Editor NEWA responsive image cropping tool for React
License: ISC License
A responsive image cropping tool for React
License: ISC License
Issue
Crop range disappears roughly 2 seconds following a selection.
Expected Result
Crop range stays until new range generated or user clicks on other element.
Code
<ReactCrop
crop={{aspect:1}}
src={this.state.imagePreviewUrl}
onComplete={(c,p)=>this.cropComplete(c,p)}
keepSelection
/>
If you need more info I'd be happy to provide a GIF demonstrating this issue.
Would be great to have the component load with a crop already in place.
Assuming I will to initialize the cropper with some image URL and I want to be able to edit it (meaning to crop the image and call canvas.toDataURL based on the cropped image). The problem is, I will get
Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.
while calling canvas.toDataURL
because the server didn't send "Access-Control-Allow-Origin: *
response header. In order for the server to send such header I need to load the image with crossOrigin = 'anonymous'
attribute set. Would it be OK to make it configurable via props that underlying the (I use '.ReactCrop--image-copy'
image to load it onto canvas and get dataURL) has crossOrigin = 'anonymous'
attribute set? (I can issue a PR if such change is OK.)
The responsive aspect of this is great, but I'm not seeing a way to limit height for tall images. Is there an easy path to doing this?
Apparently the additional parameter pixelCrop
of onChangeComplete
is always undefined
.
And also, is there any way to set the crop on pixel units? Instead of converting it from pixel units to percentage every time in order to use it?
what are your thoughts on using inline styles for this component? any objections if I implement it?
Any plans to add support for rotating the image? Or does anyone have experience rotating the image, while maintaining the proper directionality of the cropper? Basically I'm thinking something along the lines of the following:
onImageLoaded
callback is firedrotation
prop (or potentially crop
attribute), which accepts a number of degrees to rotate the image clockwiseI'd like to work on this, but I'd want to find out from the project maintainers if this is potentially out of scope for this project (or impossible, if I'm missing something). Thanks!
EDIT: Realizing that EXIF manipulation is definitely out of scope here. But it would be nice if I could specify a particular CSS transform for how the image is displayed based on a rotation
prop.
Create a ReactCrop with crop.aspect=1 and ellipse=true. Try shrinking and growing the circle. At some point when the circle is small and you're trying to make it larger, it will suddenly invert around its upper handle and/or become very small.
I'm using the latest (1.0.0-rc3) version of react-image-crop with the following crop attributes:
const cropAttributes = {
width: 100,
height: 12,
x: 0,
y: 0,
aspect: 1663/200
}
and I'm receiving the following error in the Chrome console:
Error: <polygon> attribute points: Expected number, "0 0, 1 0, 1 NaN, 0 NaN".
Interestingly enough, this error has no effect on the crop. Everything works as expected, the aspect ratio is locked, the height, width, and coordinates are also correct, even with different values.
It seems that the inclusion of aspect
in the attributes is the only thing that causes this error. Also, if the aspect
is the only attribute specified, no error occurs:
const cropAttributes = {
aspect: 1663/200
}
I suspect this might be an issue with webkit but I'm not 100% certain.
I am looking to create a cropper which will be able to zoom an image via css while not scaling the selection marque. I would like to be able to pass a property of css styles which will be applied to the image behind the marque. Then, when the image is cropped, it will identify the correct portion of the image to crop and pass the updated pixel values in the callback. On first pass, I thought it may just be a matter of passing a style variable to be applied to the image. However now that I have thought this out, it seems as though the prop would need to be a value which would be included in calculations in the project to both calculate the scaling of the image as well as calculation of pixels based on the scale.
As we would like to use this library in our project, I am going to create a fork and start playing around with how to potentially solve this. It should be able to be done without making a breaking change by adding one or possibly two addition props to the root element allowing for scaling of the background image.
One other consideration would be about how to determine where the image is scaled (anchor).
I'd be curious to hear any thoughts you have on this topic.
Is there an elegant way to take the cropped state and access the cropped image? I would like to crop the image and submit the cropped image to a server and subsequently send to amazon S3 for storage. How can I access the image after cropping to attach to an ajax request?
Tried that in Chrome. Grabbing the corner and trying to make the crop area smaller, causes moving the whole crop area to some other part of the image. Pretty nasty ;)
Can you please mention License? Is it licensed under MIT?
Hi,
i set the minHeight and minWidth arguments(in percentage) expecting the component to force a minimum crop area but apparently it does nothing. Any suggestions on how to use that?
Hi, I'm not sure if this is by design, but the following example in the readme:
var crop = {
width: 30,
aspect: 16/9
}
won't display the crop selection because height
is falsy, which sets this.cropInvalid
to true.
However, later on in ensureAspectDimensions
, since width
and aspect
are both set, the value for height
becomes fixed to something valid anyway, and the same if only height
and aspect
are set. Because of this, do you think the crop selection should be rechecked for validity after ensureAspectDimensions
?
Thanks for your time!
Getting Module not found: Error: Can't resolve './dist/ReactCrop'
after upgrading to latest just now
It seems that ReactCrop
displays vertical images preserving their original size. Is there a way to fit image inside the parent
Right out of the box, Cropper will make any landscape image to be adjusted to cropper's width and height. Basically image dimensions are adjusted so that they fit. Example:
Vertical images on the other hand would be shown in their full height.
My image: http://pngimg.com/uploads/tree/tree_PNG230.png
This is how it looks on a screen:
Please let me know if I need to provide any other extra information.
Hi guys!
Here is a quick workaround for making the opacity background around the selection box work in IE.
Just using box shadow you can make the rest of the element have a dark opacity or whatever color you would like. You can check the following example:
.ReactCrop--crop-selection {
...
box-shadow: 0 0 0 9999px rgba(0,0,0,.5);
}
Its up to you to make the decision of either make box shadow work just on IE or remove the background.
When using the box-shadow
I suggest that you wrap the image container with a element which have overflow: hidden
css rule, to not make the box shadow bleed across all the page.
I have a codepen where i just did a box using the box shadow.
Cheers!
I initialize the component like this
const cropData = {
keepSelection: true,
aspect: 1,
top: 0,
left: 0,
width: 100
};
<ReactCrop src={ src } crop={ cropData } />
However the selection is not visible on the image (the image is well over 600 x 600). And when the user clicks outside a selection, the selection is discarded.
Hello, first of all thank you for very nice library.
I am facing issue with following workflow:
Initial selections works fine:
Initial selection lost and cropping interface doesn't work anymore after moving to the next input:
My source code:
import React, { Component, PropTypes } from 'react';
import Crop from 'react-image-crop';
export default class CropWrapper extends Component {
static propTypes = {
initialValue: PropTypes.any,
src: PropTypes.string,
onChange: PropTypes.func
}
componentWillMount() {
const { x, y, width, height } = this.props.initialValue;
this.state = { x, y, width, height, aspect: 1 };
}
componentDidMount() {
require('react-image-crop/dist/ReactCrop.css');
}
handleCropChange = (crop) => {
// this.props.onChange(crop);
this.setState(crop);
}
handleCropComplete = (crop) => {
// this.props.onChange(crop);
this.setState(crop);
}
render() {
const { x, y, width, height, aspect } = this.state;
return (
<Crop
src={this.props.src}
crop={{ x, y, width, height, aspect }}
keepSelection={true}
onChange={this.handleCropChange}
onComplete={this.handleCropComplete}
/>
);
}
}
I just upgraded to RC4 and noticed when doing require('react-image-crop')
I get back an object with a default
property, rather than the ReactImageCrop component as I would expect. I think this is the result of using an ES6 export default
construct, which unfortunately doesn't transpile well to old-fashioned require() calls.
PS.: Thanks for your great work!
There is still a lot of us that haven't switched from Babel5 to 6.
The latest commit broke all my builds and I get this error:
ERROR in ./~/react-image-crop/index.js
Module parse failed: /usr/src/app/node_modules/react-image-crop/index.js Line 2: Unexpected token
You may need an appropriate loader to handle this file type.
| //http://stackoverflow.com/a/33683495/414062
| import ReactCrop from './dist/ReactCrop';
| export default ReactCrop;
|
Please consider doing something like this:
var ReactCrop = require('./dist/ReactCrop');
module.exports = ReactCrop;
I've tested it and can confirm that this works in Babel 5.
I have a ReactCrop component inside of another component within my app, and without fail whenever I change the state of the parent component with setState(), the ReactCrop component seems to reset and lose its crop box. I am not changing any of the props or state related to the ReactCrop component, the state I am changing is completely unrelated. I've tried adding a unique key to the ReactCrop component and it has not helped. Any ideas why this might be?
as the title, it can be a File object
Hi,
I'm having issues with the crop box not showing on Safari (9.1.2).
Functionality is fine; I can drag and the crop box will appear, but it does not auto appear on loading even though I have defined the crop settings.
No issues on Chrome so it's definitely a Safari issue.
I'm trying to crop a relatively large image 2832 × 1602, and I set the aspect to 1/1
. But the pixelCrop
I got after cropping is Object {x: 0, y: 0, width: 1600, height: 1602}
. Width and height are not consist with the aspect
I set.
I checked the ReactCrop source code, seems pixelCrop
is calculated from percentage values width
and height
, and the width
and height
are wrong as well.
I had to add the code below to make sure the cropping have correct size.
handleOnChange(crop) {
const { aspect, width, height } = crop;
const newCrop = { ...crop };
// ReactCrop is producing wrong ratio, fix the percentage according to aspect
if (aspect) {
// Adjust the smaller one to make sure we have enough size
const { imageWidth, imageHeight } = this.state;
if (width < height) {
const newWidth = height * imageHeight * aspect / imageWidth;
newCrop.width = newWidth > 100 ? 100 : newWidth;
} else {
const newHeight = width * imageWidth / aspect / imageHeight;
newCrop.height = newHeight > 100 ? 100 : newHeight;
}
}
this.setState({ crop: newCrop });
}
This is an awesome tool. It works really well. However, I am experiencing an issue where when the image is uploaded and the crop selection default is put on top of it, the boundaries of the selection and the highlight do not match up. I also noticed that when you shift the selection vertically, the top attribute changes but it doesn't match the crop selection. This mismatching looks wonky.
crop: {height: 50, width: 50} is what I am setting, although I have tried using aspect and other combinations of the crop props as well.
^^ shows the first issue
^^shows the second issue (top not updating correctly with dotted selection)
@dominictobias any guidance would be appreciated. Thanks for making this lib.
Hi,
the use of crossorigin=anonymous is not a good default for our use case, as we require credentials to retrieve the images.
Thanks
Hi,
Sometimes(i can't reproduce it though) i get a CORS exception while loading the image in the canvas, as result the image is rendered(with the crop) in a very small square area.
All the images i use are loaded from a S3 bucket(i already added the CORS configuration to it).
Am i the only one who is having this issue?
Seems to be an issue with the use of clip-path: url(#clipping);
Might be missing svg elements to make this visible.
My use-case may not be normally covered by react-image-crop, but it seems like a normal workflow. I want to create a crop widget and occasionally update the crop parameters based on saved data on a server. This means I need to set the crop
property once, then some time later set it to something else. It appears that the internal crop
state is overriding the property at:
36 getInitialState(props = this.props) {
37 const crop = assign({}, this.defaultCrop, props.crop, this.state ? this.state.crop : {});
38
39 this.cropInvalid = (!crop.width || !crop.height);
40
41 return {
42 crop: crop
43 };
44 },
This means that after initially setting crop
via props it can't be set again making my use-case not work.
I've created an updated version of the plugin that does not keep crop
in internal state. Everything I tested seems to work, but I didn't read all of the code to understand what, if any, feature I might have ruined. I wanted to open this ticket to start a conversation on the topic to see if a PR would be useful or not.
Issue doesn't seem to depend on crop parameters.
I'm on 51.0.2704.103
I can limit the container div to max-width but no to max-height.
For example if my crop container has to be 300px * 300px, I want to be able to fit the image by its ratio.
How can I manage this?
Hello, I was having a look at this component and I was wondering if it would be possible to fix the size of the crop but allowing the user to position the crop anywhere on the image ? The minHeight
and minWidth
property allow us to do this in part but the user would still be able to increase the crop.
Will it be possible to achieve this in the current state of the component or would it need additional max height and Width props ?
I set image url and show ReactCrop component. If user don't change anything and confirm, this.crop
will have 0 values, so backend will receive this wrong values.
onImageLoaded = (crop, img, pixelCrop) => {
console.log('onImageLoaded', pixelCrop); // returns Object {x: 0, y: 0, width: 0, height: 0}
this.crop = pixelCrop;
}
<ReactCrop
src={this.props.user.avatarForCrop}
crop={this.state.crop}
onImageLoaded={this.onImageLoaded}
onComplete={this.onCropComplete}
minWidth={this.state.crop.width}
keepSelection
/>
Jut tested image cropping in firefox 44, but it doesn't seem to show that dark/opaque overlay to show where image will be cropped.
Wondering if you think it would be suitable to add an option to disable resetting your crop by dragging on an unselected area of the image. Illustrative gif of what I'm talking about:
A couple reasons I would like to disable this:
Glancing through the source, it looks like it would be as simple as adding a conditional here based on a prop: https://github.com/DominicTobias/react-image-crop/blob/master/lib/ReactCrop.jsx. I'd be happy to make that PR if you agree with this.
Thanks for your consideration!
Hi,
Got the cropping tool working and was able to style it to my needs, but I can't seem to be able and figure out how to grab those % values you set on a div i.e. top, left, width and height and keep them inside the state every time crop is performed. I assume through onChange(crop), but I wanted to ask you if it is possible to see a snippet showing its correct implementation.
Hey there,
I noticed (running in chromium on ubuntu) that the 2 ReactCrop instances on my page are eating up around 20% of each of my 4 cpus.
Digging deeper I finally found out that it's the css-animation (marching ants) on the .ReactCrop--crop-selection element that is causing my machine to sweat.
I'm not sure if its an issue with my particular setup or a general issue. Disabling the animation is making fixing the problem for me. I can live without the animation, but am curious to any input on why such a simple animation is using up so much resources.
Thank you for your work, and best wishes,
Andreas
In our application, we allow the user to set an aspect ratio. When we re-render the ImageCrop with the new aspect, the cropped area changes to match the new aspect ratio, but neither the onComplete
or onChange
callbacks fire (which is fair enough)
At the moment we can access the new crop using a reference to the component via this._imageCropper.state.crop
in the aspect
setState callback, but it'd be much nicer and less hacky if we had a onAspectRatioChanged
or similar callback for when the crop changes due to a new aspect ratio making it invalid, or other prop changes.
We're updating the aspect ratio by doing a this.setState({ aspect: newAspect })
in our component, and passing it down into ReactCrop like this:
<ReactCrop
ref={ elem => { this._imageCropper = elem } }
src={ src }
crop={ {
...(meta && meta.crop),
aspect,
} }
onChange={ (crop, pixelCrop) => {
this.setState({ meta: { crop, pixelCrop } })
} }
onComplete={ (crop, pixelCrop) => {
this.setState({ meta: { crop, pixelCrop } })
} }
/>
Hey @dominictobias,
Sorry to raise an issue but couldn't find another way to submit an idea.
I was wondering if the library should be triggering an event (onLoaded/onComplete) when the image is loaded. The reason when I'm asking is that if the aspect property is passed in, essentially the crop state will change, but it's not reported back to the parent component.
By now I'm avoiding this by doing the calculations myself and triggering the preview component, but it feels wrong since react-image-crop is doing the calculations.
Let me know thoughts
When I pass onChange prop, then I don't see selected area while moving cursor. And when I pass onComplete prop, then selected area disappears when I end selection.
In my app I'm getting an issue when selecting large images, where the crop doesn't match the highlight:
I have set:
.ReactCrop--image {
max-width: 100%;
}
...and have tried all sorts of combinations for crop params. Also, how do I go about selecting the default selected crop to be either 100% of width (if portrait) or 100% of height (if landscape) and keeping the aspect ratio 1/1 (square)?
My fix, hopefully temporary:
/*
Fix for webkit not re-rendering svg mask
*/
componentDidUpdate(){
var sel = this.imageCopyRef;
sel.style.display='none';
sel.offsetHeight; // no need to store this anywhere, the reference is enough
sel.style.display='block';
}
This is not a huge problem in my case, but it's bugging me =)
When an aspect ratio is set (for example 16/9), the width will not go up to 100% when you maximize the crop area. Instead I get values like 99.999999999... I'm guessing the height has a higher priority in the aspect-ratio-check or something?
Hi. Thanks for this repo.
I would like to use reac-image-crop for setting cover image. That means i need fixed crop size in pixel, let's say 500 x 300 px. So, i don't need ability to change crop width or height. User should only have ability to drag pre-defined crop area to capture certain part of image.
How can i achive this? i know there is maxWidth prop, but it use percentage and hence it doesn't allow me to get immutable 500 x 300 crop zone.
Is there any other solution for my case? Thanks!
I tried to create a toggle button of crop mode.
When I select an area and click outside on the toggle button I disable the crop, but the selection is still active. Is there anyway to workaround this?
Hi, I was trying your awesome component and all seems to work great except the minWidth
and minHeight
options. Looking at the code I see in ReactCrop.jsx at line 476:
clamp(num, min, max) {
return Math.min(Math.max(num, min), max);
}
used at line 171 with minWidth
option:
newWidth = this.clamp(newWidth, this.props.minWidth || 0, maxWidth);
and at 196 with minHeight
:
newHeight = this.clamp(newHeight, this.props.minHeight || 0, maxHeight);
Below, at 245 and 246:
crop.x = this.clamp(newX, 0, 100 - newSize.width);
crop.y = this.clamp(newY, 0, 100 - newSize.height);
It seems to be calculating the cropping area without taking into account the minWidth
and minHeight
. All next clamp
executions also define the min
values as 0.
I've tried to change those min
parameters with this.props.minWidth || 0
, but then I get a weird behaviour (width becomes fixed). Any workaround?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.