I have been working on a Phonegap based Android app which involves the HTML5 Canvas. So this is what I had been trying for some time – get a png/jpeg image of the Canvas (its a Canvas paint app, something like this and I want to get an image of the drawing..) and then upload the image to Facebook on a user’s album. Let me tell you, it has been a heck of a task and around 15-20 days of restlessness.
The problem stood tall when I discovered that for Android 2.3 (in general Android < 4.0) devices the native HTML5 Canvas- toDataURL() function does not work, which would otherwise give a base64 encoded string as image data which then can be used as a source for a HTML <img /> tag. It was working for 4.0 devices as I tested it on a Samsung Galaxy S3 and a Samsung Tab. Hence I Goggled a bit and found out various people had this issue before. So it seemed that older Android web-kits (a Phonegap app runs on the Android webview which is actually the webkit browser inside a native wrapper) does not support that native method of converting a Canvas to an image through toDataURL() generated base64 encoded strings. Guess what I had todo? I had to go for a custom Phonegap plugin as there was no other way. This is how I thought of implementing it – pass the canvas object from javascript side to the Phonegap plugin’s Java class and somehow get the base64 encoded string of the Canvas and return it back to javascript as the callback parameter. This is what the native toDataURL() method actually does – convert the Canvas to a base64 encoded image data string.
For the full post download this file or visit the actual blog post link: http://jbkflex.wordpress.com/2012/12/21/html5-canvas-todataurl-support-for-android-devices-working-phonegap-2-2-0-plugin/
HTML5 Canvas – toDataURL() support for Android devices – working Phonegap 2.2.0 Plugin
1. HTML5 Canvas – toDataURL()
support for Android devices –
working Phonegap 2.2.0 Plugin
Actual blog post link - http://jbkflex.wordpress.com/2012/12/21/html5-canvas-todataurl-support-
for-android-devices-working-phonegap-2-2-0-plugin/
I have been working on a Phonegap based Android app which involves the HTML5 Canvas. So this is
what I had been trying for some time – get a png/jpeg image of the Canvas (its a Canvas paint app,
something like this and I want to get an image of the drawing..) and then upload the image to Facebook
on a user’s album. Let me tell you, it has been a heck of a task and around 15-20 days of restlessness.
The problem stood tall when I discovered that for Android 2.3 (in general Android < 4.0) devices the
native HTML5 Canvas- toDataURL() function does not work, which would otherwise give a base64
encoded string as image data which then can be used as a source for a HTML <img /> tag. It was
working for 4.0 devices as I tested it on a Samsung Galaxy S3 and a Samsung Tab. Hence I Goggled a
bit and found out various people had this issue before. So it seemed that older Android web-kits (a
Phonegap app runs on the Android webview which is actually the webkit browser inside a native wrapper)
does not support that native method of converting a Canvas to an image through toDataURL() generated
base64 encoded strings. Guess what I had todo? I had to go for a custom Phonegap plugin as there
was no other way. This is how I thought of implementing it – pass the canvas object from javascript side
to the Phonegap plugin’s Java class and somehow get the base64 encoded string of the Canvas and
return it back to javascript as the callback parameter. This is what the native toDataURL() method actually
does – convert the Canvas to a base64 encoded image data string.
Not being a Java developer, I had to look for external help, that’s where I came across Ryan Gillespie’s
plugin which he developed some time back for the very purpose that I was looking for. But the code was
kinda old and is not compatible with Phonegap 2.2.0 (this is the version that I am using for development)
as there have been numerous changes in the Phonegap’s plugin architecture. I had to do some
modifications to the code – mainly on the Java side. I used Ryan’s Java code and modified it a little bit. I
wrote the javascript interface of the plugin entirely. Overall, thanks to Ryan for doing the tough part and its
been possible to achieve the task. I had the modified plugin running successfully on older Android’s with
Phonegap 2.2.0 and returning a valid base64 encoded image string of the HTML5 Canvas.
Let’s quickly talk on the changes that I made. I will not discus on how to create custom Phonegap plugins
in this post. For that you need to checkout the official documentation. It is better if you have some idea of
creating custom plugins and what goes into creating a plugin, specifically the communication between
JavaScript and Java.
2. As I said earlier I modified Ryan’s Java class – CanvasPlugin.java. Download the file and check out the
source. You will notice that the main changes are the new format for the overridden execute() method
and it returns a boolean type now, also your plugin class should now extend the CordovaPlugin
superclass, the third major change being the way callbackContext object now calls the success and error
methods and in a way calls the javascript interface after the execute() method has finished it’s execution.
There’s once more important change that I made is inside the custom getImageData() method –
Base64.encodeBase64() has now been deprecated for the android.util.Base64 class, instead use
Base64.encodeToString() method. So, mostly these changes made the Java class compatible with
Phonegap 2.2.0. Now let’s check out the new JavaScript interface for the plugin.
I did not use Ryan’s javascript file. I wrote a simple one myself. So get a copy of it first –
CanvasPlugin.js. The logic is simple if you know how to write a javascript part of a Phonegap plugin. I
am creating a canvasplugin method and exposing it to the global window object so that it is accessible
across your code. The canvasplugin method takes two parameters – the HTML5 Canvas reference and
the callback function reference which will be called once we have a result from Java side. Next important
thing is calling the CanvasPlugin.java execute() method and passing it the right arguments. For that I
would again suggest to go through the official documentation. You can modify the javascript code to
make it better probably.
With both the files ready, let’s see how to use it and get it working. Firstly you have to add these two files
to your Phonegap Android project. Add the CanvasPlugin.js file inside assets/www/ folder and provide a
reference to it in your index.html file, like this
<script type="text/javascript" charset="utf-8"
src="CanvasPlugin.js"></script>
Then create a directory inside your project’s src folder that matches the package name of
CanvasPlugin.java class. For our case make a directory – /org/apache/cordova/plugin inside src and then
paste CanvasPlugin.java inside it. If you change the package name, make sure to change the directory
structure as well. The package name can be found at the top of CanvasPlugin.java file.
Next thing to do is to register the plugin in the config file – open res/xml/config.xml and then add the
plugin details given below to the <plugins></plugins> section of the XML file. The name attribute is the
Java class name and the value is the path of the class. This should match the package name.
<plugin name="CanvasPlugin" value="org.apache.cordova.plugin.CanvasPlugin"/>
And then call the plugin inside your javascript (your script.js file or so) code like this. (You can call this
inside a button click handler or so),
var canvas = document.getElementById("myCanvas");
3. window.canvasplugin(canvas,function(val){
document.getElementById("myImg").src = val.data;
});
where myCanvas is the ID of the HTML Canvas. The callback function receives the Base64 encode
image string inside the data property of the returned value. Make sure to access it through val.data. Now
you can use this as a source for an HTML image tag and you can get a preview image of your canvas.
Here I am getting a Base64 encoded .png image string. If you need to change the mimeType, you can do
that inside the CanvasPlugin.js file. Also you can pass that as a parameter to the javascript interface
rather than hard code inside the CanvasPlugin.js file (which I did mistakenly). So pass it from your
script.js to window.canvasplugin() call along with the canvas reference and the callback reference, as the
third parameter.
Lot of writing and English!! DOH!! But the cool plugin architecture has been able to overcome the
shortcomings isn’t it.