gpt4 book ai didi

javascript - React Image-crop 显示错误,因为它没有以正确的形式上传图像并且从后端收到错误

转载 作者:行者123 更新时间:2023-12-03 07:09:59 26 4
gpt4 key购买 nike

使用 react-image-crop 上传裁剪后的图像时出错.我想,我在上传之前没有正确地将 base64 转换为文件类型,或者该功能没有运行?。我是 React 和 javascript 的新手,所以很多事情仍然让我感到困惑。任何人都可以查看代码并帮助解决问题吗?
我正在使用 django rest api。
这是包的链接:

https://github.com/DominicTobias/react-image-crop
这是我在上传时从后端收到的错误。
{profile_pic: ["The submitted data was not a file. Check the encoding type on the form."]}
profile_pic: ["The submitted data was not a file. Check the encoding type on the form."]
这是代码。
function getResizedCanvas(canvas, newWidth, newHeight) {
const tmpCanvas = document.createElement("canvas");
tmpCanvas.width = newWidth;
tmpCanvas.height = newHeight;

const ctx = tmpCanvas.getContext("2d");
ctx.drawImage(
canvas,
0,
0,
canvas.width,
canvas.height,
0,
0,
newWidth,
newHeight
);

return tmpCanvas;
}


export default function ProfilePicEdit() {

const [{user}, dispatch] = useStateValue()

const { register, handleSubmit } = useForm();

const [upImg, setUpImg] = useState();
// const [image, setImage] = useState(null);
const imgRef = useRef(null);
const previewCanvasRef = useRef(null);
const [crop, setCrop] = useState({ unit: "%", width: 30, aspect: 1 / 1 });
const [completedCrop, setCompletedCrop] = useState(null);

const classes = useStyles();

const onSelectFile = (e) => {
if (e.target.files && e.target.files.length > 0) {
const reader = new FileReader();
reader.addEventListener("load", () => setUpImg(reader.result));
reader.readAsDataURL(e.target.files[0]);
// setImage(
// {image: e.target.files[0]}
// )
}
};

const onLoad = useCallback((img) => {
imgRef.current = img;
}, []);

useEffect(() => {
if (!completedCrop || !previewCanvasRef.current || !imgRef.current) {
return;
}

const image = imgRef.current;
const canvas = previewCanvasRef.current;
const crop = completedCrop;

const scaleX = image.naturalWidth / image.width;
const scaleY = image.naturalHeight / image.height;
const ctx = canvas.getContext("2d");

canvas.width = crop.width * pixelRatio;
canvas.height = crop.height * pixelRatio;

ctx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
ctx.imageSmoothingQuality = "high";

ctx.drawImage(
image,
crop.x * scaleX,
crop.y * scaleY,
crop.width * scaleX,
crop.height * scaleY,
0,
0,
crop.width,
crop.height
);

const reader = new FileReader()
canvas.toBlob(blob => {
reader.readAsDataURL(blob)
reader.onloadend = () => {
dataURLtoFile(reader.result, `sample.jpg`)
}
})

const dataURLtoFile = (dataurl, filename) => {
let arr = dataurl.split(','),
mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]),
n = bstr.length,
u8arr = new Uint8Array(n);

while(n--){
u8arr[n] = bstr.charCodeAt(n);
}
let croppedImage = new File([u8arr], filename, {type:mime});
setUpImg({upImg: croppedImage })
}

}, [completedCrop]);


const onSubmit = () => {
let formData = new FormData();

// console.log(upImg)
formData.append('profile_pic', upImg);

axiosInstance.put('api/profile/update/', formData)
// window.location.reload();
}


