How to upload photos just taken with the cordova camera plugin



  • Hello
    I am trying to upload a picture that I just take with the Cordova camera plugin.
    this plugin has two option, passing either the path to the picture or the encoded image through the onSuccess callback. Of course, passing the encoded image is very expensive, so I chose passing it as a path.
    but how can I upload the image using only the path?? I can’t create or even open the image in order to have access to the image bytes.
    Additionally, I created an Uploader component which just wrapped the QUploader component and I am able to upload pictures with it.
    but What I want is upload the picture I just take directly during the onSuccess camera’s callback.

    for example:

    <template>
      <div class="row justify-center items-center">
        <q-btn icon="add_a_photo" size="sm" color="primary" round @click="captureImage" />
      </div>
    </template>
    
    <script>
    export default {
      name: 'Camera',
      data () {
        return {
          imageSrc: '',
          opts: undefined
        }
      },
    
      methods: {
        defaultCameraOptions () {
          var opts = {
              quality: 80,
              destinationType: Camera.DestinationType.FILE_URI,
              sourceType: Camera.PictureSourceType.CAMERA,
              mediaType: Camera.MediaType.PICTURE,
              encodingType: Camera.EncodingType.JPEG,
              cameraDirection: Camera.Direction.BACK,
              allowEdit: true,
              correctOrientation: true,  //Corrects Android orientation quirks
              targetWidth: 300,
              targetHeight: 400
          }
          return opts
        },
    
        captureImage (file) {
          if(this.opts === undefined){
            this.opts = this.defaultCameraOptions()
          }
          navigator.camera.getPicture(this.cameraOnSuccess, this.cameraOnError, this.opts)
        },
    
        cameraOnSuccess (imageUrl) {
          this.$store.dispatch('camera/newImage', imageUrl)
          console.log('path ' + imageUrl)
          // Notify to the parent or any listener that there is a new picture
          this.emitEvent(imageUrl)
        },
    
        emitEvent (url) {
          console.log('emitting new picture event')
          this.$emit('newpicture', url)
        },
    
        cameraOnError (msg) {
          console.log('error trying to access the camera ' + msg)
        }
      }
    }
    </script>
    

    above, my camera component which would emit an event once the picture has been taken successfully, the parent layout would be connect to that event like this:

    <camera ref="cameraRef" @newpicture="processPicture"></camera>
    

    the processPicture(path) will receive the path to where the picture was saved.
    and it is where I want to implement the uploading procedure directly, without having to open my QUploader component and select that picture.
    so that, my processPicture method could be something like(it is not working, because the server is receiving an string)

         processPicture (path) {
              console.log('path ' + path)
              // path file:///storage/emulated/0/Android/data/myApp.app/cache/1566412024593.jpg
              var endpoint = 'myEndpoint....'
              // Fills the form data to be uploaded to the server with the picture
              const fd = new FormData() // I know, It won't work
              fd.append('file', path)
              axiosInstance.defaults.headers.common['authorization'] = 'Bearer ' + localStorage.getItem('token')
              axiosInstance.post(settingsInstance[0].baseAPIURL + endpoint, fd, 
              {
                headers: { 'Content-Type': 'multipart/form-data' }
              })
              .then(res => {
                console.log('photo uploading done !')
              }).catch((err) => alert(err) )
            }
    

    Does anybody have some ideas? What might be the best approach?

    Thanks !!



  • @neithanmo you need this step to get afileEntry of the image file https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-camera/#take-a-picture-and-get-a-fileentry-object, then use that fileEntry object to get the actual File object. ie.

    ...   
        getFileEntry (fileURL) {
          return new Promise((resolve, reject) => {
            window.resolveLocalFileSystemURL(
              fileURL,
              fileEntry => {
                resolve(fileEntry)
              },
              err => {
                reject(err)
              }
            )
          })
        }, 
        readFile (fileEntry) {
          return new Promise((resolve, reject) => {
            fileEntry.file(
              file => {
                let reader = new FileReader()
                reader.readAsArrayBuffer(file)
                reader.onload = () => resolve(reader.result)
                reader.onerror = error => reject(error)
              },
              err => {
                reject(err)
              }
            )
          })
        },
    ...
    // your upload method
       processPicture async (path) {
              // path file:///storage/emulated/0/Android/data/myApp.app/cache/1566412024593.jpg          
             // get file entry
              const imgFileEntry = await this.getFileEntry(path)
              // get the File object  
              const imgFile = await this.readFile(imgFileEntry)
              var endpoint = 'myEndpoint....'
              // Fills the form data to be uploaded to the server with the picture
              const fd = new FormData() // I know, It won't work
              fd.append('file', imgFile)
              axiosInstance.defaults.headers.common['authorization'] = 'Bearer ' + localStorage.getItem('token')
              await axiosInstance.post(settingsInstance[0].baseAPIURL + endpoint, fd, 
              {
                headers: { 'Content-Type': 'multipart/form-data' }
              })
              .then(res => {
                console.log('photo uploading done !')
              }).catch((err) => alert(err) )
            }
    


  • Hello, please help
    file with key media is sending as [object Object], not as (binary)
    so at backend $_FILES are empty

    		captureImage(source) {
    
    			source = source || 1;
    
    			let cameraConfig = {
    				quality: 50,
    				sourceType: source,
    				destinationType: navigator.camera.DestinationType.FILE_URI,
    				encodingType: navigator.camera.EncodingType.JPEG,
    				mediaType: navigator.camera.MediaType.PICTURE,
    				cameraDirection: navigator.camera.Direction.BACK
    			};
    
    			navigator.camera.getPicture(
    				data => { this.processPicture(data) },
    				error => { this.$q.notify(error) },
    				cameraConfig
    			)
    
    		},
    
    		getFileEntry (fileURL) {
    			return new Promise((resolve, reject) => {
    				window.resolveLocalFileSystemURL(
    					fileURL,
    					fileEntry => {
    						resolve(fileEntry)
    					},
    					err => {
    						reject(err)
    					}
    				)
    			})
    		},
    
    		async getFile(fileEntry) {
    			try {
    				return await new Promise((resolve, reject) => fileEntry.file(resolve, reject));
    			} catch (err) {
    				console.log(err);
    			}
    		},
    
    		async processPicture (path) {
    			const fileEntry = await this.getFileEntry(path);
    			const file = await this.getFile(fileEntry);
    			this.upload(file)
    		},
    
    		upload(file) {
    			let data = new FormData(),
    				headers = { 'Content-Type': 'multipart/form-data' };
    			data.append('media', file);
    			this.$axios.post(this.sendRoute, data, { headers: headers })
    		},


  • @matroskin same issue , do you solved it?



  • Sir, I tried this using Cordova media capture and Axios to send an image to API which is working perfectly on postman

    data () {
        return {
          id: [],
          program: [],
          imagecapture : [],
          get_photos:[],
          pos:[],
        }
      },
    
    takepicture:  function (){
            
           navigator.device.capture.captureImage((mediaFiles)=>{
             this.imagecapture = mediaFiles;
            this.processPicture();
           });
    
        },
    async processPicture(){
    
          console.log(this.imagecapture[0]);
              var file = this.imagecapture[0];
              console.log(typeof file);
              
    
             var filePath = file.fullPath;
             var fileName = file.name;
             console.log(typeof fileName)
             console.log(typeof filePath)
             
             const imgFileEntry = await this.getFileEntry(filePath)
              // get the File object  
              const imgFile = await this.readFile(imgFileEntry)
              console.log(typeof imgFile);
    
             let form = new FormData();
                   form.append('photos',imgFile);
                  console.log(form);
    
                   var id = this.id;
                   //alert(id);
                   var tokentemp = localStorage.getItem("apitoken");
                  var finaltoken = tokentemp.replace('__q_strn|','');
                  alert(finaltoken);
                  console.log(finaltoken);
    
                  const headers = {
                        'content-type': 'multipart/form-data',
                        'Accept': 'application/json',
                        'Authorization': 'Bearer '+finaltoken,
                  
                  };
                  //alert(headers);
                  console.log(headers);
                
                   this.$axios.post(this.$baseURL+"addPhoto/"+id,form,{headers:headers}).then((response)  =>  {                   
                      console.log(response);
                    })
                    .catch((error)=>{
                      alert(error)
                      console.log(error)
                    });
    
        },
    
        
    
    getFileEntry (fileURL) {
          return new Promise((resolve, reject) => {
            window.resolveLocalFileSystemURL(
              fileURL,
              fileEntry => {
                resolve(fileEntry)
              },
              err => {
                reject(err)
              }
            )
          })
        }, 
        readFile (fileEntry) {
          return new Promise((resolve, reject) => {
            fileEntry.file(
              file => {
                let reader = new FileReader()
                reader.readAsArrayBuffer(file)
                reader.onload = () => resolve(reader.result)
                reader.onerror = error => reject(error)
              },
              err => {
                reject(err)
              }
            )
          })
        },
    

    but getting an array as this 500 internal server as it a Laravel server (Call to a member function getClientOriginalName() on null) due to proper blob not passed

    my postman request as javascript

    var form = new FormData();
    form.append("photos", "home/Pictures/testimage uploads/8.jpg");
    
    var settings = {
      "async": true,
      "crossDomain": true,
      "url": "https://sampleapi.com/api/v1/addPhoto/2",
      "method": "POST",
      "headers": {
        "Accept": "application/json",
        "Authorization": "Bearer eyJ.....",
        "cache-control": "no-cache",
        "Postman-Token": "6...."
      },
      "processData": false,
      "contentType": false,
      "mimeType": "multipart/form-data",
      "data": form
    }
    
    $.ajax(settings).done(function (response) {
      console.log(response);
    });
    

    I would appreciate if anyone can help me😄


Log in to reply