Navigation

    Quasar Framework

    • Register
    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search

    How to upload photos just taken with the cordova camera plugin

    Framework
    7
    14
    1456
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • N
      neithanmo last edited by

      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 !!

      1 Reply Last reply Reply Quote 0
      • metalsadman
        metalsadman last edited by metalsadman

        @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) )
                }
        
        1 Reply Last reply Reply Quote 1
        • matroskin
          matroskin last edited by matroskin

          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 })
          		},
          1 Reply Last reply Reply Quote 0
          • S
            seaton last edited by

            @matroskin same issue , do you solved it?

            1 Reply Last reply Reply Quote 0
            • tanaychatterji
              tanaychatterji last edited by tanaychatterji

              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😄

              1 Reply Last reply Reply Quote 0
              • metalsadman
                metalsadman last edited by metalsadman

                @tanaychatterji the error is coming from your server, check there if you are really receiving a file. if it’s a blob issue, check the file, maybe you need to convert it to one. i’m using the code i sited above in production, to upload the image to aws S3, no problem with it.

                tanaychatterji 1 Reply Last reply Reply Quote 0
                • G
                  gusy last edited by

                  @matroskin @seaton same here

                  1 Reply Last reply Reply Quote 0
                  • S
                    saro199 last edited by

                    I have the same problem struggling to get a work around. It works fine using uploader. My requirement is same as @neithanmo. My server api runs on flask/python and it strictly expecting a form with enctype multipart. On submit I don’t receive any files in server side any help on this really appreciated.

                    1 Reply Last reply Reply Quote 0
                    • metalsadman
                      metalsadman last edited by

                      @saro199 check this issue https://github.com/axios/axios/issues/318#issuecomment-528789463

                      1 Reply Last reply Reply Quote 0
                      • tanaychatterji
                        tanaychatterji @metalsadman last edited by tanaychatterji

                        @metalsadman

                        sir, I solved it my self by searching more forums and so sorry for replying late and thank you for replying so fast 🙂

                        this is not from the server end but I think we have to first convert the file to base64 then to blob object then upload it to the server and it does work even with 30mb file sizes 🙂

                        tried the API with KOTLIN on android to upload image it works perfectly 🙂 so outcome server is fine

                        my code please have a look if I am doing something wrong?
                        my takepicture() function with upload to server and working fine in every scenario

                            takepicture: function (){
                                /* This is for Codepen (using UMD) to work */
                              const spinner = typeof QSpinnerGears !== 'undefined'
                                ? QSpinnerGears // Non-UMD, imported above
                                : Quasar.components.QSpinnerGears // eslint-disable-line
                              /* End of Codepen workaround */
                              
                              
                                var options = {quality: 50 };
                               navigator.device.capture.captureImage((mediaFiles,options)=>{
                                 
                                //  console.log(captureSuccess);
                                 this.imagecapture = mediaFiles;
                                  console.log(this.imagecapture[0]);
                                  var file = this.imagecapture[0];
                                  console.log(JSON.stringify(file));
                                 
                        
                                 var filePath = file.fullPath;
                                 var fileName = file.name;
                                 console.log(fileName)
                                 console.log( filePath)
                        
                                 this.$q.loading.show({
                                                spinner,
                                                spinnerColor: 'red-3',
                                                spinnerSize: 200,
                                                
                                              delay: 400 ,
                                              message: '<span class="text-h4">CONVERTING IMAGE</span><br><span class="text-h6">Please Wait</span>'
                                            })
                        
                        function getFileContentAsBase64(path,callback){
                            window.resolveLocalFileSystemURL(path, gotFile, fail);
                                    
                            function fail(e) {
                                  alert('Cannot found requested file');
                            }
                        
                            function gotFile(fileEntry) {
                                   fileEntry.file(function(file) {
                                      var reader = new FileReader();
                                      reader.onloadend = function(e) {
                                           var content = this.result;
                                           callback(content);
                                      };
                                      // The most important point, use the readAsDatURL Method from the file plugin
                                      reader.readAsDataURL(file);
                                   });
                            }
                        }
                                 getFileContentAsBase64(filePath,function(base64Image){
                          //window.open(base64Image);
                          console.log(base64Image); 
                          
                        
                        
                          // Then you'll be able to handle the myimage.png file as base64
                          var ImageURL = base64Image; 
                          var block = ImageURL.split(";");
                          var contentType = block[0].split(":")[1];
                          var realData = block[1].split(",")[1];
                          var blob = b64toBlob(realData, contentType);
                        
                        
                        function b64toBlob(b64Data, contentType, sliceSize) {
                                contentType = contentType || '';
                                sliceSize = sliceSize || 512;
                        
                                var byteCharacters = atob(b64Data);
                                var byteArrays = [];
                        
                                for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
                                    var slice = byteCharacters.slice(offset, offset + sliceSize);
                        
                                    var byteNumbers = new Array(slice.length);
                                    for (var i = 0; i < slice.length; i++) {
                                        byteNumbers[i] = slice.charCodeAt(i);
                                    }
                        
                                    var byteArray = new Uint8Array(byteNumbers);
                        
                                    byteArrays.push(byteArray);
                                }
                        
                              var blob = new Blob(byteArrays, {type: contentType});
                              return blob;
                        }
                          
                          upload(blob);
                          
                        });
                                 
                        
                                                      
                        
                        
                        //TODO: GET THE BLOB VARUIABLE OUTSIDE AVAILABE TO UPLOAD 
                        var vm = this;
                        function upload (data){
                        var blob = data;
                        console.log(blob);
                        var coordinates = vm.latitude+'/'+vm.longitude;
                        
                        console.log(vm);
                        
                                            let form = new FormData();
                                            form.append('photos',blob);
                                            form.append('filename',fileName);
                                            form.append('coordinates',coordinates);
                                            console.log(form);
                        
                                            var id = vm.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);
                                            vm.$q.loading.hide();
                                            
                                            vm.$q.dialog({
                                                    title: 'Confirm',
                                                    message: 'Would you like to Upload recently taken picture',
                                                    cancel: true,
                                                     ok: {
                                                        push: true
                                                      },
                                                      cancel: {
                                                        push: true,
                                                        color: 'negative'
                                                      },
                                                      persistent: true,
                                                  }).onOk(() => {
                                                       
                                                      LoadingBar.setDefaults({
                                                          color: 'green',
                                                          size: '15px',
                                                          position: 'bottom'
                                                        })
                                                      LoadingBar.start()
                                                      vm.$axios.post(vm.$baseURL+"addPhoto/"+id,form,{headers:headers}).then((response)  =>  {                   
                                                      console.log(response);
                                                       LoadingBar.stop()
                                                      
                        
                                                              vm.$q.dialog({
                                                                    
                                                                    title: 'Alert',
                                                                      message: 'Image uploaded'
                                                                  }).onOk(() => {
                                                                    vm.get_program_info();
                                                                  })
                        
                                                      
                                                    })
                                                    .catch((error)=>{
                                                      alert(error)
                                                      console.log(error)
                                                    });
                                                    console.log('ok pressed')
                                                  }).onCancel(() => {
                                                    vm.get_program_info();
                                                  }).onDismiss(() => {
                                                    vm.get_program_info();
                                                  })
                        
                                            
                        
                        
                        }
                        
                         
                        
                                
                        
                               });
                               
                               
                                
                            },
                                
                        

                        hope I am doing it right? and please forgive me for the references I have made in a hurry 😞
                        And Thank you sir for your guidance as i am a noob in this 🤣

                        1 Reply Last reply Reply Quote 0
                        • S
                          saro199 last edited by

                          Hi @metalsadman @tanaychatterji , It worked when I convert the file as blob. I am able to upload without any issues.
                          By the way @tanaychatterji we don’t need o convert to base64, we can directly read the file as data url and convert to blob.
                          I lost 48 hours on this. This forum helped me narrow down the issue. Appreciate your help. I love Quasar.

                          tanaychatterji 1 Reply Last reply Reply Quote 1
                          • tanaychatterji
                            tanaychatterji @saro199 last edited by

                            @saro199
                            Hi, I tried without converting it to base64 but I got error in laravel Logs API endpoint as

                            null in getClientOriginalName()
                            

                            because mediaFiles only return file URL, not an absolute one full Path, that’s why I converted it to base64 then blob then upload. But thank you for notifying the usual thing hope my code helped you 🙂

                            1 Reply Last reply Reply Quote 0
                            • S
                              saro199 last edited by

                              @tanaychatterji
                              You are absolutely correct. My API says it got the files, but there is no content. Realized after seeing your comment :).
                              Thank you so much for the help and I really appreciate it. After changing to base64, I see the content in API.

                              tanaychatterji 1 Reply Last reply Reply Quote 0
                              • tanaychatterji
                                tanaychatterji @saro199 last edited by

                                @saro199 Welcome, thank god it helped you 🤣
                                I thought I have to again code this logic 🤣

                                1 Reply Last reply Reply Quote 0
                                • First post
                                  Last post