我已经构建了一个 Slack 风格的头像图像上传和裁剪功能,但我无法将裁剪后的图像保存而不会损坏。原始文件上传,使用相同的端点和方法,工作得很好。它是从 Blob 手动创建的裁剪副本,总是损坏的。
步骤非常简单:
- 选择并上传图像文件
- 裁剪(react-image-crop)出现
- 选择区域,点击保存
在步骤 1 中,当文件输入发生变化时,文件被上传。文件被发送到流式端点,该端点将文件上传到 s3 存储桶。
<button type="button">Upload</button>
<input
type="file"
accept="image/*"
onChange={onFileChange}
/>
...
const onFileChange = async e => {
e.preventDefault();
let uploadedFile = e.target.files[0];
await onSave(uploadedFile);
};
UploadFile var 是从输入控件返回的 File 对象。这很好用!还没有问题。
在第 3 步中,一旦您选择了图像的一个区域,react-image-crop 就会生成一个 Blob。
const getCroppedImage = (source, config) => {
const canvas = document.createElement("canvas");
const scaleX = source.naturalWidth / source.width;
const scaleY = source.naturalHeight / source.height;
canvas.width = config.width;
canvas.height = config.height;
const ctx = canvas.getContext("2d");
ctx.drawImage(
source,
config.x * scaleX,
config.y * scaleY,
config.width * scaleX,
config.height * scaleY,
0,
0,
config.width,
config.height
);
let mimeType = mime.lookup(userProfile.image_file.split(".").at(-1));
return new Promise((resolve, reject) => {
canvas.toBlob(blob => {
if (!blob) {
reject(new Error("Canvas is empty"));
return;
}
resolve(blob); //***THIS BLOB...
}, mimeType);
});
};
这个 Blob 是有效的,因为我在保存之前在屏幕上显示了选定的区域:
const AvatarPreview = () => {
if (activeAvatar) {
return <ImageCropper imageToCrop={activeAvatar} onImageCropped={onImageCropped} />;
}
return <Icon icon="bi:person" />;
};
我将 react-image-crop 生成的 Blob 填充到 File 对象中,因为这是我的代码所期望的,就像步骤 1 一样。
const onImageCropped = croppedBlob => { //***IS PASSED IN HERE
let croppedImg = URL.createObjectURL(croppedBlob);
setActiveAvatar(croppedImg);
const reader = new FileReader();
reader.readAsDataURL(croppedBlob);
reader.addEventListener("load", () => {
let { result } = reader;
let resultMimeType = result.split(";")[0].split(":")[1];
let croppedFile = new File([result], userProfile.image_file, { type: resultMimeType }); //***NEW File object, from Blob
setCroppedAvatar(croppedFile);
}, false);
};
<button type="button" onClick={() => onSave(croppedAvatar)}>Save</button>
上面 FileReader 加载中的“结果”是 base64 图像数据:
'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/4gIoSUNDX1BST0ZJTEUAAQEAAAIYAAAAAAQwAABtbnRyUkdCIFhZWiAAAAAAAAAAAAAAAABhY3NwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAA9tYAAQAAAADTLQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlkZXNjAAAA8AAAAHRyWFlaAAABZAAAABRnWFlaAAABeAAAABRiWFlaAAABjAAAABRyVFJDAAABoAAAAChnVFJDAAABoAAAAChiVFJDAAABoAAAACh3dHB0AAAByAAAABRjcHJ0AAAB3AAAADxtbHVjAAAAAAAAAAEAAAAMZW5VUwAAAFgAAAAcAHMAUgBHAEIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA…QCMFWeFZ9u3fPsWY3hh9uVHWllbSwtGASrIOQc1t6rt0OBqG6x7aVfdY859pnIwfDDhCfpwBUyaSus4VZO+susGGM60zrB1TuEjx5Ov76FBKUgNTltIQlP4UpQghKQMAAAADHApt6lv1x1HeHrzdny9KkJbDrpHLhQhKNx91EJBJ9SSaQkLS+4HTwvalKvmQMZ/PFa8hBCRntnirYUDqVYtEWlQ8JYJSrv8vnTy6W2h5/qBYmCgqbcmtgLSMg+YUyYD4aUUqTlJ4I+td+FLethRhai0sgoUOCg+hFPBwcxjruUie1k/VDOmenKkIcS2iJCzyeAAmvF7qjqFzVWurzfHV7jJluKBJ/hBwP6VL1u+KvqlD0lL0VeLt+2rZLjmO25MyqSwNuPK7nKh8l7vlioFejqU8tx453EnIPcmrWrvW5VFf6zK0GifTWs1n6TRoUrIaDZBSeDSVUzyMTY7gBIORR/EcXwTnFEozfc0xVwOYT/2Q=='
新的 File 对象对我来说似乎是合法的:
然后我再次通过端点发送图像,并上传。它出现在存储桶中,并且文件大小看起来是合法的(不是 0KB 像断流所表明的那样。)
但是,在下载并尝试打开文件时,它已损坏。我想我在某处遗漏了一个选项......一些可以使这项工作正常进行的小调整?File 对象是否没有正确形成?如何进一步解决此问题?