I am get an error while uploading a cropped image using react-image-crop. I think, I am not properly converting the base64 to file type before uploading or that function isn't running?. I am new to react and javascript so lots of things, still confuses me. Can anyone please have a look at the code and help resolve the issue?
I am using django rest api.
This is the link to the package:
https://github.com/DominicTobias/react-image-crop
This is the error I am getting from the backend while uploading.
{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."]
This is the code.
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>
);
}
Thank you