Why giving dynamically a src to a new Image() object sometimes give width and height 0

Viewed 37

I am working on a project where I need to edit images, I was trying to draw image into canvas but one thing I noticed is when I upload even the same image and check for width and height I sometimes get correct width and height but sometimes 0. Here is what I am doing:

Here I have an input type file and I store it in a state once the FileReader is loaded and then passing to my ImageEditor component

export default function App() {
  const [img, setImg] = useState();
  const fileUpload = (e) => {
    if (!e.target.files.length > 0) return;
    // console.log(e.target.files[0])

    const reader = new FileReader();
    reader.onload = (e) => {
      setImg(e.target.result);
    };

    reader.readAsDataURL(e.target.files[0]);
    e.target.value = "";
  };
  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
      <input type="file" onChange={fileUpload} />
      <br />
      <ImageEditor img={img} />
    </div>
  );
}

Here is my <ImageEditor/> component:

const ImageEditor = ({ img }) => {
  const canvasRef = useRef(null);

  useEffect(() => {
    if (!img || !canvasRef.current) return;

    const imgElement = new Image();
    imgElement.src = img;
    console.log(
      imgElement.naturalWidth,
      imgElement.naturalHeight,
      imgElement.width,
      imgElement.height
    );
    const ctx = canvasRef.current.getContext("2d");
    ctx.clearRect(0, 0, canvasRef.current.width, canvasRef.current.height);
    ctx.drawImage(
      imgElement,
      0,
      0,
      imgElement.naturalWidth,
      imgElement.naturalWidth,
      0,
      0,
      300,
      300
    );
  }, [img]);

  return <canvas width={300} height={300} ref={canvasRef} />;
};

This console log:

console.log(
          imgElement.naturalWidth,
          imgElement.naturalHeight,
          imgElement.width,
          imgElement.height
        );

sometimes shows 0 0 0 0 and sometimes correct values, why is this happening as I've checked the img is always there otherwise the if statement would be triggered.

Here is codesandbox demo: https://codesandbox.io/s/xenodochial-euler-m4z42?file=/src/App.js:677-1379

1 Answers

I found this to be a race condition. Try changing your code so that you respond to the imgElement onload event. This works on the sandbox. Better yet, use the useState hook to detect when the Image is actually loaded into the dom. A bandaid is:

 const imgElement = new Image();

 imgElement.onload = function () {
  console.log(
    imgElement.naturalWidth,
    imgElement.naturalHeight,
    imgElement.width,
    imgElement.height
  );
  //other code dependent on loading image
 }
 
 imgElement.src = img;
Related