首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >反映图像裁剪显示错误,因为它不是以适当的形式上传图像,而是从后端获取错误。

反映图像裁剪显示错误,因为它不是以适当的形式上传图像,而是从后端获取错误。
EN

Stack Overflow用户
提问于 2020-11-06 11:05:22
回答 1查看 1.9K关注 0票数 4

我得到一个错误,当上传一个裁剪的图像使用react-image-crop。我认为,在上传之前,我没有正确地将base64转换为文件类型,或者该函数没有运行?我的反应和javascript是新的,所以很多事情,仍然让我困惑。有人能看一下代码并帮助解决这个问题吗?

我正在使用django rest。

这是到包的链接:

代码语言:javascript
复制
https://github.com/DominicTobias/react-image-crop

这是我在上传时从后端得到的错误。

代码语言:javascript
复制
{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."]

这是密码。

代码语言:javascript
复制
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>
  );

}

谢谢

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-11-08 19:26:00

在这段代码中不需要使用useEffect和useCallback。ReactCrop给了你onComplete,所以你唯一需要做的就是在那之后开始画画。

api错误:

在上面的代码中,您将向api发送base64字符串,但正如我们在错误api中所看到的,除了文件格式之外。此外,将名称设置为blob也是识别为文件的必要条件。

我收集这些更改,这段代码应该可以工作:

代码语言:javascript
复制
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>
  );

}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64713428

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档