Search code examples
javascriptreactjsreact-dropzone

restrict image dimension in react-dropzone


I am using react-dropzone for image upload. Everything is working fine. Validation for image size is also working fine. But I could not check the dimension for image. I want to validate the image's width and height to enforce user to upload the image in between those specified width and height. I tried image.addEventListener('load') but this is not working.

Here is what I have done

export const UploadField = ({ preview, label, uploadProps, ...props }) => {
  const {
    input: { onChange },
    disabled
  } = props;

  const {
    isDragActive,
    getRootProps,
    getInputProps,
    isDragReject,
    rejectedFiles
  } = useDropzone({
    onDrop: files => {
      onChange(
        files.map(file => {
          const image = new Image();
          image.addEventListener("load", () => {
            console.log("image", image);
          });
          return Object.assign(file, {
            preview: URL.createObjectURL(file)
          });
        })
      );
    },
    ...uploadProps
  });

  const isFileTooLarge =
    rejectedFiles.length > 0 && rejectedFiles[0].size > uploadProps.maxSize;

  const files = props.input.value;

  if (disabled) {
    return null;
  }

  return (
    <>
      {label && <Label>{label}</Label>}
      <DropzoneContainer {...getRootProps()}>
        <input {...getInputProps()} />
        {!isDragActive && "Click here or drop a file to upload!"}
        {isDragActive && !isDragReject && "Drop it like it's hot!"}
        {isDragReject && "File type not accepted, sorry!"}
        {isFileTooLarge && (
          <div className="text-danger mt-2">File is too large.</div>
        )}
      </DropzoneContainer>
      <div>
        {files && files !== undefined ? (
          <>
            <Preview files={files} isLocal />
          </>
        ) : (
          <Preview files={preview} isLocal={false} />
        )}
      </div>
    </>
  );
};

export default UploadField;

UploadField.defaultProps = {
  uploadProps: {
    accept: "image/*",
    multiple: false,
    minSize: 0,
    maxSize: 5242880
  }
};

const DropzoneContainer = styled.div`
  width: 100%;
  padding: 14px;
  border-width: 2px;
  border-radius: 2px;
  border-color: ${props => getColor(props)};
  border-style: dashed;
  background-color: #fafafa;
  color: #bdbdbd;
  outline: none;
  transition: border 0.24s ease-in-out;
`;

const getColor = props => {
  if (props.isDragAccept) {
    return "#00e676";
  }
  if (props.isDragReject) {
    return "#ff1744";
  }
  if (props.isDragActive) {
    return "#2196f3";
  }
  return "#eeeeee";
};

Solution

  • You never set the src for the image so your event handler never fires. Try setting image.src = URL.createObjectURL(file). Once the file loads, your 'load' handler will fire.

    Try changing the contents of your onDrop callback to include this:

    const filteredImages = [];
    let counter = 0;
    
    files.map(file => {
        const image = new Image();
        image.addEventListener('load', () => {
            console.log(`${image.width}x${image.height}`)
    
            // only select images within width/height limits
            if (image.width < WIDTH_LIM && image.height < HEIGHT_LIM) {
                filteredImages.push(image)
            }
    
            // increment counter for each image we go through
            counter += 1;
    
            // if we have gone through all the files, handle the ones that
            // made it through the filter using `handleImages` function
            if (counter === files.length) handleImages(filteredImages);
        });
        image.src = URL.createObjectURL(file)
    })