Convert a picture taken with the camera to a Base64 String

Hi,

i’m trying to get my head around how i can convert a picture taken with the camera (as explained here) into a Base64 String to save or send to my server.

Best regards

Till

Hey Till, thanks for posting in the forum. We are working on getting both the Camera and IO api a bit better, but this should work:

var Camera = require('FuseJS/Camera');
Camera.takePicture({targetWidth:20, targetHeight:20}).then(function(file){
    var reader  = new FileReader();
    reader.onloadend = function() {
        console.log(reader.result);
    };
    reader.readAsDataURL(file);
}).catch(function(e){
    console.log(e);
});

Oh, you mean capture the effect in UX. I think you have to go into Uno land to do that. I will see if I get time to create an example for you.

Hey Anders,

your first solution was exactly what i was looking for. Thanks a lot :slight_smile:

Hey Anders,

i’m running into an issue now. This method works the first time i use it, but when taking another picture, the call to reader.readAsDataURL fails.

While debugging i found out, that the resulting file of Camera.takePicture is the same as before (e.g. /var/mobile/Containers/Data/Application/94E711F4-80FC-460B-8A7F-51226C275A5E/Documents/temp.jpg). This might be an issue, as the file already exists.

Here is my code, can you take another look at this?

<App Theme="Basic">

    <Panel>

        <JavaScript>

            var Observable = require('FuseJS/Observable');
            var Camera = require('FuseJS/Camera');

            var imageString = Observable("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAADaSURBVDhPtZK9CYRAFISvNhEUURDEwAIMLMAWLMHcxMDQMqzAxCIUxUSdY/f2+cfbC05u4Iuc+VjWfeFh/itYluUrIlpBURQwTVOL7/sYx5EX9H0Pz/NgWZaWqqpklxVkWcaOiDiOVZMRtG0L27bZIdE0jWrfBOu6IkkSdkSkaSp7lIugrmt2RARBgGEYVPuTXSA+uK7LDomyLFX7yC7I85wdEWEYYp5n1T4iBV3XwXEcdkicL+6cl3hRURTBMAwt4uLo5d0jTyCONk2Tlm3bZJnL5S/8kocC4A2RfkKIvwD9JQAAAABJRU5ErkJggg==");

            console.log("##########################################");

            function takePicture()
            {
                Camera.takePicture({targetWidth:128})
                .then(function(file)
                {
                    console.log( "picture taken: " + file.path );
                    convertPictureToBase64( file );

                })
                .catch(function(e)
                {
                    console.log( "error: " + e );
                });
            }


            function convertPictureToBase64( file )
            {
                console.log("converting to Base64.");

                var reader  = new FileReader();

                reader.onloadend = function() 
                {
                    //console.log( reader.result );                    console.log( "conversion finished" );
                    console.log("**");                    imageString.value = reader.result;
                };

                reader.readAsDataURL( file );
            }


            module.exports = 
            {
                imageString : imageString,
                takePicture : takePicture,
            };


        </JavaScript>

        <StackPanel Orientation="Vertical">

            <Image Width="64" Height="64" ux:Name="picture1" >
                <Base64ImageSource Base64="{imageString}" />
            </Image>

            <Button Height="48" Text="Take picture" Clicked="{takePicture}" />

        </StackPanel>

    </Panel>

</App>
</code></pre></div>
<p>EDIT: Saving the file with the same name into the same folder is most likely no the cause of the problem. I was sometimes able to take 3 pictures without problems, then breaking it on the fourth picture.</p>
<p>This is my StackTrace from XCode (no errors in Fuse Monitor)</p>
<div class="highlighted_code"><pre><code class="language-uno">* thread #22: tid = 0x5ab8, 0x0000000100348568 base64Testg::Fuse::Scripting::FactoryClosure::Run() [inlined] uType::T(this=0x7000000000000000, index=0) at ObjectModel.h:848, stop reason = EXC_BAD_ACCESS (code=1, address=0x7000000000000078)
  * frame #0: 0x0000000100348568 base64Testg::Fuse::Scripting::FactoryClosure::Run() [inlined] uType::T(this=0x7000000000000000, index=0) at ObjectModel.h:848 [opt]
    frame #1: 0x0000000100348568 base64Testg::Fuse::Scripting::FactoryClosure::Run(this=0x0000000152e31110) + 48 at Fuse.Scripting.g.cpp:1010 [opt]
    frame #2: 0x00000001004f690c base64Testinvoke_delegate(arg=&lt;unavailable&gt;) + 44 at posix_thread.h:15 [opt]
    frame #3: 0x0000000181753b28 libsystem_pthread.dylib_pthread_body + 156
    frame #4: 0x0000000181753a8c libsystem_pthread.dylib`_pthread_start + 156

Hi Anders, I’m also having issues, specifically with FileReader.

I followed your example, copy-paste in fact, and every time I attempt to run the code my app crashes (running on Android 4.4.2 Galaxy S4).

