Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Phonegap Plugin:How to convert Base64 String to a PNG image in Android

Android does not allow native apps like Phonegap-based apps to write binary files. A common application is converting Base64 Strings to Images. So, how do you go about this problem?

like image 557
mukama Avatar asked Jul 09 '12 01:07

mukama


People also ask

How does base64 png work?

To get to a base64 representation:png. Paint uses its png encoder to convert the bitmap of pixels into a stream of bytes that it compresses and appends headers to so that when it sees those bytes again it knows how to display them. Image is written to disk as series of bytes.

What is base64 png?

data:image/png;base64 tells the browser that the data is inline, is a png image and is in this case base64 encoded. The encoding is needed because png images can contain bytes that are invalid inside a HTML document (or within the HTTP protocol even).


2 Answers

The solution; This plugin that converts a Base64 PNG String and generates an image to the sdCard. Let's go!

1. The Base64 Decoder

Get this blazing fast Base64 encode/decoder class called MiGBase64. Download it from SourceForge. Create a folder called 'util' within your project's src/ folder. Place the downloaded class there.

2. The java

Create a folder called 'org/apache/cordova' within your project's src/ folder. Create in it a Java file called "Base64ToPNG.java" with the following source code.

package org.apache.cordova;

/**
* A phonegap plugin that converts a Base64 String to a PNG file.
*
* @author mcaesar
* @lincese MIT.
*/

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

import org.apache.cordova.api.Plugin;
import org.apache.cordova.api.PluginResult;
import org.json.JSONArray;

import android.os.Environment;
import java.io.*;
import org.json.JSONException;
import org.json.JSONObject;
import util.Base64;

public class Base64ToPNG extends Plugin {

    @Override
    public PluginResult execute(String action, JSONArray args, String callbackId) {

        if (!action.equals("saveImage")) {
            return new PluginResult(PluginResult.Status.INVALID_ACTION);
        }

        try {

            String b64String = "";
            if (b64String.startsWith("data:image")) {
                b64String = args.getString(0).substring(21);
            } else {
                b64String = args.getString(0);
            }
            JSONObject params = args.getJSONObject(1);

            //Optional parameter
            String filename = params.has("filename")
                    ? params.getString("filename")
                    : "b64Image_" + System.currentTimeMillis() + ".png";

            String folder = params.has("folder")
                    ? params.getString("folder")
                    : Environment.getExternalStorageDirectory() + "/Pictures";

            Boolean overwrite = params.has("overwrite") 
                    ? params.getBoolean("overwrite") 
                    : false;

            return this.saveImage(b64String, filename, folder, overwrite, callbackId);

        } catch (JSONException e) {

            e.printStackTrace();
            return new PluginResult(PluginResult.Status.JSON_EXCEPTION, e.getMessage());

        } catch (InterruptedException e) {
            e.printStackTrace();
            return new PluginResult(PluginResult.Status.ERROR, e.getMessage());
        }

    }

    private PluginResult saveImage(String b64String, String fileName, String dirName, Boolean overwrite, String callbackId) throws InterruptedException, JSONException {

        try {

            //Directory and File
            File dir = new File(dirName);
            if (!dir.exists()) {
                dir.mkdirs();
            }
            File file = new File(dirName, fileName);

            //Avoid overwriting a file
            if (!overwrite && file.exists()) {
                return new PluginResult(PluginResult.Status.OK, "File already exists!");
            }

            //Decode Base64 back to Binary format
            byte[] decodedBytes = Base64.decode(b64String.getBytes());

            //Save Binary file to phone
            file.createNewFile();
            FileOutputStream fOut = new FileOutputStream(file);
            fOut.write(decodedBytes);
            fOut.close();


            return new PluginResult(PluginResult.Status.OK, "Saved successfully!");

        } catch (FileNotFoundException e) {
            return new PluginResult(PluginResult.Status.ERROR, "File not Found!");
        } catch (IOException e) {
            return new PluginResult(PluginResult.Status.ERROR, e.getMessage());
        }

    }
}

3. The Javascript

Write this JavaScript as Base64ToPNG.js to your project's www folder. DONT forget to include a reference to it in your html files.

/**Works on all versions prior and including Cordova 1.6.1 
* by mcaesar
*  MIT license
*  
*/

(function() {
    /* This increases plugin compatibility */
    var cordovaRef = window.PhoneGap || window.Cordova || window.cordova; // old to new fallbacks

    /**
    * The Java to JavaScript Gateway 'magic' class 
    */
    function Base64ToPNG() { }

    /**
    * Save the base64 String as a PNG file to the user's Photo Library
    */
    Base64ToPNG.prototype.saveImage = function(b64String, params, win, fail) {
        cordovaRef.exec(win, fail, "Base64ToPNG", "saveImage", [b64String, params]);
    };

    cordovaRef.addConstructor(function() {
        if (!window.plugins) {
            window.plugins = {};
        }
        if (!window.plugins.base64ToPNG) {
            window.plugins.base64ToPNG = new Base64ToPNG();
        }
    });

})(); 

4. The plugins.xml file

Add the following to res/xml/plugins.xml file

<plugin name="Base64ToPNG" value="org.apache.cordova.Base64ToPNG"/>

5. Finally, HTML examples and the parameters

<button onclick="test();">No optional params required, Cowboy.</button> </br>
<button onclick="test2();">Make PNG with some parameters</button>

<script src="Base64ToPNG.js" type="text/javascript"></script>

<script type="text/javascript">

//May have a mime-type definition or not 
var myBase64 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="//a red dot


function test(){

    //Illustrates how to use plugin with no optional parameters. Just the base64 Image.
    window.plugins.base64ToPNG.saveImage(myBase64, {}, 
       function(result) {
          alert(result);
       }, function(error) {
          alert(error);
       });
 }

 //No mimetype definition example
 var myOtherBase64 = "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="

 function test2(){

    //Shows how to use optional parameters
    window.plugins.base64ToPNG.saveImage(myBase64, {filename:"dot.png", overwrite: true}, 
       function(result) {
          alert(result);
       }, function(error) {
          alert(error);
    });

 }
 </script>

Parameters

  1. filename: Name of the file to be generated. By default the same as the one in url.
  2. folder: Name of the directory to generate the file to. By default "sdcard/Pictures"
  3. overwrite: If the file already exists, replace it. By default false.

    I hope this answers some bothering questions. Happy coding!

like image 105
5 revs Avatar answered Oct 08 '22 03:10

5 revs


Fo anybody wanting to use this with kineticjs, the following works a treat:

function saveCanvas() {
    $('#save').bind( $bind, function(){
        stage.toDataURL({
        callback: function(dataUrl){
            window.plugins.base64ToPNG.saveImage(dataUrl.substr(22,dataUrl.length), {}, 
                function(result) {
                    alert(result);
                }, function(error) {
                    alert(error);
                }
            );
        },
            mimeType: 'image/png',
            quality: 0.5
        });
    });
}
like image 26
Luke Snowden Avatar answered Oct 08 '22 03:10

Luke Snowden