Thursday, August 14, 2014

Capture image generated by Google Charts API

Previous posts show how to "Display Google Charts (pie chart) on Android WebView" and "More Google Charts examples on Android WebView". To capture the PNG image of a chart, we can use the getImageURI() method, it return a string in "data:image/png;base64,..." format.


We can pass this string to Android code, decode and generate bitmap. To decode string in "data:image/png;base64,..." format, to Bitmap, we can use the code:
 private Bitmap decodeBase64PNG(String src){

  String imageDataBytes = src.substring(src.indexOf(",") + 1);
  
  InputStream stream = 
   new ByteArrayInputStream(
    Base64.decode(imageDataBytes.getBytes(), 
    Base64.DEFAULT));
  
     Bitmap bitmap = BitmapFactory.decodeStream(stream);
     return bitmap;
 }

For MainActivity.java, activity_main.xml and AndroidManifest.xml, refer to last post "Display Google Charts (pie chart) on Android WebView".

Other files modify from last post "More Google Charts examples on Android WebView".

Modify layout_webchart.xml to add a Button to Capture the image.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />
    
    <Spinner
        android:id="@+id/spcharts"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    
    <Button
        android:id="@+id/capture"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Capture" />
    
    <WebView
        android:id="@+id/web"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</LinearLayout>

ShowWebChartActivity.java
package com.example.androidwebchart;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import android.annotation.SuppressLint;
import android.app.Dialog;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.util.Base64;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.webkit.JavascriptInterface;
import android.webkit.WebView;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.Toast;

@SuppressLint("SetJavaScriptEnabled") 
public class ShowWebChartActivity extends ActionBarActivity {
 
 WebView webView;
 int num1, num2, num3, num4, num5;
 
 Spinner spCharts;
 List<String> listCharts;
 List<String> listHtml;
 
 Button btnCapture;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
        setContentView(R.layout.layout_webchart);
        
        Intent intent = getIntent();
        num1 = intent.getIntExtra("NUM1", 0);
        num2 = intent.getIntExtra("NUM2", 0);
        num3 = intent.getIntExtra("NUM3", 0);
        num4 = intent.getIntExtra("NUM4", 0);
        num5 = intent.getIntExtra("NUM5", 0);
        
        spCharts = (Spinner) findViewById(R.id.spcharts);
        
        listCharts = new ArrayList<String>();
        listCharts.add("Pie Chart");
        listCharts.add("Pie Chart 3D");
        listCharts.add("Scatter Chart");
        listCharts.add("Column Chart");
        listCharts.add("Bar Chart");
        listCharts.add("Histogram");
        listCharts.add("Line Chart");
        listCharts.add("Area Chart");
        
