Image of MapView

2398
6
01-28-2013 04:56 AM
GregMilette
New Contributor II
How do I get an image of the MapView?

I have a MapView object, with a few graphics layers on it, and I would like to export a .png or some other image format.

Is there some way to accomplish this?
6 Replies
AndyGup
Esri Regular Contributor
Greg,

Give this a try. It's some test code I wrote that shows how to create an image of the MapView and then store it locally on the device. Note, I've only tested this using the ArcGIS Runtime for Android SDK v10.1.1 and on a 4.0.x device. I'm not 100% certain it will run on a 2.x or 3.x device.

private void createMapViewImage(){ 

 final Runnable runnable = new Runnable() {
  int counter = 0;
  
  @Override
  public void run() {
   counter++;
   try{ 
    final Handler handler = new Handler(); 
    //Use 0, 0 for x/y so that you capture the entire MapView
    final Bitmap bitmap = mMapView.getDrawingMapCache(0, 0,
      mMapView.getWidth(), mMapView.getHeight());  
    
    Log.d("TEST", "Map Width = " + mMapView.getWidth() + " Map Height = "
     + mMapView.getHeight());        
    
    Log.d("TEST","Testing if able to create mapView bitmap. Attempt #" + counter);
    
    if(bitmap != null){

     Log.d("TEST","mapView bitmap has been successfully created.");
     
     final File dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);
     final File output = new File(dir, "mapview.png");
     final String imagePath = output.getAbsolutePath();
     FileOutputStream fileOut;
     
     try{
      fileOut = new FileOutputStream(output);
      bitmap.compress(Bitmap.CompressFormat.PNG, 100, fileOut);
      fileOut.flush();
      fileOut.close();
      bitmap.recycle();
     }catch(Exception e){
      e.printStackTrace();
     }    
     
     handler.post(mUpdateResults);
               
    }
    else if(counter < 5){

     handler.postDelayed(this, 2000);
    }
    else{
     Log.d("TEST","Unable to create mapView bitmap after 5 attempts.");
    }
   }
   catch(Exception exc){
    Log.d("TEST","Unable to create mapView exception: " + exc.toString());
   }
  
  }
 };
 
 runnable.run();

}

final Runnable mUpdateResults = new Runnable() {
 
 @Override
 public void run() { 
  doSomething();  
 }
};

private void doSomething(){
 final File dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM + "/mapview.png");
 //You are now back on the UI thread and have access to the image file .
}
0 Kudos
GregMilette
New Contributor II
it worked, Do you know why the code needs to retry in a loop? is getDrawingMapCache asyncronous?

I ended up doing a simple loop with a sleep and screenShotOf contains the actual doing of the screenshot

        int MAX_TRIES = 5;

        int tries = 0;
        Log.d(TAG, tries + " screenshot to: " + bitmapPath);
        result = screenShotOf(v, bitmapPath);
        while (result == null && tries < MAX_TRIES)
        {
            tries++;
            try
            {
                Thread.sleep(500);
            }
            catch (InterruptedException e)
            {
                Log.d(TAG, "interrupted");
            }
            Log.d(TAG, tries + " screenshot to: " + bitmapPath);
            result = screenShotOf(v, bitmapPath);
        }
0 Kudos
AndyGup
Esri Regular Contributor
It has a retry loop because you can get null values when calling getDrawingMapCache. I'm not exactly sure why, and it could very well be device dependent. I noticed it on both 2.3 and 4.x phones. The null value is typically the first try, and then on the second try after waiting a few seconds you should be able to get the cache.

Just a note, in your psuedo-code below, the while loop itself looks like it runs on the UI thread which could cause laggy behavior of the map. You may have already done this in your code, so for other readers the recommended practice is to place while loops inside a Runnable(){public void run(){while...}}. Just a suggestion 🙂

-Andy


Here's some references:

Another forum post on getDrawingMapCache null values.

Handling expensive operations on the UI thread.
0 Kudos
AndyGup
Esri Regular Contributor
Slightly modified the code above. I noticed that for some reason sometimes the PNG file isn't created properly and it has a size of 0 bytes. So I added a check that verifies the width of the PNG > 0.

private void createMapViewImage(){ 

 final Runnable runnable = new Runnable() {
  int counter = 0;
  
  @Override
  public void run() {
   counter++;
   try{ 
    final Handler handler = new Handler(); 
    //Use 0, 0 for x/y so that you capture the entire MapView
    final Bitmap bitmap = mMapView.getDrawingMapCache(0, 0,
      mMapView.getWidth(), mMapView.getHeight());  
    
    Log.d("TEST", "Map Width = " + mMapView.getWidth() + " Map Height = "
     + mMapView.getHeight());        
    
    Log.d("TEST","Testing if able to create mapView bitmap. Attempt #" + counter);
    
    if(bitmap != null){

     final File dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);
     final File output = new File(dir, "mapview.png");
     final String imagePath = output.getAbsolutePath();
     FileOutputStream fileOut;
     
     try{
      fileOut = new FileOutputStream(output);
      bitmap.compress(Bitmap.CompressFormat.PNG, 100, fileOut);
      int w = bitmap.getWidth();
      if(w > 0){
       fileOut.flush();
       fileOut.close();
       bitmap.recycle();
       handler.post(mUpdateResults);
       Log.d("TEST","mapView bitmap has been successfully created.");        
      }
      else if(counter < 5){
       Log.d("TEST","PNG didn't create properly so trying again.");
       handler.postDelayed(this, 1000);
      }
      else{
       Log.d("TEST","Unable to create PNG.");
      }
     }catch(Exception e){
      e.printStackTrace();
     }    
               
    }
    else if(counter < 5){

     handler.postDelayed(this, 2000);
    }
    else{
     Log.d("TEST","Unable to create mapView bitmap after 5 attempts.");
    }
   }
   catch(Exception exc){
    Log.d("TEST","Unable to create mapView exception: " + exc.toString());
   }
  
  }
 };
 
 runnable.run();

}


final Runnable mUpdateResults = new Runnable() {
 
 @Override
 public void run() { 
  doSomething();
 }
};

private void doSomething(){
 final File dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM + "/mapview.png");
 //TO-DO
}
0 Kudos
BlakeEdwards
New Contributor II

Thank you, this works for me. However, it takes some time to produce the image. I am trying to perform the operation at a fast rate and it is introducing lag into my application. Is there any way to perform this method of turning the map view into an image so that it does not decrease the performance of my application? As in, it allows other operations to continue while multiple screenshots or generated, etc.

0 Kudos
AndyGup
Esri Regular Contributor

Blake, in the latest Android Runtime there is a method you might try: GeoView (ArcGIS Runtime SDK for Android 100.5.0). FYI, I haven't used the method since I haven't been working on Runtime in quite some time so I won't be able to answer any questions about it.

0 Kudos