I am working on an android app and I want to take screenshot of a visible area of horizontalscrollview. I am using below code for that :-
public Bitmap screenShot(View view) {
/*Rect rect = new Rect(0, 0,
mDiviceWidth , view.getHeight());*/
/*Rect rect = new Rect(view.getScrollX(), 0,
view.getScrollX() + mDiviceWidth , view.getHeight());*/
Rect scrollBounds = new Rect();
// view.getHitRect(scrollBounds);
// view.getDrawingRect(scrollBounds);
// view.getLocalVisibleRect(scrollBounds);
// view.getGlobalVisibleRect(scrollBounds);
view.getWindowVisibleDisplayFrame(scrollBounds);
Log.e("X Scrolled", ""+view.getScrollX());
Log.e("left", ""+scrollBounds.left);
Log.e("right", ""+scrollBounds.right);
Log.e("top", ""+scrollBounds.top);
Log.e("bottom", ""+scrollBounds.bottom);
/*view.setDrawingCacheEnabled(true);
Bitmap bitmap = view.getDrawingCache();*/
Bitmap bitmap = Bitmap.createBitmap(view.getWidth(),
view.getHeight(), Config.ARGB_8888);
/*float left,right,top,bottom;
left = view.getLeft();
right = mDiviceWidth;
top = 0;
bottom = view.getHeight();*/
Canvas canvas = new Canvas(bitmap);
// canvas.clipRect(left, top,
// right , bottom);
canvas.clipRect(scrollBounds);
view.draw(canvas);
// view.setDrawingCacheEnabled(false);
return bitmap;
}
Above code is taking the screenshot but returning wrong area. Some times it captures visible area but sometimes it captures the random area which is not visible or partial visible. I have already used
// view.getHitRect(scrollBounds);
// view.getDrawingRect(scrollBounds);
// view.getLocalVisibleRect(scrollBounds);
// view.getGlobalVisibleRect(scrollBounds);
methods but not getting the perfect result.
So please help me to resolve this issue.
Use this function:
private static Bitmap takeScreenShot(Activity activity) {
View view = activity.getWindow().getDecorView();
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
Bitmap b1 = view.getDrawingCache();
Rect frame = new Rect();
activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
int statusBarHeight = frame.top;
int width = activity.getWindowManager().getDefaultDisplay().getWidth();
int height = activity.getWindowManager().getDefaultDisplay().getHeight();
Bitmap b = Bitmap.createBitmap(b1, 0, statusBarHeight, width, height - statusBarHeight);
view.destroyDrawingCache();
return b;
}
We have a problem to generate a bitmap from a particular view. The restriction is that it can not be rendered view (drawing). Does anyone have any tips how to solve this?
The documentation of the class view (http://developer.android.com/reference/android/view/View.html) has some explanation of the steps used by Android to render a View. In the case, we would get in step "layout", but not in the "drawing". Anyone who has any idea, could show an example?
My code is generating the exception:
error -> width and height must be> 0
...
public static Bitmap loadBitmapFromView(View v) {
Bitmap b = null;
try {
b = Bitmap.createBitmap(
v.getWidth(),
v.getHeight(),
Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
v.measure(v.getWidth(), v.getHeight());
v.layout(0, 0, v.getWidth(), v.getHeight());
v.draw(c);
} catch (Exception e) {
Log.e(MainActivity.TAG, "error -> "+e.getMessage());
}
return b;
}
public void snap(View v) {
LayoutInflater inflate = (LayoutInflater) getBaseContext()
.getSystemService(LAYOUT_INFLATER_SERVICE);
View view = new View(getBaseContext());
view = inflate.inflate(R.layout.list_item, null);
Log.d(MainActivity.TAG, "getWidth -> "+view.getWidth());
Log.d(MainActivity.TAG, "getHeight -> "+view.getHeight());
Bitmap b = loadBitmapFromView(view);
if (b != null) {
LinearLayout mainLayout = (LinearLayout) findViewById(R.id.LinearLayout1);
ImageView image = new ImageView(this);
image.setImageBitmap(b);
mainLayout.addView(image);
}
}
I found the solution this way:
public static Bitmap getScreenViewBitmap(final View v) {
v.setDrawingCacheEnabled(true);
v.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());
v.buildDrawingCache(true);
Bitmap b = Bitmap.createBitmap(v.getDrawingCache());
v.setDrawingCacheEnabled(false); // clear drawing cache
return b;
}
You're immediately trying to get the width and height of the view after inflation, but the View doesn't have a size until after it's been laid out. You can either determine a size for it yourself (call measure() with whatever MeasureSpec is appropriate) or have it as part of a layout, set to Invisible, and only try to load the Bitmap from the View after it has been laid out.
hello guys i'm trying to get an image(Frame from resources) to overlay it over the original bitmap. so far i couldn't make my Bitmap goes into the frame as the frame always empty. the original bitmap is now showing inside the frame.
here is my code that i'm using to accomplish this.
Canvas canvas = new Canvas();
Bitmap border = null;
Bitmap scaledBorder = null;
border = BitmapFactory.decodeResource(getResources(), R.drawable.frame1);
int width = bmp.getWidth();
int height = bmp.getHeight();
scaledBorder = Bitmap.createScaledBitmap(border,width,height, false);
canvas.drawBitmap(scaledBorder, 0, 0, new Paint());
view.setImageBitmap(scaledBorder);
bmp as my original Bitmap from Gallery or Camera. i can't find away to put them together. only the frame will appear but not the bmp.
thanks in advance.
thanks man i figured it out by own. using this
void hm1(){
Bitmap border = BitmapFactory.decodeResource(getResources(), R.drawable.vignette2);
int width = bmp.getWidth();
int height = bmp.getHeight();
change = Bitmap.createScaledBitmap(change, width, height, false);
Canvas canvas = new Canvas(change);
Bitmap scaledBorder = Bitmap.createScaledBitmap(border,width,height, false);
canvas.drawBitmap(scaledBorder, 0, 0,null);
//canvas.drawBitmap(k, 0, 0, null);
view.setImageBitmap(change);
}
by adding this method on any click button , menu etc you can draw two bitmaps over each other.
P.S : Bitmap change is another bitmap from the original one as i don't want the user to apply the Overlay on the original method but on the changed one.
hope the answer helps someone. thanks
Bottom line, first you need to add your original image to the canvas, then the border, then place the canvas on the view. Your best bet is to do this in an onDraw() method. Something like this should work:
#Override
void onDraw (Canvas canvas)
{
canvas.drawBitmap(bmp,0,0,new Paint())
Bitmap border = null;
Bitmap scaledBorder = null;
border = BitmapFactory.decodeResource(getResources(), R.drawable.frame1);
int width = bmp.getWidth();
int height = bmp.getHeight();
scaledBorder = Bitmap.createScaledBitmap(border,width,height, false);
canvas.drawBitmap(scaledBorder, 0, 0, new Paint());
}
Alternatively, you could call the draw() function from the view.
canvas.drawBitmap(bmp,0,0,new Paint())
Bitmap border = null;
Bitmap scaledBorder = null;
border = BitmapFactory.decodeResource(getResources(), R.drawable.frame1);
int width = bmp.getWidth();
int height = bmp.getHeight();
scaledBorder = Bitmap.createScaledBitmap(border,width,height, false);
canvas.drawBitmap(scaledBorder, 0, 0, new Paint());
view.draw(canvas);
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Converting a view to Bitmap without displaying it in Android?
I am trying to convert the view into bitmap from following reference link
link text
Now the problem is how can i get the bitmap that is being converted from view only. in the example author has used relativelayout.dispatchDraw(c) but this line is giving me compile time error i.e.
The method dispatchDraw(Canvas) from
the type ViewGroup is not visible
Here is my code and i have written the following code inside onCreate function
Canvas c=null;
//Create Layout
RelativeLayout relativeView ;
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT
);
relativeView = new RelativeLayout(this);
relativeView.setLayoutParams(lp);
//Background of Layout
Bitmap viewBgrnd = BitmapFactory.decodeResource(getResources(),R.drawable.bgblack);
relativeView.setBackgroundDrawable(new BitmapDrawable(viewBgrnd));
//associated with canvas
Bitmap returnedBitmap = Bitmap.createBitmap(320,480,Bitmap.Config.ARGB_8888);
c = new Canvas(returnedBitmap);
Paint paint = new Paint();
//Create Imageview that holds image
ImageView newImage = new ImageView(this);
Bitmap srcBitmap = BitmapFactory.decodeResource(getResources(),R.drawable.bgpink);
newImage.setImageBitmap(srcBitmap);
TextView newText = new TextView(this);
newText.setText("This is the text that its going to appear");
c.drawBitmap(viewBgrnd, 0, 0, paint);
relativeView.layout(100, 0, 256, 256);
relativeView.addView(newImage);
relativeView.addView(newText);
// here i am getting compile time error so for timing i have replaced this line
// with relativeView.draw(c);
relativeView.dispatchDraw(c);
Here the returnedBitmap should contain the image of (ImageView and TextView) but this bitmap contains only bacground bitmap of relativeView i.e. bgblack
here is my solution:
public static Bitmap getBitmapFromView(View view) {
Bitmap returnedBitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(),Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(returnedBitmap);
Drawable bgDrawable =view.getBackground();
if (bgDrawable!=null)
bgDrawable.draw(canvas);
else
canvas.drawColor(Color.WHITE);
view.draw(canvas);
return returnedBitmap;
}
Enjoy :)
This works for me:
Bitmap viewCapture = null;
theViewYouWantToCapture.setDrawingCacheEnabled(true);
viewCapture = Bitmap.createBitmap(theViewYouWantToCapture.getDrawingCache());
theViewYouWantToCapture.setDrawingCacheEnabled(false);
I believe the view has to be visible (ie. getVisiblity() == View.VISIBLE). If you are trying to capture it but hide it to the user at the same time, you could move it off screen or put something over it.
I will try to explain what exactly I need to do.
I have 3 separate screens say A,B,C. There is another screen called say HomeScreen where all the 3 screens bitmap should be displayed in Gallery view and the user can select in which view does he wants to go.
I have been able to get the Bitmaps of all the 3 screens and display it in Gallery view by placing all the code in HomeScreen Activity only. Now, this has complicated the code a lot and I will like to simplify it.
So, can I call another Activity from HomeScreen and do not display it and just get the Bitmap of that screen. For example, say I just call HomeScreen and it calls Activity A,B,C and none of the Activities from A,B,C are displayed. It just gives the Bitmap of that screen by getDrawingCache(). And then we can display those bitmaps in Gallery view in HomeScreen.
I hope I have explained the problem very clearly.
Please let me know if this is actually possible.
there is a way to do this. you have to create a Bitmap and a Canvas and call view.draw(canvas);
here is the code:
public static Bitmap loadBitmapFromView(View v) {
Bitmap b = Bitmap.createBitmap( v.getLayoutParams().width, v.getLayoutParams().height, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
v.layout(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
v.draw(c);
return b;
}
if the view wasn't displayed before the size of it will be zero. Its possible to measure it like this:
if (v.getMeasuredHeight() <= 0) {
v.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
Bitmap b = Bitmap.createBitmap(v.getMeasuredWidth(), v.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());
v.draw(c);
return b;
}
EDIT: according to this post, Passing WRAP_CONTENT as value to makeMeasureSpec() doesn't to do any good (although for some view classes it does work), and the recommended method is:
// Either this
int specWidth = MeasureSpec.makeMeasureSpec(parentWidth, MeasureSpec.AT_MOST);
// Or this
int specWidth = MeasureSpec.makeMeasureSpec(0 /* any */, MeasureSpec.UNSPECIFIED);
view.measure(specWidth, specWidth);
int questionWidth = view.getMeasuredWidth();
here is my solution:
public static Bitmap getBitmapFromView(View view) {
Bitmap returnedBitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(),Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(returnedBitmap);
Drawable bgDrawable =view.getBackground();
if (bgDrawable!=null)
bgDrawable.draw(canvas);
else
canvas.drawColor(Color.WHITE);
view.draw(canvas);
return returnedBitmap;
}
Enjoy :)
I know this may be a stale issue, but I was having problems getting any of these solutions to work for me.
Specifically, I found that if any changes were made to the view after it was inflated that those changes would not get incorporated into the rendered bitmap.
Here's the method which ended up working for my case. With one caveat, however. prior to calling getViewBitmap(View) I inflated my view and asked it to layout with known dimensions. This was needed since my view layout would make it zero height/width until content was placed inside.
View view = LayoutInflater.from(context).inflate(layoutID, null);
//Do some stuff to the view, like add an ImageView, etc.
view.layout(0, 0, width, height);
Bitmap getViewBitmap(View view)
{
//Get the dimensions of the view so we can re-layout the view at its current size
//and create a bitmap of the same size
int width = view.getWidth();
int height = view.getHeight();
int measuredWidth = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY);
int measuredHeight = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY);
//Cause the view to re-layout
view.measure(measuredWidth, measuredHeight);
view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
//Create a bitmap backed Canvas to draw the view into
Bitmap b = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
//Now that the view is laid out and we have a canvas, ask the view to draw itself into the canvas
view.draw(c);
return b;
}
The "magic sauce" for me was found here:
https://groups.google.com/forum/#!topic/android-developers/BxIBAOeTA1Q
Cheers,
Levi
Try this,
/**
* Draw the view into a bitmap.
*/
public static Bitmap getViewBitmap(View v) {
v.clearFocus();
v.setPressed(false);
boolean willNotCache = v.willNotCacheDrawing();
v.setWillNotCacheDrawing(false);
// Reset the drawing cache background color to fully transparent
// for the duration of this operation
int color = v.getDrawingCacheBackgroundColor();
v.setDrawingCacheBackgroundColor(0);
if (color != 0) {
v.destroyDrawingCache();
}
v.buildDrawingCache();
Bitmap cacheBitmap = v.getDrawingCache();
if (cacheBitmap == null) {
Log.e(TAG, "failed getViewBitmap(" + v + ")", new RuntimeException());
return null;
}
Bitmap bitmap = Bitmap.createBitmap(cacheBitmap);
// Restore the view
v.destroyDrawingCache();
v.setWillNotCacheDrawing(willNotCache);
v.setDrawingCacheBackgroundColor(color);
return bitmap;
}
There is a great Kotlin extension function in Android KTX: View.drawToBitmap(Bitmap.Config)
Layout or view to bitmap:
private Bitmap createBitmapFromLayout(View tv) {
int spec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
tv.measure(spec, spec);
tv.layout(0, 0, tv.getMeasuredWidth(), tv.getMeasuredHeight());
Bitmap b = Bitmap.createBitmap(tv.getMeasuredWidth(), tv.getMeasuredWidth(),
Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
c.translate((-tv.getScrollX()), (-tv.getScrollY()));
tv.draw(c);
return b;
}
Calling Method:
Bitmap src = createBitmapFromLayout(View.inflate(this, R.layout.sample, null)/* or pass your view object*/);
I think this is a bit better :
/**
* draws the view's content to a bitmap. code initially based on :
* http://nadavfima.com/android-snippet-inflate-a-layout-draw-to-a-bitmap/
*/
#Nullable
public static Bitmap drawToBitmap(final View viewToDrawFrom, int width, int height) {
boolean wasDrawingCacheEnabled = viewToDrawFrom.isDrawingCacheEnabled();
if (!wasDrawingCacheEnabled)
viewToDrawFrom.setDrawingCacheEnabled(true);
if (width <= 0 || height <= 0) {
if (viewToDrawFrom.getWidth() <= 0 || viewToDrawFrom.getHeight() <= 0) {
viewToDrawFrom.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
width = viewToDrawFrom.getMeasuredWidth();
height = viewToDrawFrom.getMeasuredHeight();
}
if (width <= 0 || height <= 0) {
final Bitmap bmp = viewToDrawFrom.getDrawingCache();
final Bitmap result = bmp == null ? null : Bitmap.createBitmap(bmp);
if (!wasDrawingCacheEnabled)
viewToDrawFrom.setDrawingCacheEnabled(false);
return result;
}
viewToDrawFrom.layout(0, 0, width, height);
} else {
viewToDrawFrom.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
viewToDrawFrom.layout(0, 0, viewToDrawFrom.getMeasuredWidth(), viewToDrawFrom.getMeasuredHeight());
}
final Bitmap drawingCache = viewToDrawFrom.getDrawingCache();
final Bitmap bmp = ThumbnailUtils.extractThumbnail(drawingCache, width, height);
final Bitmap result = bmp == null || bmp != drawingCache ? bmp : Bitmap.createBitmap(bmp);
if (!wasDrawingCacheEnabled)
viewToDrawFrom.setDrawingCacheEnabled(false);
return result;
}
Using the above code, you don't have to specify the size of the bitmap (use 0 for width&height) if you want to use the one of the view itself.
Also, if you wish to convert special views (SurfaceView, Surface or Window, for example) to a bitmap, you should consider using PixelCopy class instead. It requires API 24 and above though. I don't know how to do it before.
Hope this helps
View view="some view instance";
view.setDrawingCacheEnabled(true);
Bitmap bitmap=view.getDrawingCache();
view.setDrawingCacheEnabled(false);
Update
getDrawingCache() method is deprecated in API level 28. So look for other alternative for API level > 28.
I used this just a few days ago:
fun generateBitmapFromView(view: View): Bitmap {
val specWidth = View.MeasureSpec.makeMeasureSpec(1324, View.MeasureSpec.AT_MOST)
val specHeight = View.MeasureSpec.makeMeasureSpec(521, View.MeasureSpec.AT_MOST)
view.measure(specWidth, specHeight)
val width = view.measuredWidth
val height = view.measuredHeight
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
view.layout(view.left, view.top, view.right, view.bottom)
view.draw(canvas)
return bitmap
}
This code is based in this gist
I had a similar need and developed something based on codes provided, specially the one by #Azhagthott and the brand new androidx.core.view.drawToBitmap, hopefully this will be hopeful here also,
val view = MyCustomView(context)
view.measure(
View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.AT_MOST),
View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.AT_MOST)
)
view.layout(0, 0, width, height)
val bitmap = view.drawToBitmap()
private fun getBitmapFromView(view: View): Bitmap
{
val returnedBitmap = Bitmap.createBitmap(view.width,
view.height
,Bitmap.Config.ARGB_8888)
val canvas = Canvas(returnedBitmap)
//background image
val bgDrawable = view.background
//background image is selected
if (bgDrawable != null){
bgDrawable.draw(canvas)
}
else{
canvas.drawColor(Color.WHITE)
}
view.draw(canvas)
return returnedBitmap
}
I had the same problem in my project and found a solution, which I will describe here.
public Bitmap catchBitmapFromView(View capture_view){
if (capture_view == null) {
return null;
}
capture_view.setDrawingCacheEnabled(true);
Bitmap bitmap = Bitmap.createBitmap(capture_view.getWidth(), capture_view.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
Drawable bgDrawable = capture_view.getBackground();
if (bgDrawable != null) {
bgDrawable.draw(canvas);
} else {
canvas.drawColor(Color.WHITE);
}
capture_view.draw(canvas);
capture_view.setDrawingCacheEnabled(false);
return bitmap;
}
view.setDrawingCacheEnabled(true);
Bitmap bitmap = Bitmap.createBitmap(view.getDrawingCache());
view.setDrawingCacheEnabled(false);