        listHtml = new ArrayList<String>();
        listHtml.add("file:///android_asset/pie_chart.html");
        listHtml.add("file:///android_asset/pie_chart_3d.html");
        listHtml.add("file:///android_asset/scatter_chart.html");
        listHtml.add("file:///android_asset/column_chart.html");
        listHtml.add("file:///android_asset/bar_chart.html");
        listHtml.add("file:///android_asset/histogram.html");
        listHtml.add("file:///android_asset/line_chart.html");
        listHtml.add("file:///android_asset/area_chart.html");
        
     ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this,
      android.R.layout.simple_spinner_item, listCharts);
     dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
     spCharts.setAdapter(dataAdapter);
     spCharts.setOnItemSelectedListener(new OnItemSelectedListener(){

   @Override
   public void onItemSelected(AdapterView<?> parent, View view,
     int position, long id) {
    String chartHtml = listHtml.get(parent.getSelectedItemPosition());
    webView.loadUrl(chartHtml);
   }

   @Override
   public void onNothingSelected(AdapterView<?> parent) {
    // TODO Auto-generated method stub
    
   }});
        
        webView = (WebView)findViewById(R.id.web);
        webView.addJavascriptInterface(new WebAppInterface(), "Android");

        webView.getSettings().setJavaScriptEnabled(true); 

        btnCapture = (Button)findViewById(R.id.capture);
        btnCapture.setOnClickListener(new OnClickListener(){

   @Override
   public void onClick(View v) {
    //call Javascript in WebView/HTML
    webView.loadUrl("javascript:capture()");
   }});
 }
 
 private void showCaptured(String imageuri){

  Bitmap bmp = decodeBase64PNG(imageuri);
  
  Dialog dialog = new Dialog(this);
     ImageView imageView = new ImageView(this);
     imageView.setImageBitmap(bmp);
     dialog.addContentView(
       imageView, 
       new LayoutParams(
        LayoutParams.MATCH_PARENT, 
        LayoutParams.MATCH_PARENT));
     dialog.show();
  
 }
 
 private Bitmap decodeBase64PNG(String src){

  String imageDataBytes = src.substring(src.indexOf(",") + 1);
  
  InputStream stream = 
   new ByteArrayInputStream(
    Base64.decode(imageDataBytes.getBytes(), 
    Base64.DEFAULT));
  
     Bitmap bitmap = BitmapFactory.decodeStream(stream);
     return bitmap;
 }

 public class WebAppInterface {

     @JavascriptInterface
  public int getNum1() {
   return num1;
  }
  
  @JavascriptInterface
  public int getNum2() {
   return num2;
  }
  
  @JavascriptInterface
  public int getNum3() {
   return num3;
  }
  
  @JavascriptInterface
  public int getNum4() {
   return num4;
  }
  
  @JavascriptInterface
  public int getNum5() {
   return num5;
  }
  
  @JavascriptInterface
  public void captureCallback(String imageURI){
   Toast.makeText(ShowWebChartActivity.this, 
    imageURI, Toast.LENGTH_LONG).show();
   showCaptured(imageURI);
  }
 }

}

All other HTMLs:

  • add a method Javascript function capture() to be called from Android, and call chart.getImageURI() to get image, and pass back to Android by calling captureCallback().
  • Make chart to global by removing "var" in front of it.

pie_chart.html
<!--ref: https://google-developers.appspot.com/chart/interactive/docs/quick_start-->
<html>
  <head>
    <!--Load the AJAX API-->
    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
    <script type="text/javascript">
    
      // Load the Visualization API and the piechart package.
      google.load('visualization', '1.0', {'packages':['corechart']});
      
      // Set a callback to run when the Google Visualization API is loaded.
      google.setOnLoadCallback(drawChart);


      // Callback that creates and populates a data table, 
      // instantiates the pie chart, passes in the data and
      // draws it.
      function drawChart() {

      // Create the data table.
      var data = new google.visualization.DataTable();
      data.addColumn('string', 'ITEM');
      data.addColumn('number', 'VALUE');
      data.addRows([
        ['Item 1', Android.getNum1()],
        ['Item 2', Android.getNum2()],
        ['Item 3', Android.getNum3()], 
        ['Item 4', Android.getNum4()],
        ['Item 5', Android.getNum5()]
      ]);

      // Set chart options
      var options = {'title':'Android-er: Google Charts example of Pie chart'};

      // Instantiate and draw our chart, passing in some options.
      chart = new google.visualization.PieChart(document.getElementById('chart_div'));
      chart.draw(data, options);
    }
    </script>
    
    <script type="text/javascript">
    function capture(){
     Android.captureCallback(chart.getImageURI());
    }
    </script>
    
  </head>

  <body>
 <!--Div that will hold the pie chart-->
    <div id="chart_div" style="width:100%; height:100%"></div>
  </body>
</html>