If I comment out the line reader.readAsDataURL(file); my app will run, but of course I’m not able to do what I’m trying to do.

I also tried using Storage.read(file.path), this will successfully get into my promise callback but the contents of the file are read as blank, example:

var Observable = require('FuseJS/Observable');
var Camera = require('FuseJS/Camera');
var Storage = require('FuseJS/Storage');

var picture = Observable();

function takePicture(){
    Camera.takePicture({targetWidth:1000, targetHeight:1200}).then(function(file){
        Storage.read(file.path).then(function(file_content){
            console.log(file.name);
            console.log(file_content);
            var obj = {'file' : file_content};
            fetch('http://testurl', {
                method: 'POST',
                body: JSON.stringify(obj)
            }).then(function(response) {
                console.log(response.status)
                console.log(response.text())
            }).catch(function(err) {
                console.log(err.message);
            });
        }).catch(function(err){
            console.log(err.message);
        });
    }).catch(function(e){
        console.log(e);
    });
}

file.path will return something like "/storage/emulated/0/Android/data/com.photoapp/files/JPEG_12_-452507721.jpg" and my response.status properly returns 200. However, file_content is returning an empty string.

Ideally I would use the base64 method you outlined earlier, but like I said, the line reader.readAsDataURL(file); causes my app to crash.

Any advice is greatly appreciated.

I have the same problem :frowning: My app crash!

Anders Bondehagen wrote:

Hey Till, thanks for posting in the forum. We are working on getting both the Camera and IO api a bit better, but this should work:

var Camera = require('FuseJS/Camera');
Camera.takePicture({targetWidth:20, targetHeight:20}).then(function(file){
    var reader  = new FileReader();
    reader.onloadend = function() {
        console.log(reader.result);
    };
    reader.readAsDataURL(file);
}).catch(function(e){
    console.log(e);
});

When I use preview on my Android device like this: file

Work fine! But when I export my app to apk via terminal (uno build --target=Android -run) the app Crash! (I test it only on Android).

Hi Cristian,

Can you please provide a zip with the app in question?

Anders Lassen wrote:

Hi Cristian,

Can you please provide a zip with the app in question?

Is very similar to till@eightdaysaweek.cc app:

    <App Theme="Basic">
        <Panel>
            <JavaScript>
                var Observable = require('FuseJS/Observable');
                var Camera = require('FuseJS/Camera');

                var imageFile = Observable("");


                function takePicture()
                {
                    Camera.takePicture({ targetWidth: 200, targetHeight: 200, correctOrientation: true}).then(function(file)
                    {
                        convert( file );

                    })
                    .catch(function(e)
                    {
                    });
                }


                function convert( file )
                {

                    var reader  = new FileReader();

                    reader.onloadend = function() 
                    {
                        imageFile.value = reader.result;
                    };

                    reader.readAsDataURL( file );
                }

            module.exports = {
                takePicture : takePicture
            }
        </JavaScript>

        <Button Height="48" Text="Take picture" Clicked="{takePicture}" />

        </Panel>
    </App>

Are there any news on this topic? I would love to implement user avatars in my app.

Thanks

Till

Hi Till, we have an open ticket on this but we might not get much done on it in the next 1-2 weeks. We’ll let you know when there’s any progress on this.

Same problem here… Any news?

Soon ready, I hope we can get it in one of the upcoming releases.

The file that is given via the first parameter of camera.takePicture can just have a toBase64() method, that would make it easier for everyone:

camera.takePicture({...}, function(file) {
  file.toBase64(); // returns base64 code
});

The File currently returned is one of these guys and we won’t extend that with arbitrary APIs.

This is actively being worked on at a day to day basis right now, I’ll keep this thread posted when things change. The next Camera API will require migration as it diverges a fair bit from the current one, though we’ll offer backwards compat.

That’s reasonable to not alter the Native Objects, how about passing a toBase64 method that takes a file object?

camera.takePicture({...}, function(file, toBase64) {
  toBase64(file); // returns base64 code
});

The advantage is that readAsDataURL doesn’t interact with fuse/uno/native (not sure which word is right), the same way camera.takePicture does to open up the camera, so the toBase64 would use Uno’s native power

But anywho hopefully you guys figured something way better, but just a small suggestion

BTW an object helper would be better

camera.takePicture({...}, function(file, helper) {
  helper.toBase64(file); // returns base64 code
});

So that it can have all types of methods and properties

Looking forward to this!

any update on this? my app is crashing using the file reader solution

function takePicture(){
    camera.takePicture({targetWidth:100, targetHeight:100}).then(function(file){
      var reader  = new FileReader();
      reader.onloadend = function() {
          picture.value = reader.result;
          console.log(reader.result);
      };
      reader.readAsDataURL(file);
    }).catch(function(e){
        console.log(e);
    });
}

I also wanna know as well any update, but @Prince try to play with https://www.fusetools.com/docs/fusejs/base64

See if that helps and please let me know if you had any luck.