Upload a photo from Camera.takePicture

Hi, I asked this in slack and was advised to post here.

I’m trying to take a picture with the camera and post it to a server. I was trying to avoid Parse but have just recently started playing around with it.

I’ve tried two methods with no success. Both of these examples are written within the Camera.takePicture callback, file is the File object passed to the callback.

Method 1: Using the FileReader.

I follwed an example posted in another forum thread (https://www.fusetools.com/community/forums/howto_discussions/convert_a_picture_taken_with_the_camera_to_a_base6?page=1), as follows:

var reader  = new FileReader();
reader.onloadend = function() {
    console.log(reader.result);
};
reader.readAsDataURL(file);

My problem here is that reader.readAsDataURL(file); crashes my app entirely (Android 4.4.2).

Method 2: Using Storeage.read.

I also tried using Storage.read

Storage.read(file.path).then(function(file_content){
    console.log(file_content);
}).catch(function(err){
    console.log(err.message);
});

My problem here is that file_content is an empty string. I also, initially tried this with Storage.read(file) instead of Storage.read(file.path).

The fellow on Slack said I may not even need to read the file into JS which would be glorious! Any help is greatly appreciated!

We are currently working on making this a lot better. It is possible to do this in the current version without making it a base64 image by using Uno. If you can’t wait for the new API, I can try to code an examplpe for you.

Anders, that would be amazing! I have no use for having the actual photo data within JS other than to transport it somewhere. Thanks so much!

I have not tested if this actually works, but it should :stuck_out_tongue: You should add some more error checking ofc. But you get the idea.

MainView.ux:

<App Theme="Basic">
    <Upload ux:Global="uploadFile" />
    <JavaScript>
        var Camera = require('FuseJS/Camera');
        var Uploader = require('uploadFile');

        Camera.takePicture({targetWidth:150, targetHeight:150}).then(function(file){
            return Uploader.send(file, 'https://<myAwesomeImageUrl>.com&#39;);
        }).then(function(statusCode){
            console.log("Done");
            console.log(statusCode);
        }).catch(function(e){
            console.log("Error");
            console.log(e);
        });
    </JavaScript>
</App>

Add this to the project file:

  "Packages": [
...
        "Uno.Threading",
        "Uno.Net.Http"
  ],

And create a file called UploadFile.uno and add the following:

using Uno;
using Fuse.Scripting;
using Fuse.Reactive;
using Uno.Threading;
using Uno.Net.Http;

public class Upload : NativeModule
{
    public Upload()
    {
        AddMember(new NativePromise<int, int>("send", (FutureFactory<int>)send, null));
    }

    static Future<int> send(object[] args)
    {
        var path = ((Fuse.Scripting.Object)args[0])["path"] as string;
        var uri = (string)args[1];

        var imageData = Uno.IO.File.ReadAllBytes(path);

        var client = new HttpMessageHandler();
        var request = client.CreateRequest("POST", uri);

        var promise = new Promise<int>();
        new ResultClosure(promise, request);
        request.SendAsync(imageData);

        return promise;
    }

    class ResultClosure
    {
        Promise<int> _promise;

        public ResultClosure(Promise<int> promise, HttpMessageHandlerRequest request)
        {
            _promise = promise;

            request.Done += Done;
            request.Aborted += Aborted;
            request.Error += Error;
            request.Timeout += Timeout;
        }

        void Done(HttpMessageHandlerRequest r) { _promise.Resolve(r.GetResponseStatus()); }

        void Error(HttpMessageHandlerRequest r, string message) { _promise.Reject(new Exception(message)); }

        void Aborted(HttpMessageHandlerRequest r) { _promise.Reject(new Exception("Aborted")); }

        void Timeout(HttpMessageHandlerRequest r) { _promise.Reject(new Exception("Timeout")); }
    }
}

Thanks so much! This is great. It may be a few days before I get to test this out (right now Fuse development is just something I’m doing in my spare time) but I’ll definitely give this a shot and report back!

Anders Bondehagen wrote:

I have not tested if this actually works, but it should :stuck_out_tongue: You should add some more error checking ofc. But you get the idea.

MainView.ux:

<App Theme="Basic">
    <Upload ux:Global="uploadFile" />
    <JavaScript>
        var Camera = require('FuseJS/Camera');
        var Uploader = require('uploadFile');

        Camera.takePicture({targetWidth:150, targetHeight:150}).then(function(file){
            return Uploader.send(file, 'https://<myAwesomeImageUrl>.com&#39;);
        }).then(function(statusCode){
            console.log("Done");
            console.log(statusCode);
        }).catch(function(e){
            console.log("Error");
            console.log(e);
        });
    </JavaScript>
</App>

Add this to the project file:

  "Packages": [
...
        "Uno.Threading",
        "Uno.Net.Http"
  ],

And create a file called UploadFile.uno and add the following:

using Uno;
using Fuse.Scripting;
using Fuse.Reactive;
using Uno.Threading;
using Uno.Net.Http;

public class Upload : NativeModule
{
    public Upload()
    {
        AddMember(new NativePromise<int, int>("send", (FutureFactory<int>)send, null));
    }

    static Future<int> send(object[] args)
    {
        var path = ((Fuse.Scripting.Object)args[0])["path"] as string;
        var uri = (string)args[1];

        var imageData = Uno.IO.File.ReadAllBytes(path);

        var client = new HttpMessageHandler();
        var request = client.CreateRequest("POST", uri);

        var promise = new Promise<int>();
        new ResultClosure(promise, request);
        request.SendAsync(imageData);

        return promise;
    }

    class ResultClosure
    {
        Promise<int> _promise;

        public ResultClosure(Promise<int> promise, HttpMessageHandlerRequest request)
        {
            _promise = promise;

            request.Done += Done;
            request.Aborted += Aborted;
            request.Error += Error;
            request.Timeout += Timeout;
        }

        void Done(HttpMessageHandlerRequest r) { _promise.Resolve(r.GetResponseStatus()); }

        void Error(HttpMessageHandlerRequest r, string message) { _promise.Reject(new Exception(message)); }

        void Aborted(HttpMessageHandlerRequest r) { _promise.Reject(new Exception("Aborted")); }

        void Timeout(HttpMessageHandlerRequest r) { _promise.Reject(new Exception("Timeout")); }
    }
}

I have tried doing this with a gallery image. I’m getting the same results as tj where my image file is empty.

Any updates on how to do this with the current version?

Hi Jozef, did that happen when you used the Uno code you quoted or FileReader? What platforms/os did you try?

Anders Bondehagen wrote:

Hi Jozef, did that happen when you used the Uno code you quoted or FileReader? What platforms/os did you try?

It happend when using the Uno code. I tried it on iOS using the Xcode simulator. I’ve used debug log’s to see if the image get’s passed to the actual Uno code and that worked. But when sending the file to the PHP script it seems like it get’s lost somewhere. Here’s the output from my debug log.

file

I will add a ticket so we can investigate this.

Anders Bondehagen wrote:

I will add a ticket so we can investigate this.

Any update or timeframe on when I can expect an update?

That’s a start but this sample seems half baked.

The global is called “uploadFile” with a lowercase “u”.

The file is called UploadFile.uno, with a uppercase “U”.

The class is called “Upload”.

We require: var Uploader = require(‘UploadFile’); which doesn’t work for me. While we use the class with the name “Uploader”.

Is this working for anyone or have we come up with another way, like the FormData implementation for using with XMLHttpRequest.

Cheers.

-P

Small update:

I’ve created a new app and now I do get data to be sent to my server only I have no idea how to get that data I get to a actual image file.

I’ve managed to get the output into a TXT file and when opening it looks something like this

Do you have any advise on how to see if this is actually an image and how to convert it into a image file?

My php script looks like this.

<?php
$post = file_get_contents('php://input');

$test = $post;


$file = 'image.txt';
// Open the file to get existing content
$current = file_get_contents($file);
// Append a new person to the file
$current .= print_r($test, true);
// Write the contents back to the file
file_put_contents($file, $current);
?>

If I simply change the extention to .jpeg (tried this in my script and in finder) the image doesnt open

In this Uno example, which I finally got to work (with a Ruby on Rails server at least), you can get the raw data, and save it to a PNG file.

Although I know very little of PHP, this seems correct: $post = file_get_contents(‘php://input’);

Then create a new file and dump the content to it. No need to get the content of a file, append, any of that.

-P

Hi Aders and everyone, i did something pretty simple to upload images, this is the code:

                    function TakePhoto()
		{
			CameraRoll.getImage()
    		.then(function(image) {
    			
    			ImageTools.getBase64FromImage(image).then(function(b64){
    				UploadImage(b64);
    			});

    		}, function(error) {
        		// Will be called if the user aborted the selection or if an error occurred.
    		});
		}
		
		function UploadImage(image)
		{
			var xhr = new XMLHttpRequest();
			xhr.addEventListener("progress",function(e){ Progress(e); }, false);
			xhr.onprogress = Progress; //i tried this one too
			xhr.addEventListener("load",function(e){ Done(e); }, false);
			xhr.addEventListener("error",function(e){ Error(e); }, false);
			xhr.open("POST","MyHiddenWebServiceURL",true);
			xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
			var parametros = {'imagen':image,'id': ElCliente.value.IDCliente};
			xhr.send(JSON.stringify(parametros));
			
		}

		function Done(e)
		{
			if(e.target.status===200)
			{
				var r = JSON.parse(e.target.responseText);
				var datos = JSON.parse(r.d);
				ElCliente = datos;
				console.log("Subio imagen");
				console.log("Exito " + e.target.responseText);
			}else
			{
				console.log("Estaus erroneo " + e.target.status);
				var r = JSON.parse(e.target.responseText);
				console.log("El error es " + e.target.responseText);
			}
		}

		function Error(e)
		{
			console.log("Error al subir imagen");
		}

		function Progress(e)
		{
			console.log("hay progreso");
			if(e.lengthComputable)
			{
				var pc = Math.round(e.loaded * 100 / e.Total);
				console.log("Subiendo: " + pc + "%");
			}else{
				console.log("No computable");
			}
		}

But i can`t get the progress event to fire and i was wondering if your code does it or if there is some way to get the progress event to fire with this code.

The image Uplodas correctly, by the way.

Sorry for the mix between English and Spanish in the code