pie_chart_3d.html
<!--ref: https://google-developers.appspot.com/chart/interactive/docs/gallery/piechart-->
<html>
  <head>
    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
    <script type="text/javascript">
      google.load("visualization", "1", {packages:["corechart"]});
      google.setOnLoadCallback(drawChart);
      function drawChart() {
        var data = google.visualization.arrayToDataTable([
          ['Items',  'Value'],
          ['Item 1', Android.getNum1()],
          ['Item 2', Android.getNum2()],
          ['Item 3', Android.getNum3()],
          ['Item 4', Android.getNum4()],
          ['Item 5', Android.getNum5()]
        ]);

        var options = {
          title: 'Android-er: Google Charts example of 3D Pie chart',
          is3D: true,
        };

        chart = new google.visualization.PieChart(document.getElementById('piechart_3d'));
        chart.draw(data, options);
      }
    </script>
    
    <script type="text/javascript">
    function capture(){
     Android.captureCallback(chart.getImageURI());
    }
    </script>
    
  </head>
  <body>
    <div id="piechart_3d" style="width: 100%; height: 100%;"></div>
  </body>
</html>

scatter_chart.html
<!--ref: https://google-developers.appspot.com/chart/interactive/docs/gallery/scatterchart-->
<html>
  <head>
    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
    <script type="text/javascript">
      google.load("visualization", "1", {packages:["corechart"]});
      google.setOnLoadCallback(drawChart);
      function drawChart() {
        var data = google.visualization.arrayToDataTable([
          ['x', 'Value'],
          [ 1, Android.getNum1()],
          [ 2, Android.getNum2()],
          [ 3, Android.getNum3()],
          [ 4, Android.getNum4()],
          [ 5, Android.getNum5()]
        ]);

        var options = {
          title: 'Android-er: Google Charts example of Scatter chart',
          hAxis: {title: 'X'},
          vAxis: {title: 'Value'},
          legend: 'none'
        };

        chart = new google.visualization.ScatterChart(document.getElementById('chart_div'));
        chart.draw(data, options);
      }
    </script>
    
    <script type="text/javascript">
    function capture(){
     Android.captureCallback(chart.getImageURI());
    }
    </script>
    
  </head>
  <body>
    <div id="chart_div" style="width: 100%; height: 100%;"></div>
  </body>
</html>

column_chart.html
<!--ref: https://google-developers.appspot.com/chart/interactive/docs/gallery/columnchart-->
<html>
  <head>
    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
    <script type="text/javascript">
      google.load("visualization", "1", {packages:["corechart"]});
google.setOnLoadCallback(drawChart);
function drawChart() {

  var data = google.visualization.arrayToDataTable([
    ['Items', 'Value'],
    ['Item 1',  Android.getNum1()],
    ['Item 2',  Android.getNum2()],
    ['Item 3',  Android.getNum3()],
    ['Item 4',  Android.getNum4()],
    ['Item 5',  Android.getNum5()]
  ]);

  var options = {
    title: 'Android-er: Google Charts example of Column chart',
    hAxis: {title: 'Value', titleTextStyle: {color: 'red'}}
  };

  chart = new google.visualization.ColumnChart(document.getElementById('chart_div'));

  chart.draw(data, options);

}
    </script>
    
    <script type="text/javascript">
    function capture(){
     Android.captureCallback(chart.getImageURI());
    }
    </script>
    
  </head>
  <body>
    <div id="chart_div" style="width: 100%; height: 100%;"></div>
  </body>
</html>

bar_chart.html
<!--ref: https://google-developers.appspot.com/chart/interactive/docs/gallery/barchart-->
<html>
  <head>
    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
    <script type="text/javascript">
      google.load("visualization", "1", {packages:["corechart"]});
      google.setOnLoadCallback(drawChart);
      function drawChart() {
        var data = google.visualization.arrayToDataTable([
          ['Items', 'Value'],
          ['Item 1',  Android.getNum1()],
          ['Item 2',  Android.getNum2()],
          ['Item 3',  Android.getNum3()],
          ['Item 4',  Android.getNum4()],
          ['Item 5',  Android.getNum5()]
        ]);

        var options = {
          title: 'Android-er: Google Charts example of Bar chart',
          vAxis: {title: 'Value',  titleTextStyle: {color: 'red'}}
        };

        chart = new google.visualization.BarChart(document.getElementById('chart_div'));

        chart.draw(data, options);
      }
    </script>
    
    <script type="text/javascript">
    function capture(){
     Android.captureCallback(chart.getImageURI());
    }
    </script>
    
  </head>
  <body>
    <div id="chart_div" style="width: 100%; height: 100%;"></div>
  </body>
