在 React 中裁剪和调整图像大小

2025-06-07

在 React 中裁剪和调整图像大小

在我的上一篇文章中,我谈到了如何应对图片堵塞 Firebase 数据库/存储空间的问题。其中一个有助于减小文件大小的方法是允许用户裁剪图片,然后在上传到 Firebase 存储空间之前调整大小。以下是我使用 react-easy-crop 库设置基本图片裁剪的方法。

安装 react-easy-crop

使用 npm:

npm install react-easy-crop --save
Enter fullscreen mode Exit fullscreen mode

或使用纱线:

yarn add react-easy-crop
Enter fullscreen mode Exit fullscreen mode

设置 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
Enter fullscreen mode Exit fullscreen mode

设置一个接受图像文件的组件

裁剪器接受图片 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
Enter fullscreen mode Exit fullscreen mode

设置裁剪并保存图像的功能

为了仅保存图像的“裁剪”部分,我们创建一个画布,并使用.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')
    })
}
Enter fullscreen mode Exit fullscreen mode

这应该会给你一个可用的图片裁剪工具!当用户上传图片时,裁剪工具就会出现。然后,用户可以拖动裁剪区域并放大/缩小图片内容。点击提交后,最终裁剪后的图片会被上传(我这里是上传到 Firebase 存储),并调整大小以减小文件大小。

经过一些造型后,我的外观如下:

图像裁剪工具运行过程中的屏幕截图。

谢谢阅读!😊

文章来源:https://dev.to/sharong/cropping-and-resizing-images-in-react-360a
PREV
作为开源新手,如何做出你的第一个贡献
NEXT
Python中的垃圾收集