Tuesday, September 23, 2014

Firefox OS: Converting a camera image to a base64 encoded image URL

I'm porting my apps ScoreGeek and Easy Password Storage to Firefox OS, and ran into some issues with saving images returned by the camera or gallery picker.

The problem is that I am used to Android and iOS returning a base64 image URL, but Firefox OS returns a blob URL that points to a local location on the device, like this:


You can load that URL into a image tag's source and it displays, but you can't resize it, save it, send it to another device, or even keep it around after you turn off the phone.

My objective is to save it as a Base64 encoded image URL and then put it into LocalStorage or push it to my cloud server to be downloaded by other devices.

After days of fooling around with FileReader I gave it up and found the correct approach: use a picker to get the photo data (as a blob:// url), load the blob URL into an image, then copy the image data to a canvas, and convert it to a Data URL.  The result is a base64 encoded image URL that can be saved on the device.

I've copied the relevant functions from my code below, but it will require some modification to run in your environment.

I hope this helps someone else with the same problem!

var devicePlatform = getDevicePlatform();

var pick = new MozActivity({
                        name: "pick",
                        data: {
                            type: ["image/png"]
                        pick.onsuccess=function() {
                            var res=pick.result;
                            // Create object url for picked image
                            var photoURL=window.URL.createObjectURL(res.blob);
                        pick.onerror = function() {


gamePicSuccess: function (imageData) {
        var $el = $('#imgGameImage'); //jquery variable pointing to the element where the image will be displayed
        if (devicePlatform === "FirefoxOS") {
            var elDom = document.getElementById("imgGameImage");
            function myLoad() {
                elDom.removeEventListener('load', myLoad); // to avoid a loop
                var imgCanvas = document.createElement("canvas"),
                imgContext = imgCanvas.getContext("2d");
                imgCanvas.width = elDom.width;
                imgCanvas.height = elDom.height;
                imgContext.drawImage(elDom, 0, 0, elDom.width, elDom.height);
                var imgAsDataURL = imgCanvas.toDataURL("image/png");
                $el.attr('src', imgAsDataURL).load(); 
            elDom.addEventListener("load", myLoad, false);
            $el.attr('src', imageData).load(); 


function getDevicePlatform() {
    var device;
    var deviceArray;
    var userAgent = navigator.userAgent;
    //userAgent = "Mozilla/5.0 (Mobile; rv:14.0) Gecko/14.0 Firefox/14.0";
    if (userAgent.match(/(iOS|iPhone|iPod|iPad|Android|Windows Phone|Mobile)/)) {
        deviceArray = userAgent.match(/(iPhone|iPod|iPad|Android|Windows Phone|Mobile)/);
        device = deviceArray[0];
        if (device === "Mobile") {
            deviceArray = userAgent.match(/(Firefox)/);
            device = deviceArray[0];
            if (device === "Firefox") {
                device = "FirefoxOS";
            } else {
                device = "Browser";

        if (device === "iPhone" || device === "iPod" || device === "iPad") {
            device = "iOS";
        if (device === "Windows Phone") {
            device = "WinPhone";
    } else {
        device = "Browser";

    return device;