</html>

histogram.html
<!--ref: https://google-developers.appspot.com/chart/interactive/docs/gallery/histogram-->
<html>
  <head>
    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
    <script type="text/javascript">
      google.load("visualization", "1", {packages:["corechart"]});
      google.setOnLoadCallback(drawChart);
      function drawChart() {
        var data = google.visualization.arrayToDataTable([
          ['Items', 'Value'],
          ['Item 1', Android.getNum1()],
          ['Item 2', Android.getNum2()],
          ['Item 3', Android.getNum3()],
          ['Item 4', Android.getNum4()],
          ['Item 5', Android.getNum5()]]);

        var options = {
          title: 'Android-er: Google Charts example of Histogram',
          legend: { position: 'none' },
        };

        chart = new google.visualization.Histogram(document.getElementById('chart_div'));
        chart.draw(data, options);
      }
    </script>
    
    <script type="text/javascript">
    function capture(){
     Android.captureCallback(chart.getImageURI());
    }
    </script>
    
  </head>
  <body>
    <div id="chart_div" style="width: 100%; height: 100%;"></div>
  </body>
</html>

line_chart.html
<!--ref: https://google-developers.appspot.com/chart/interactive/docs/gallery/linechart-->
<html>
  <head>
    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
    <script type="text/javascript">
      google.load("visualization", "1", {packages:["corechart"]});
      google.setOnLoadCallback(drawChart);
      function drawChart() {
        var data = google.visualization.arrayToDataTable([
          ['Items', 'Value'],
          ['Item 1',  Android.getNum1()],
          ['Item 2',  Android.getNum2()],
          ['Item 3',  Android.getNum3()],
          ['Item 4',  Android.getNum4()],
          ['Item 5',  Android.getNum5()]
        ]);

        var options = {
          title: 'Android-er: Google Charts example of Line chart'
        };

        chart = new google.visualization.LineChart(document.getElementById('chart_div'));
        chart.draw(data, options);
      }
    </script>
    
    <script type="text/javascript">
    function capture(){
     Android.captureCallback(chart.getImageURI());
    }
    </script>
    
  </head>
  <body>
    <div id="chart_div" style="width: 100%; height: 100%;"></div>
  </body>
</html>

area_chart.html
<!--ref: https://google-developers.appspot.com/chart/interactive/docs/gallery/areachart-->
<html>
  <head>
    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
    <script type="text/javascript">
      google.load("visualization", "1", {packages:["corechart"]});
      google.setOnLoadCallback(drawChart);
      function drawChart() {
        var data = google.visualization.arrayToDataTable([
          ['Items', 'Value'],
          ['Item 1',  Android.getNum1()],
          ['Item 2',  Android.getNum2()],
          ['Item 3',  Android.getNum3()],
          ['Item 4',  Android.getNum4()],
          ['Item 5',  Android.getNum5()]
        ]);

        var options = {
          title: 'Android-er: Google Charts example of Area chart',
          hAxis: {title: 'Value',  titleTextStyle: {color: '#333'}},
          vAxis: {minValue: 0}
        };

        chart = new google.visualization.AreaChart(document.getElementById('chart_div'));
        chart.draw(data, options);
      }
    </script>
    
    <script type="text/javascript">
    function capture(){
     Android.captureCallback(chart.getImageURI());
    }
    </script>
    
  </head>
  <body>
    <div id="chart_div" style="width: 100%; height: 100%;"></div>
  </body>
</html>

download filesDownload the files.

No comments: