使用react-cropper裁剪后图片体积变大,如何控制在2MB内?
问题:react-cropper裁剪后图片体积反而增大的修复方案
原图片大小2MB,使用react-cropper裁剪后体积反而变成6MB,需要修复该问题并确保裁剪后文件不超过2MB。以下是当前使用的组件和处理函数代码:
裁剪处理函数
const getCropData2 = () => { if (typeof cropperRef2.current?.cropper !== 'undefined') { const cropper = cropperRef2.current?.cropper; if ((cropper.getCroppedCanvas().toDataURL().length * (3/4)) / 1024 < 2048) FitnessStore.editFitnessImagesUpload({image: cropper.getCroppedCanvas().toDataURL()}); else { FitnessStore.editFitnessImagesUpload({image: null}); alert('Размер файла превышает 2 мб'); } setImage2(true); handleClose2(); } };
Cropper组件代码
<Dialog open={open2} onClose={handleClose2} aria-labelledby="alert-dialog-title" aria-describedby="alert-dialog-description" > <DialogContent> <DialogContentText id="alert-dialog-description"> {!image2 && FitnessStore.fitnessImagesUpload.image ? <> <Cropper aspectRatio={10 / 11} style={{height: 400}} preview=".img-preview" guides={true} src={FitnessStore.fitnessImagesUpload.image} ref={cropperRef2} dragMode={'move'} background={false} responsive={true} autoCropArea={1} checkOrientation={false} viewMode={1} minCropBoxHeight={10} minCropBoxWidth={10} /> </> : null} </DialogContentText> </DialogContent> <DialogActions> <Button onClick={getCropData2}>Обрезать</Button> </DialogActions> </Dialog>
问题原因
裁剪后体积变大的核心原因是:getCroppedCanvas()默认生成无压缩的PNG格式画布,即便原图片是JPG,转成PNG后体积会大幅上升;同时toDataURL()默认也使用PNG格式,进一步放大了体积问题。另外当前的体积计算是通过base64长度估算,存在误差。
修复方案
指定画布输出格式与压缩质量
调用getCroppedCanvas时传入格式和质量参数,优先使用JPG格式压缩体积:const canvas = cropper.getCroppedCanvas({ imageSmoothingQuality: 'high', // 保证裁剪画质 format: 'image/jpeg', quality: 0.8 // 初始质量,可根据需求调整 });改用Blob获取准确文件大小
把画布转成Blob对象,直接获取真实文件大小,比base64估算更准确:canvas.toBlob((blob) => { const fileSizeMB = blob.size / (1024 * 1024); if (fileSizeMB <= 2) { // 转成base64存入store const reader = new FileReader(); reader.onload = () => { FitnessStore.editFitnessImagesUpload({image: reader.result}); }; reader.readAsDataURL(blob); } else { FitnessStore.editFitnessImagesUpload({image: null}); alert('Размер файла превышает 2 мб'); } }, 'image/jpeg', 0.8);动态调整压缩质量(可选)
如果需要严格确保不超2MB,可以写一个循环逐步降低质量,直到体积符合要求:const compressCanvasToSize = (canvas, maxSizeMB, callback) => { let quality = 0.9; const step = 0.1; const tryCompress = () => { canvas.toBlob((blob) => { if (blob.size / (1024*1024) <= maxSizeMB || quality <= 0.1) { callback(blob); return; } quality -= step; tryCompress(); }, 'image/jpeg', quality); }; tryCompress(); }; // 使用示例 compressCanvasToSize(canvas, 2, (blob) => { // 处理符合大小的blob });
修改后的完整getCropData2函数
const getCropData2 = () => { if (typeof cropperRef2.current?.cropper !== 'undefined') { const cropper = cropperRef2.current?.cropper; const canvas = cropper.getCroppedCanvas({ imageSmoothingQuality: 'high', format: 'image/jpeg', quality: 0.8 }); canvas.toBlob((blob) => { const fileSizeMB = blob.size / (1024 * 1024); if (fileSizeMB <= 2) { const reader = new FileReader(); reader.onload = () => { FitnessStore.editFitnessImagesUpload({image: reader.result}); }; reader.readAsDataURL(blob); } else { FitnessStore.editFitnessImagesUpload({image: null}); alert('Размер файла превышает 2 мб'); } setImage2(true); handleClose2(); }, 'image/jpeg', 0.8); } };
内容的提问来源于stack exchange,提问作者Kanat Berkinbayev
相关产品推荐
相关产品推荐

