6

PROBLEM DESCRIPTION:
I have tested the following two methods, in order to create a bitmap snaphot from a View (e.g. a RelativeLayout in this case). Both methods work excellent for Views which dimensions (e.g. width and height) are less than the dimensions of the device screen (e.g. 480x900). The visible part of the View is captured and written into the bitmap. Unfortunately, the bitmap is black in the unvisible part of the View.

QUESTION:
How can I capture also the unvisible part of the View ?

CODE:

public class NewRelativeLayout extends RelativeLayout{

private Bitmap bmp;

public NewRelativeLayout(Context context){
    super(context);
    this.setLayoutParams(new RelativeLayout.LayoutParams(2000,2000));
    // add here methods to configure the RelativeLayout or to add children
    }

//This is the first method
public void makeSnapshot_Method1(){
    this.setDrawingCacheEnabled(true);   
    bmp = Bitmap.createBitmap(this.getDrawingCache());   
    this.setDrawingCacheEnabled(false);
    }

//This is the second method
public void makeSnapshot_Method2(){
    bmp = Bitmap.createBitmap(2000, 2000, Bitmap.Config.ARGB_8888);
    Canvas helpCanvas = new Canvas(bmp);
    this.draw(helpCanvas);
    }

}

Aleks G
  • 56,435
  • 29
  • 168
  • 265
Anne Droid
  • 3,151
  • 4
  • 16
  • 15

3 Answers3

1

I was searching for the solution to this too and, in the end, managed to come up with my own solution which is actually quite simple.

In my case, I had a LinearLayout which contained a number of View elements, some of which sometimes were not on screen, vertically below the end of the screen bounds. I was able to save the View as a Bitmap (see loadBitmapFromView(), below) but had trouble when it extended beyond the bottom of the screen.

My solution was to make the LinearLayout part of a ScrollView composite.

e.g.

This:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/my_linear_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
 >
<!-- Some Views added here at runtime -->
</LinearLayout>

Became:

Note use of wrap_content to ensure ScrollView scales to the height of your content.

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/scroll"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" 
    >

    <LinearLayout
        android:id="@+id/my_linear_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
     >
        <!-- Some Views added here at runtime -->
    </LinearLayout>
</ScrollView>

This seemed to ensure that the offscreen items could be manually laid out when I wanted to save the View as a bitmap. I used the following method to save the bitmap. I found this much earlier on SO but I can't seem to find the question in order to reference it properly (whoever you are - thank you!).

For the following method, I pass in a reference to the LinearLayout above (my_linear_layout).

public static Bitmap loadBitmapFromView(View view) {
    Bitmap bitmap = null;

    // width measure spec
    int widthSpec = View.MeasureSpec.makeMeasureSpec(
            view.getMeasuredWidth(), View.MeasureSpec.AT_MOST);
    // height measure spec
    int heightSpec = View.MeasureSpec.makeMeasureSpec(
            view.getMeasuredHeight(), View.MeasureSpec.AT_MOST);

    // measure the view
    view.measure(widthSpec, heightSpec);

    // set the layout sizes
    int left = view.getLeft();
    int top = view.getTop();
    int width = view.getMeasuredWidth();
    int height = view.getMeasuredHeight();
    int scrollX = view.getScrollX();
    int scrollY = view.getScrollY();

    view.layout(left, top, width + left, height + top);

    // create the bitmap

    bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(),
            Bitmap.Config.ARGB_8888);

    // create a canvas used to get the view's image and draw it on the
    // bitmap

    Canvas c = new Canvas(bitmap);
    // position the image inside the canvas
    c.translate(-view.getScrollX(), -view.getScrollY());
    // get the canvas
    view.draw(c);

    return bitmap;
}
aoemerson
  • 147
  • 9
0

Depends upon which image you want to capture, the image from view's background or foreground. Either way you have to get the Drawable object from them, cast them to BitmapDrawable and get the Bitmap from their. Code:-

BitmapDrawable bd=(BitmapDrawable) view.getBackground(); //if you need background image
BitmapDrawable bd=(BitmapDrawable) view.getDrawable(); //if you need foreground image (Only available to some views who have an android:src xml property)
Bitmap bm=bd.getBitmap();

I hope this will work for you.

0xC0DED00D
  • 19,522
  • 20
  • 117
  • 184
  • Thanks Creator for your fast response. The view.getDrawable() method is supported only by Views, which "hold" a foreground picture inside like the ImageView for instance. All other Views like RelativeLayouts, LinearLayouts, TextViews etc. do not support this method. Most internet forums recommend method 1 or 2 (see my post) in order to make a bitmap screenshot (i.e. background plus foreground) from a View. The problem is still unsolved for oversized Views. Any other ideas ? – Anne Droid Feb 15 '12 at 18:54
  • Well, I've already mentioned that view.getDrawable() is not supported by every view in the post itself. Those two methods gives the complete image, including the off-screen parts, may be you can try putting those two separate images in a single view (if the forground one is a transparent background png image) using canvas and custom view and get the drawable from there, although I never tried that, so can't tell how this will work, but if you could follow that you might achieve what you need. – 0xC0DED00D Feb 15 '12 at 19:15
  • The getDrawingCache() method is intended to give only the on-screen image only, so I don't think that will work for you. Using getDrawingCache(true) might work for you. Another idea could be to resize the view using LayoutParams to to fit the screen and then get the drawing cache from there. – 0xC0DED00D Feb 15 '12 at 19:19
0

I'm also trying to figure this out for a ListView, to get all rows that are not on screen.

I have found lots of things I would like to share:

Here someone asks if a bitmap can be created from a view that's not drawn: Bitmap from View not displayed on Android

Here they claim it's a duplicate and it's also answered correctly (?) It contains a URL with some coding that's old and doesn't compile. Also the possible duplicate question didn't help me. Android get full View as Bitmap

I think I will try to get it done via this method: List View using bitmap Already came up with the same idea, now I still have to discover how.

Hope you can use some of this info.

Community
  • 1
  • 1
Dante
  • 1,104
  • 1
  • 10
  • 15