v4.0.0
馃帀 Better rotation handling 馃帀
Thanks to an awesome work by @trurl-master, we are now handling rotation properly when computing the output image coordinate. 馃帀
in addition, the example code for generating the cropped image is now more efficient and should reduce the number of issues on iOS devices like reported in #91.
New initialCroppedAreaPercentages prop
initialCroppedAreaPercentages
is similar to initialCroppedAreaPixels
but more accurate as there is no rounding.
It minimizes the losses of save/restore operations. They're still present on some occasions as the JS floating-point operations accuracy is limited, but it allows to preserve the crop for much longer. initialCroppedAreaPixels
still can be used, but it's a bit risky.
鈿狅笍 Breaking changes 鈿狅笍
TL;DR: If you were not using the rotation
prop, there should be no breaking changes.
The croppedArea
and croppedAreaPixels
output by onCropComplete()
have changed when using the Cropper with a rotation different than 0.
Migration guide
The main impact this major version has is on the croppedAreaPixels
when used together with the rotation. As it now generates bounding box relative values, you will need to remake the part that generates the final image, taking that into account.
Here's an example implementation (codesandbox):
First, calculate the bounding box size:
const image = await createImage(...)
const rotRad = getRadianAngle(rotation)
const bBoxWidth =
Math.abs(Math.cos(rotRad) * image.width) +
Math.abs(Math.sin(rotRad) * image.height)
const bBoxHeight =
Math.abs(Math.sin(rotRad) * image.width) +
Math.abs(Math.cos(rotRad) * image.height)
Second, create a canvas element with the size of the bounding box:
const canvas = document.createElement('canvas')
canvas.width = bBoxWidth
canvas.height = bBoxHeight
Then, rotate the canvas context around the center of the canvas:
const ctx = canvas.getContext('2d')
ctx.translate(bBoxWidth / 2, bBoxHeight / 2)
ctx.rotate(rotRad)
Set context to point to the top-left corner of the rotated image:
ctx.translate(-image.width / 2, -image.height / 2)
Draw the image onto the rotated context:
ctx.drawImage(image, 0, 0)
What you have in the canvas at this point is a rotated image inside its bounding box. Now, you just need to extract the result using croppedAreaPixels
and repaint it on a canvas with the size of the final image:
const data = ctx.getImageData(
croppedAreaPixels.x,
croppedAreaPixels.y,
croppedAreaPixels.width,
croppedAreaPixels.height
)
// set the canvas size to the final image size - this will clear existing context
canvas.width = croppedAreaPixels.width
canvas.height = croppedAreaPixels.height
// paste the extracted image at the top left corner
ctx.putImageData(data, 0, 0)
croppedArea
If you somehow managed to use croppedArea
with rotation before - you're smarter than me. If not - now is the time. The approach is basically the same as with croppedAreaPixels
- you just need to convert percentages to pixels based on the image you're cropping
Here's how you can use percentages server-side and crop using sharp (codesandbox):
Rotate the image:
const image = sharp(...);
await image.rotate(rotation);
Get rotated image bounding box size (basically you need to create a new image out of the rotated one, otherwise the metadata won't change):
const meta = await sharp(await image.toBuffer()).metadata();
Alternatively, you can calculate the bounding box size using the same method we used for the client-side crop
Convert percentages to pixels:
const cropInfo = {
top: Math.round((croppedArea.y / 100) * meta.height),
left: Math.round((croppedArea.x / 100) * meta.width),
width: Math.round((croppedArea.width / 100) * meta.width),
height: Math.round((croppedArea.height / 100) * meta.height)
}
Extract the image:
const myCroppedImage = await image.extract(cropInfo)
Commits
- Change rotated crop area output by @trurl-master in https://github.com/ricardo-ch/react-easy-crop/pull/312
- Update readme video tutorials section by @CodingWith-Adam in https://github.com/ricardo-ch/react-easy-crop/pull/300
- Bump tmpl from 1.0.4 to 1.0.5 by @dependabot in https://github.com/ricardo-ch/react-easy-crop/pull/296
- Bump object-path from 0.11.7 to 0.11.8 in /docs by @dependabot in https://github.com/ricardo-ch/react-easy-crop/pull/295
New Contributors
- @CodingWith-Adam made their first contribution in https://github.com/ricardo-ch/react-easy-crop/pull/300
- @trurl-master made their first contribution in https://github.com/ricardo-ch/react-easy-crop/pull/312
Full Changelog: ricardo-ch/react-easy-crop@v3.5.3...v4.0.0