使用react-cropper结合图片压缩方法对图片进行裁剪压缩处理

本文介绍了如何在React项目中使用react-cropper组件实现图片裁剪,并结合antd的Modal组件创建裁剪弹窗。通过压缩函数compressImage对裁剪后的图片进行压缩,确保图片大小满足需求。整个过程涵盖了图片上传、裁剪、预览和压缩等功能,实现了自定义裁剪并优化图片质量。
摘要由CSDN通过智能技术生成

最近项目要使用图片裁剪上传,因为项目采用的是react+antd,所以第一时间想到的是ImgCrop插件,但是这不满足项目需求,项目要求的是能够缩放裁剪框,最后确定了采用react-cropper来实现图片的自定义裁剪
安装react-cropper
npm install --save react-cropper
新建一个CropperModal.jsx

import React, { useState, useEffect, useCallback, useRef } from 'react'
import PropTypes from 'prop-types'
import Cropper from 'react-cropper' // 引入Cropper
import 'cropperjs/dist/cropper.css' // 引入Cropper对应的css
import { Modal } from 'antd'

function CropperModal({ uploadedImageFile, onClose, onSubmit, cropperModalVisible }) {
    const [src, setSrc] = useState(uploadedImageFile)
    const cropperRef = useRef(null)
    const [cropperSrc, setCropperSrc] = useState(uploadedImageFile)

    // 裁剪
    function onCrop() {
        setCropperSrc(this.cropper.getCroppedCanvas().toDataURL())

    }
    // 确定回传裁剪图片
    function handleSubmit() {
        onSubmit(cropperSrc)
    }
    return (
        <Modal
            visible={cropperModalVisible}
            onCancel={onClose}
            onOk={handleSubmit}
            maskClosable={false}
        >
            <div className={styles['cropper-container']}>
                <Cropper
                    src={src}
                    className="cropper"
                    ref={cropperRef}
                    viewMode={1}
                    // initialAspectRatio={3}
                    zoomable={true} // 是否缩放
                    guides={false}
                    cropend={onCrop} // 裁剪完成触发
                // preview=".cropper-preview"  // 预览框
                />
            </div>
        </Modal>
    )
}

CropperModal.propTypes = {
    uploadedImageFile: PropTypes.string.isRequired,
    onClose: PropTypes.func.isRequired,
    onSubmit: PropTypes.func.isRequired
}

export default CropperModal

上面代码会将裁剪图片的base64编码回传给父组件
在父组件中


import React, { useState, useEffect, useRef } from 'react';
import { Button, Modal, Input, Upload, message, Select, } from 'antd';
import './index.less';
import CropperModal from '@/components/CropperModal'
import { compressImage} from '@/utils/utils'

const ToolsModal = props => {
	const { dispatch, userInfo } = props;
    const [imgUrl, setImgUrl] = useState('')
    const toolModal = useRef(null);
    // 裁剪图片
    const [cropperSrc, setCropperSrc] = useState('')
    // 裁剪框
    const [cropperModalVisible, setCropperModalVisible] = useState(false)

    function getBase64(img, callback) {
        const reader = new FileReader();
        reader.addEventListener('load', () => callback(reader.result));
        reader.readAsDataURL(img);
    }
    function beforeUpload(file) {
        const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png' || file.type === 'image/x-icon';
        if (!isJpgOrPng) {
            message.error('只支持上传JPG或PNG文件!');
        }
        const isLt2M = file.size / 1024 / 1024 < 2;
        if (!isLt2M) {
            message.error('图片必须小于2M');
        }
        return isJpgOrPng && isLt2M;
    }

    // 上传logo
    const handleChange = info => {
        setShow(false)
        if (info.file.status === 'done') {
            getBase64(info.file.originFileObj, imageUrl => {
                setCropperSrc(imageUrl)
                setCropperModalVisible(true)
                // setImgUrl(imageUrl)
            });
        }
    };

    // 关闭裁剪modal
    function closeCropperModal() {
        setCropperModalVisible(false)
    }

    // 裁剪回调
    function submitCropperModal(imgUrl) {
        // console.log(imgUrl.length)
        setCropperModalVisible(false)
        // 压缩函数
        compressImage(imgUrl, 200, useImg)
    }

    // 压缩回调+
    function useImg(base64) {
        setImgUrl(base64)
    }
    return (
        <Modal>
            <div className='tool-content' ref={toolModal}>
                <div className='tool-logo'>
                    <div className='name'>工具logo</div>
                    <div className='content' style={{ position: 'relative', height: 150 }}>
                        <div className='logo'>
                            <div className='logo-preview'>
                                <img src={objVal.icon ? objVal.icon : clue} alt="" />
                                <Button
                                    className='logo-edit'
                                    onClick={showIconList}
                                    icon={<EditOutlined />}></Button>
                            </div>  
                        </div>
                        <Upload
                            method='get'
                            className='btn'
                            name='file'
                            listType='picture'
                            accept={'image/*'}
                            beforeUpload={beforeUpload}
                            onChange={handleChange}
                            showUploadList={false}
                        >
                            <Button>自定义logo上传</Button>
                        </Upload>
                    </div>
                </div>
              </div>

            {
                cropperModalVisible ?
                    <CropperModal
                        uploadedImageFile={cropperSrc}
                        onClose={closeCropperModal}
                        onSubmit={submitCropperModal}
                        cropperModalVisible={cropperModalVisible}
                    />
                    : null
            }
        </Modal>
    )
}
export default connect(({ }) => ({
}))(ToolsModal)

utils.js

//图片压缩函数
/* 
  base64: 图片base64编码
  w:默认宽度
  callback: 回调函数,及时监听压缩后的base64编码
*/
export function compressImage(base64, w, callback) {
  var newImage = new Image();
  var quality = 0.5; //压缩系数0-1之间
  newImage.src = base64;
  // newImage.setAttribute("crossOrigin", 'Anonymous');	//url为外域时需要
  var imgWidth, imgHeight;
  newImage.onload = function() {
    imgWidth = this.width;
    imgHeight = this.height;
    var canvas = document.createElement('canvas');
    var ctx = canvas.getContext('2d');

    if (Math.max(imgWidth, imgHeight) > w) {
      if (imgWidth > imgHeight) {
        canvas.width = w;
        canvas.height = (w * imgHeight) / imgWidth;
      } else {
        canvas.height = w;
        canvas.width = (w * imgWidth) / imgHeight;
      }
    } else {
      canvas.width = imgWidth;
      canvas.height = imgHeight;
      quality = 0.5;
    }
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    // 在canvas绘制前填充白色背景
    ctx.fillStyle = '#fff';
    ctx.fillRect(0, 0, canvas.width, canvas.height);

    ctx.drawImage(this, 0, 0, canvas.width, canvas.height);
    var base64 = canvas.toDataURL('image/jpeg', quality); //压缩语句
    // 如想确保图片压缩到自己想要的尺寸,如要求在50-150kb之间,请加以下语句,quality初始值根据情况自定
    // while (base64.length / 1024 > 150) {
    // 	quality -= 0.01;
    // 	base64 = canvas.toDataURL("image/jpeg", quality);
    // }
    // 防止最后一次压缩低于最低尺寸,只要quality递减合理,无需考虑
    // while (base64.length / 1024 < 50) {
    // 	quality += 0.001;
    // 	base64 = canvas.toDataURL("image/jpeg", quality);
    // }
    callback(base64); //必须通过回调函数返回,否则无法及时拿到该值
  };
}

到这里就完成了对上传图片的裁剪以及压缩

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值