return (
<div className="imagecropper">
<form className={classes.form} noValidate onSubmit={handleSubmit(onSubmit)}>
<Grid item xs={6}>
<label htmlFor="profile-pic">
<input
accept="image/*"
className={classes.input}
id="profile-pic"
onChange={onSelectFile}
name="image"
type="file"
ref={register}
/> {console.log(upImg)}
<div className="profile_pic__edit_main">
{upImg === undefined ?
<Avatar src={user && user.profile_pic} alt={user && user.username}
className="profile__pic_edit"
/>
: <Avatar src={upImg} className="profile__pic_edit" alt="" />
}
<div className="profile_pic__edit_icon">
<IconButton color="primary" component="span">
<PhotoCamera fontSize="large" />
</IconButton>
</div>
</div>
</label>
</Grid>
<ReactCrop
src={upImg}
onImageLoaded={onLoad}
crop={crop}
onChange={(c) => setCrop(c)}
onComplete={(c) => setCompletedCrop(c)}
/>
{/* <div>
<canvas
ref={previewCanvasRef}
// Rounding is important so the canvas width and height matches/is a multiple for sharpness.
style={{
width: Math.round(completedCrop?.width ?? 0),
height: Math.round(completedCrop?.height ?? 0)
}}
/>
</div> */}

<Button
type="submit"
fullWidth
variant="contained"
color="primary"
className={classes.submit}
>
Update
</Button>
</form>
</div>
);

}
谢谢

最佳答案

没有必要使用 useEffect 和 useCallback 在这段代码中。
ReactCrop 为您提供 onComplete,因此您唯一需要做的就是在那之后开始绘图。
api错误:
在上面的代码中,您正在向 api 发送 base64 字符串,但正如我们在错误 api 中看到的,除了 文件格式 .
还有将名称设置为 blob 必须识别为文件。
我收集了这些更改,此代码应该可以正常工作:

export default function ProfilePicEdit() {
const [upImg, setUpImg] = useState();
const imgRef = useRef(null);
const canvasRef = useRef(null);
const [crop, setCrop] = useState({ unit: "%", width: 30, aspect: 1 / 1 });
const croppedImage = useRef(null);

const onSelectFile = (e) => {
if (e.target.files && e.target.files.length > 0) {
const reader = new FileReader();
reader.addEventListener("load", () => setUpImg(reader.result));
reader.readAsDataURL(e.target.files[0]);
}
};

const onLoad = (img) => {
imgRef.current = img;
};

const onCropComplete = (crop) => {
makeClientCrop(crop);
};

const makeClientCrop = async (crop) => {
if (imgRef.current && crop.width && crop.height) {
croppedImage.current = await getCroppedImg(
imgRef.current,
crop,
"newFile.jpeg"
);
}
};

const getCroppedImg = (image, crop, fileName) => {
if (!canvasRef.current || !imgRef.current) {
return;
}
const canvas = canvasRef.current;
const scaleX = image.naturalWidth / image.width;
const scaleY = image.naturalHeight / image.height;
const ctx = canvas.getContext("2d");

canvas.width = crop.width * pixelRatio;
canvas.height = crop.height * pixelRatio;

ctx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
ctx.imageSmoothingQuality = "high";
ctx.drawImage(
image,
crop.x * scaleX,
crop.y * scaleY,
crop.width * scaleX,
crop.height * scaleY,
0,
0,
crop.width,
crop.height
);

return new Promise((resolve, reject) => {
canvas.toBlob((blob) => {
if (!blob) {
//reject(new Error('Canvas is empty'));
console.error("Canvas is empty");
return;
}
blob.name = fileName;
resolve(blob);
}, "image/jpeg");
});
};

const onSubmit = (e) => {
let formData = new FormData();
formData.append("profile_pic", croppedImage.current,
croppedImage.current.name);

axiosInstance.put('api/profile/update/', formData)
window.location.reload();
};

return (
<div className="imagecropper">
<form className={classes.form} noValidate onSubmit={handleSubmit(onSubmit)}>
<div>
<label htmlFor="profile-pic">
<input
accept="image/*"
id="profile-pic"
onChange={onSelectFile}
name="image"
type="file"
/>
<div className="profile_pic__edit_main">
<img
style={{ width: 40, height: 40 }}
src={upImg}
className="profile__pic_edit"
alt=""
/>
</div>
</label>
</div>
<ReactCrop
src={upImg}
onImageLoaded={onLoad}
crop={crop}
onChange={(c) => setCrop(c)}
onComplete={onCropComplete}
/>
<div>
<canvas
ref={canvasRef}
/>
</div>
<Button
type="submit"
fullWidth
variant="contained"
color="primary"
className={classes.submit}
>
Update
</Button>
</form>
</div>
);

}

关于javascript - React Image-crop 显示错误,因为它没有以正确的形式上传图像并且从后端收到错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64713428/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com