Way to take screenshot of view faster - android

In my app I show all errors by taking a screenshot, grayscaling it, and adding error text on it. This is how I take screenshot:
private Bitmap getBitmapFromView(View v) {
Bitmap bitmap = Bitmap.createBitmap(v.getWidth(), v.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
v.draw(canvas);
return bitmap;
}
final ViewGroup root = (ViewGroup) getWindow().getDecorView();
Bitmap bitmap = getBitmapFromView(root);
And then convert bitmap to grayscale, add a text and show.
My problem is that getBitmapFromView on some devices (Galaxy S5 unexpected btw) takes 500-700 ms to complete. My question is if there is any faster way to take screenshot of the view, or of entire screen? I have tried View.getDrawingCache(), and it's the same slow. If I'm right, then it works the same way as my getBitmapFromView method.
EDIT:
Ok, I figured out what caused so slow performance using Android Monitor and method profiling in my case. It was the GradientDrawable taking 80% of time to draw. I have optimized it, and it now takes about 150 ms. to take screenshot. But the question stays the same: Is there any faster way to do it? Maybe using NDK?

Your custome view here
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
this.buildDrawingCache();
}
To get your CacheBitmap just
view.getDrawingCache();
This works for me ,i can get the CacheBitmap immediately
But it's a bad ideal that may cause some performance problems

Related

Android Draw Bitmap to Canvas

I'm trying to draw a Bitmap to a Canvas in a custom SurfaceView, but it doesn't show up anywhere.
In the SurfaceView, I'm using:
//in the constructor
Bitmap leftUp = BitmapFactory.decodeResources(R.drawable.leftup);
leftCurrent = leftUp; //it's a button - leftUp and leftDown
//in my drawing method
canvas.drawBitmap(leftCurrent, controlsWidth, controlsHeight, new Paint());
It runs OK, no errors, but nothing shows up. Anyone have any ideas?
The problem is with you paint object that you pass to the drawBitmap method. It must be configured properly. Take a look at this
answer.

Canvas Optimization

I am drawing multiple text on the canvas in my app. For two text its working fine but drawing multiple text/bitmap at the same times it's a big headache for everyone.it takes all GPU process and it hangs at some point of time especially when you draw large bitmap/text.
Is there any way to save previous drawn things to single bitmap?
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (CustomTextview.GetDB().size() != 0) {
for (CustomTextview textview : CustomTextview.GetDB()) {
Bitmap b= drawasbitmap(textview.text,textview.X,textview,Y) //creating a bitmap for view
canvas.drawBitmap(b, textview.X, textview.Y, textview.paint);
b.recycle();
}
canvas.restore();
}
}
Lets say i have 5 bitmaps/text in my app.it should draw 5 text at the same time.
If it's 5 bitmap the memory will go away,is there any way to save all previous view (Bitmap-which is drawn before adding the new one )to one Bitmap ,or can i use drawing cache?
P.S- i have multiple views in my app- i want to draw the recent one for editing purpose .everthing should be saved to temp bitmap and shown to use that views are out there.when ever user clicks that particular region that view get selected called in onDraw

Android: Rotating large image crashes without throwing an error

I have searched and found simple code to rotate an image. I am pulling the image out of an ImageView object into a bitmap, rotating it then putting it back. I realize this is not the most effective method but I don't think it should crash without giving an error message in the CATCH block.
Here is my code. The only value passed in is "r" or "l" depending on which direction I want to rotate. Smaler images (1500x1500 or smaller) work just fine. Things go bad around the 2500x2500 size.
public void rotate(String dir)
{
try
{
float angle = (dir.equals("r") ? 90 : -90);
Bitmap bitmap = ((BitmapDrawable) imageView.getDrawable()).getBitmap();
Matrix matrix = new Matrix();
matrix.reset();
matrix.postRotate(angle);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false);
imageView.setImageBitmap(bitmap);
}
catch(Exception e)
{
Utilities.logError(e.toString());
}
}
Any clue as to why it is crashing and why it doesn't thow an exception? I just get a message "Unfortuantly process .... has stopped" and I get kicked back to the welcome screen of my app.
Oh, for kicks I set the angle to ZERO (hard coded) and it didn't crash. I suspect that it is just taking too long to rotate and Android is having a fit. But I am not sure how to confirm that as the problem or how to tell Android to wait a little longer.
Even if I reduce the preview image for the rotation, when I go to save I will have to rotate the full size image at least once and will hit this same issue. Won't I?
I can more or less guarantee without looking at the logs that you're getting an Out Of Memory Exception.
You need to use smaller images, or use a different method to rotate that doesn't use up so much memory (you're allocating 2 2500x2500 bitmaps at the same time here! that's tons!).
Try using a RotateAnimation to get your effect instead.
Hope this helps :)

