在 React 中裁剪和调整图像大小
在我的上一篇文章中,我谈到了如何应对图片堵塞 Firebase 数据库/存储空间的问题。其中一个有助于减小文件大小的方法是允许用户裁剪图片,然后在上传到 Firebase 存储空间之前调整大小。以下是我使用 react-easy-crop 库设置基本图片裁剪的方法。
安装 react-easy-crop
使用 npm:
npm install react-easy-crop --save
或使用纱线:
yarn add react-easy-crop
设置 ImageCropper 组件
这是我的裁剪器的基本设置。我使用它是getBlob()
为了将裁剪后的图像从这个子组件传递上去。
此设置aspect={1}
会强制将图片裁剪成正方形,但您可以根据需要更改宽高比。我把宽高比设为 1,因为我在应用中使用它来制作用户头像,而且正方形图片更容易设置样式。😊
// ImageCropper.js
import React, { useState } from 'react'
import Cropper from 'react-easy-crop'
import { getCroppedImg } from './cropImage'
const ImageCropper = ({ getBlob, inputImg }) => {
const [crop, setCrop] = useState({ x: 0, y: 0 })
const [zoom, setZoom] = useState(1)
/* onCropComplete() will occur each time the user modifies the cropped area,
which isn't ideal. A better implementation would be getting the blob
only when the user hits the submit button, but this works for now */
const onCropComplete = async (_, croppedAreaPixels) => {
const croppedImage = await getCroppedImg(
inputImg,
croppedAreaPixels
)
getBlob(croppedImage)
}
return (
/* need to have a parent with `position: relative`
to prevent cropper taking up whole page */
<div className='cropper'>
<Cropper
image={inputImg}
crop={crop}
zoom={zoom}
aspect={1}
onCropChange={setCrop}
onCropComplete={onCropComplete}
onZoomChange={setZoom}
/>
</div>
)
}
export default ImageCropper
设置一个接受图像文件的组件
裁剪器接受图片 URL 或 base64 编码。这里我允许用户上传自己的图片,然后将其转换为 base64 编码。
// ImageUpload.js
import React, { useState } from 'react'
import * as firebase from 'firebase/app'
import ImageCropper from './ImageCropper'
const ImageUpload = () => {
const [blob, setBlob] = useState(null)
const [inputImg, setInputImg] = useState('')
const getBlob = (blob) => {
// pass blob up from the ImageCropper component
setBlob(blob)
}
const onInputChange = (e) => {
// convert image file to base64 string
const file = e.target.files[0]
const reader = new FileReader()
reader.addEventListener('load', () => {
setInputImg(reader.result)
}, false)
if (file) {
reader.readAsDataURL(file)
}
}
const handleSubmitImage = (e) => {
// upload blob to firebase 'images' folder with filename 'image'
e.preventDefault()
firebase
.storage()
.ref('images')
.child('image')
.put(blob, { contentType: blob.type })
.then(() => {
// redirect user
})
}
return (
<form onSubmit={handleSubmitImage}>
<input
type='file'
accept='image/*'
onChange={onInputChange}
/>
{
inputImg && (
<ImageCropper
getBlob={getBlob}
inputImg={inputImg}
/>
)
}
<button type='submit'>Submit</button>
</form>
)
}
export default ImageUpload
设置裁剪并保存图像的功能
为了仅保存图像的“裁剪”部分,我们创建一个画布,并使用.useContext('2d')
在其上创建一个二维形状。我们使用 仅在画布上绘制图像的裁剪部分.drawImage()
,然后将画布作为 blob 返回。
将canvas.width
和设置canvas.height
为您想要存储裁剪图像的大小(以像素为单位)。对我来说,我将其设置为 250px x 250px。
// cropImage.js
// create the image with a src of the base64 string
const createImage = (url) =>
new Promise((resolve, reject) => {
const image = new Image()
image.addEventListener('load', () => resolve(image))
image.addEventListener('error', error => reject(error))
image.setAttribute('crossOrigin', 'anonymous')
image.src = url
})
export const getCroppedImg = async (imageSrc, crop) => {
const image = await createImage(imageSrc)
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
/* setting canvas width & height allows us to
resize from the original image resolution */
canvas.width = 250
canvas.height = 250
ctx.drawImage(
image,
crop.x,
crop.y,
crop.width,
crop.height,
0,
0,
canvas.width,
canvas.height
)
return new Promise((resolve) => {
canvas.toBlob((blob) => {
resolve(blob)
}, 'image/jpeg')
})
}
这应该会给你一个可用的图片裁剪工具!当用户上传图片时,裁剪工具就会出现。然后,用户可以拖动裁剪区域并放大/缩小图片内容。点击提交后,最终裁剪后的图片会被上传(我这里是上传到 Firebase 存储),并调整大小以减小文件大小。
经过一些造型后,我的外观如下:
谢谢阅读!😊
文章来源:https://dev.to/sharong/cropping-and-resizing-images-in-react-360a