How do convert a datauri element into a file I can upload via react?

Viewed 1221

I am sending a file to an api endpoint via react webapp and for now as a mock up have been using file upload. I have since added camera capabilities as I plan for users to be able to take a picture and upload that picture. I'm using the react-html5-camera-photo which captures a datauri element. How do I convert this to a file to upload to the endpoint? Or am I approaching this incorrectly?

File Upload:

handleUploadImage=()=> {
  console.log(this.state.selectedFile)
  const data = new FormData();
  data.append('file', this.state.selectedFile);
  data.append('filename', this.state.selectedFile.name);
  fetch('http://localhost:5000/upload', {
    method: 'POST',
    body: data,
  })
    .then((response) => {
    response.json()
    .then((response) => {
      //this.setState({ imageURL: `http://localhost:5000/${body.file}` });
      console.log(response.text)
      this.setState({ text: response.text})
      this.getPlate()
    })
  });
}

Camera Code:

  startCamera = () => {
    console.log('starting camera')
    if(!this.state.cameraLoad) {
      this.setState({ cameraLoad: true, camIconData: collapse}) ;  
    } else {
      this.setState({ cameraLoad: false, camIconData: expand}) ;
    }
  } 

   onTakePhoto = (dataUri) => {
     // Do stuff with the dataUri photo...
     console.log('photo taken');
     this.setState({ camColor: 'green', dataUri : dataUri })
   }

 // will upload photo after user confirms to upload
  uploadPhoto = e => {
    console.log('uploading photo')
    console.log(this.state.dataUri)
    this.setState({ camColor: 'green', dataUri: null, cameraLoad: false });  
  };

The dataUri element looks something like:

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABQAAAALQCAYAAADPfd1WAAAgAElEQVR4XlS9h5Nk63HdmeVdV5vpmXnzDAEQBAiKwlJmIzZiQ/u/72qDWongkpREQFjRgHh2/LQp7zd+52TeavSLfjPTXXXr3s/kl3n
2 Answers

Here is the complete example. Please write a CameraComponent as below where you will find submitPhoto() function and this function is responsible for uploading image to the api.

import React, {useState} from 'react';
import Camera from 'react-html5-camera-photo';
import 'react-html5-camera-photo/build/css/index.css';
import ImagePreview from "./ImagePreview";
import axios from 'axios';

function CameraComponent(props) {
    const [dataUri, setDataUri] = useState('');
    const isFullscreen = false;
    const cameraRef = React.useRef();

    function handleTakePhoto(dataUri) {
        console.log('takePhoto');
    }

    function handleTakePhotoAnimationDone(dataUri) {
        console.log(dataUri, 'takePhoto');
        setDataUri(dataUri);
    }

    function handleCameraError(error) {
        console.log('handleCameraError', error);
    }

    function handleCameraStart(stream) {
        console.log('handleCameraStart');
    }

    function handleCameraStop() {
        console.log('handleCameraStop');
    }

    function submitPhoto() {
        const url = "http://localhost:3000/api/img";
        const request = axios.post(url, {
            method: "POST",
            headers: {
                Accept: "application/json",
                "Content-Type": "application/json"
            },
            body: JSON.stringify({
                img: dataUri
            })
        }).catch(error => {
            console.warn(error);
        });
    }

    return (
        <div>
            <button onClick={submitPhoto}>Upload</button>
            {(dataUri)
                ? <ImagePreview dataUri={dataUri}
                                isFullscreen={isFullscreen}
                /> :
                <Camera ref={cameraRef}
                        onTakePhoto={(dataUri) => {
                            handleTakePhoto(dataUri);
                        }}
                        onTakePhotoAnimationDone={(dataUri) => {
                            handleTakePhotoAnimationDone(dataUri);
                        }}
                        onCameraError={(error) => {
                            handleCameraError(error);
                        }}
                        onCameraStart={(stream) => {
                            handleCameraStart(stream);
                        }}
                        onCameraStop={() => {
                            handleCameraStop();
                        }}
                />
            }
        </div>
    );
}

export default CameraComponent;

Here is the another component ImagePreview which will preview the image

import React from 'react';
import PropTypes from 'prop-types';
import './styles/imagePreview.css';

export const ImagePreview = ({ dataUri, isFullscreen }) => {
  let classNameFullscreen = isFullscreen ? 'demo-image-preview-fullscreen' : '';

  return (
    <div className={'demo-image-preview ' + classNameFullscreen}>
      <img src={dataUri} />
    </div>
  );
};

ImagePreview.propTypes = {
  dataUri: PropTypes.string,
  isFullscreen: PropTypes.bool
};

export default ImagePreview;

use this :

function dataURLtoFile(dataurl, filename) {
  var 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);
  }

  return new File([u8arr], filename, { type: mime });
}
var convertedFile = dataURLtoFile(dataUri, `${Math.random(10)}.jpg`);
Related