OutOfMemoryError: Android large Bitmap rotation (90°)

I have a big Memory Problem:
// in sourceImage is a big JPEG previously loaded
Matrix mat = new Matrix();
mat.postRotate(90);
Bitmap rotatedImage = Bitmap.createBitmap(sourceImage, 0, 0, sourceImage.getWidth(), sourceImage.getHeight(), mat, true);
Always i Run this code, my App crashes and says "VM won't let us allocate xxxxxx bytes"
Can you help me?
Edit:
I saw much similar questions here, but i don't know how to recycle the sourceImage before rotatating it... (cause the second instance is to big to hold it at the same time)
Thanks.
You can't create a new rotated bitmap without holding temporary 2 bitmaps in memory.
But you can display the bitmap rotated without creating a new bitmap (apply a transformation).
ImageView does not come with rotation capabilities, so you should write your own extended version of ImageView (RotatedImageView?).
The idea is to override the onDraw method with something like this (not tested).
#Override
public void onDraw(Canvas canvas) {
canvas.rotate((int)(angle * 180 / Math.PI), getWidth() >> 1, getHeight() >> 1);
super.onDraw(canvas);
}
For others like me:
there's an option to have the camera perform the rotation,
https://stackoverflow.com/a/16010289/755804

Android 2.1 View's getDrawingCache() method always returns null

I'm working with Android 2.1 and have the following problem:
Using the method View.getDrawingCache() always returns null. getDrawingCache() should return a Bitmap, which is the presentation of View's content.
Example code:
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final View view = findViewById(R.id.ImageView01);
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
final Bitmap bmp = view.getDrawingCache();
System.out.println(bmp);
}
I've already tried different ways to configure the View object for generating the drawing cache (e.g. View.setWillNotDraw(boolean) and View.setWillNotCacheDrawing(boolean)), but nothing works.
What is the right way, or what I'm doing wrong?
PS: In real code I want to apply getDrawingCache() on a ViewGroup like RelativeLayout. Is the behaviour the same when using a ViewGroup?
Bitmap screenshot;
view.setDrawingCacheEnabled(true);
screenshot = Bitmap.createBitmap(view.getDrawingCache());
view.setDrawingCacheEnabled(false);
You need Bitmap.createBitmap(view.getDrawingCache()); as the Bitmap from which the reference is received by getDrawingCache() gets recycled.
use
onLayout(x, y, width, height);
for ex:
onLayout(0, 0, 100, 100);
before calling getDrawingCache
Never do these things in onCreate!
You can do it in a View.onClickListener or other place.
I know this doesn't answer your question, but....
Just as an aside for other developers reading this, if what you are really trying to do is have access to a custom view's contents, derive your custom view from an ImageView. And then create a canvas and bitmap that you are going to control/draw into/read and use setImageBitmap() to set your bitmap into the view object. From there on in you can ignore the canvas passed to you in the onDraw(canvas) method and just draw into your local canvas/bitmap instead.
Why would you need this? There is an oversight in the Canvas class in my opinion. The Canvas class gives you no way to read the canvas contents nor to get at the bitmap behind it. So if you ever need to read from a bitmap, for example to acquire an image dump of the view contents, there's no way I know of to do it, other than the method described above.
This won't work for the RelativeView problem originally described here in this thread but this might be of interest to new Android developers.
As far as I read the last days in the documentation you should onlycall setDrawingCacheEnabled or buildDrawingChache() but not both.
had the same problem and finally this partly works for me:
view.layout(0, 0, 1000, 100);
Bitmap b = view.getDrawingCache();
try {
b.compress(CompressFormat.JPEG, 95,
new FileOutputStream( Environment.getExternalStorageDirectory() + "/folder/name.jpg"));
catch (FileNotFoundException e) {
Log.e(LOGTAG, "error:" + e.getMessage());
}
the only problem is, that I can't get the full dimensions of my view.
view.getwidth returns null ...
Check out if your view is not bigger than the screen size. I found this and switched the dimensions of my view so, now it works =)
Android get full View as Bitmap

Categories

Resources