1

I have a form which allows users to upload an image, crop that image (utilising vue-cropperjs wrapper component) then upload the cropped image (not the original image).

I'm unable to provide the correct format for the file in order to upload it. The file has been converted (encoded) the base64 image string to display it on the page. I now need to covert (decode) it back into a file format to upload it (as a default image upload form input would do).

The view component can be found at: https://www.npmjs.com/package/vue-cropperjs

And the following coded is based on the code from this package's example, i've just added a upload method for this example:

<template>
  <div id="app">
    <h2 style="margin: 0;">Vue CropperJS</h2>
    <form @submit.prevent>
      <input v-model="imageName" type="text" />
      <hr />
      <input
        type="file"
        name="image"
        accept="image/*"
        style="font-size: 1.2em; padding: 10px 0;"
        @change="setImage"
      />

      <br />

      <div style="width: 400px; height:300px; border: 1px solid gray; display: inline-block;">
        <vue-cropper
          ref="cropper"
          :guides="true"
          :view-mode="2"
          drag-mode="crop"
          :auto-crop-area="0.5"
          :min-container-width="250"
          :min-container-height="180"
          :background="true"
          :src="imgSrc"
          alt="Source Image"
          :img-style="{ 'width': '400px', 'height': '300px' }"
        ></vue-cropper>
      </div>

      <img
        :src="cropImg"
        style="width: 200px; height: 150px; border: 1px solid gray"
        alt="Cropped Image"
      />
      <br />
      <br />

      <div>Debug Output: {{ cropImg }}</div>

      <br />
      <br />

      <button @click="cropImage" v-if="imgSrc != ''" style="margin-right: 40px;">Crop</button>

      <br />
      <br />

      <button @click="submitForm" v-if="imgSrc != ''">Submit Form</button>
    </form>
  </div>
</template>


<script>
import VueCropper from "vue-cropperjs";
import "cropperjs/dist/cropper.css";

export default {
  components: {
    VueCropper
  },

  data() {
    return {
      imageName: "",
      imgSrc: "",
      cropImg: "",
    };
  },

  methods: {
    setImage(e) {
      const file = e.target.files[0];

      if (!file.type.includes("image/")) {
        alert("Please select an image file");
        return;
      }

      if (typeof FileReader === "function") {
        const reader = new FileReader();

        reader.onload = event => {
          this.imgSrc = event.target.result;
          // rebuild cropperjs with the updated source
          this.$refs.cropper.replace(event.target.result);
        };

        reader.readAsDataURL(file);
      } else {
        alert("Sorry, FileReader API not supported");
      }
    },

    cropImage() {
      // get image data for post processing, e.g. upload or setting image src
      this.cropImg = this.$refs.cropper.getCroppedCanvas().toDataURL();
    },

    submitForm() {
      console.log("imageName: " + this.imageName);
      console.log("cropImg: " + this.cropImg); //Output: data:image/png;base64,iVBORw0KGgoAAA (please note: i've truncated the value for this example)
      //example of an file upload to firebase storage (this could apply for different solutions)
      //I need to convert the base64 date back into a file in order to upload.
      let e = this.cropImg;


      if(e != null) {
        const file = e;
        console.log("upload file: " + file.name);
        fb.storage
          .ref("images/" + file.name)
          .put(file)
          .then(response => {
            //etc
          }
      }
    }
  }
};
</script>

I have done some research into blobs, decoding etc - but have been unable to find a solid solution.

Jake Anderson
  • 309
  • 1
  • 4
  • 18

1 Answers1

1

Ok i was able to solve this one myself - if anyone is interested i sent be base64 url to this method:

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});
}

For more info see here

Jake Anderson
  • 309
  • 1
  • 4
  • 18