Output is unexpected while trying to take a foreground-screenshot - java

So my problem is the output of this code is this (the square one) instead of what I should expect. Any ideas why this happens?
I'll explain this much further, the output is basically a square like image but not really square but it contains all the view but it is compressed unlike what we should expect, a fullscreen size image with all the views in the proper place:
Code:
private Bitmap getScreenshot(int id) {
Log.d(TAG, "Creating screenshot");
RelativeLayout RL= (RelativeLayout)findViewById(id);
View v1 = getWindow().getDecorView().getRootView(); //or RL.getRootView();
v1.setDrawingCacheEnabled(true);
v1.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
v1.layout(0, 0, v1.getMeasuredWidth(), v1.getMeasuredHeight());
v1.buildDrawingCache(true);
Bitmap bm = Bitmap.createBitmap(v1.getDrawingCache());
v1.setDrawingCacheEnabled(false);
return bm;
}
Image:

The answer to this question is:
Just force the width and the height of the views.
If it is auto scaled like match_parent, the screenshot will not see it like how it is outputted.
Code:
view.getLayoutParams().width = width;
Same goes with the height
https://i.stack.imgur.com/mFuNG.png

Related

How to center and scale an overlayed drawable icon on a bitmap

I have a bitmap thumbnail for a map and I want to add the a map marker in the center but am struggling to do so. I was able to overlay the two bitmaps but the the one in front is significantly smaller and not centered. Is there a way to center the bitmap and scale it up? This is what it looks like:
I looked at this Android: How to overlay-a-bitmap/draw-over a bitmap? and it helped but the map marker is very small and off centered. Thanks
Update:
I ended up solving it this way. I'll leave my solution for anyone who needs it in the future. Here it goes:
public static Bitmap overlay(Bitmap bmp1, Bitmap bmp2) {
Bitmap resizedBitmap = Bitmap.createScaledBitmap(bmp2, 500, 500, false);
Bitmap bitmapWithOverlay = Bitmap.createBitmap(bmp1.getWidth(), bmp1.getHeight(), bmp1.getConfig());
Canvas canvas = new Canvas(bitmapWithOverlay);
canvas.drawBitmap(bmp1, new Matrix(), null);
canvas.drawBitmap(resizedBitmap, ((bmp1.getWidth()/2)-250), ((bmp1.getHeight()/2)-450), null);
return bitmapWithOverlay;
}
and here is the process of getting the bitmap from a drawable
Bitmap icon = BitmapFactory.decodeResource(getActivity().getBaseContext().getResources(),
R.drawable.your_icon);
You can put both in the same FrameLayout. FrameLayout is build to only have one child, if you put more childs into it they will overlap. Ty this.
And also putting more childs into FrameLayout isn't bad practice.

Save multiple TextViews as image of large resolution

Situation: I have a picture and user could add texts on it, change there color, size, position, rotation, font size and etc., i need to save all this texts in one image. It's ok, i'm saving them by using drawing cache.
//RelativeLayout layout - layout with textviews
layout.setDrawingCacheEnabled(true);
Bitmap bitmap = null;
if (layout.getDrawingCache() != null)
bitmap = Bitmap.createBitmap(layout.getDrawingCache());
layout.setDrawingCacheEnabled(false);
Problem: Result image could be small due to screen size of the user's device. I need this image in resolution of 1500-2000 px. In case of just resizing this image - text looks fuzzy and not as good as it was on the screen.
Question: Is there're some other ways to save textviews as image without just resizing and loosing quality of text?
Ok, finally i found working solution.
The idea: user add text view on the image with 800x800 px size, do something with it and then i need to get the same image but in 2000x2000 px. The problem was - after resizing text was fuzzy and noisy. But how can i take a screenshot of not rendered view with size bigger than screen?
Here code that i used, it works just fine, i get the same image, text in the same positions, same size and etc. but no resizing noise, text look clear and not fuzzy. Also, this code save bitmap much bigger than screen size and without showing it to user.
private Bitmap makeTextLayer(int maxWidth, int maxHeight, ImageObject imageObject) {
Context c = mContext;
View v = LayoutInflater.from(c).inflate(R.layout.text_view_generator, new LinearLayout(c), false);
RelativeLayout editTexts = (RelativeLayout) v.findViewById(R.id.editTexts);
initView(v, maxWidth, maxHeight);
for (int i = 0; i < imageObject.getEditTexts().size(); ++i) {
ImageObject.TextInImage textInImage = imageObject.getEditTexts().get(i);
//text view in relative layout - init his size, in my case it's as big as image
CustomEditText editText = new CustomEditText(c);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.FILL_PARENT, RelativeLayout.LayoutParams.FILL_PARENT);
params.addRule(RelativeLayout.CENTER_HORIZONTAL, RelativeLayout.TRUE);
// don't forget to add your view to layout, this view will be saved as screenshot
editTexts.addView(editText, params);
editText.getLayoutParams().width = maxWidth;
editText.getLayoutParams().height = maxHeight;
editText.loadTextParams(textInImage);
editText.loadSizeAndRotation(textInImage);
// this is important, without new init - position of text will be wrong
initView(v, maxWidth, maxHeight);
// and here i configure position
editText.loadPosition();
}
Bitmap result = getViewBitmap(v, maxWidth, maxHeight);
return result;
}
Bitmap getViewBitmap(View v, int maxWidth, int maxHeight) {
//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 = v.getWidth();
int height = v.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
v.measure(measuredWidth, measuredHeight);
v.layout(0, 0, v.getMeasuredWidth(), v.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
v.draw(c);
return b;
}
private void initView(View view, int maxWidth, int maxHeight){
ViewGroup.LayoutParams vParams = view.getLayoutParams();
//If the View hasn't been attached to a layout, or had LayoutParams set
//return null, or handle this case however you want
if (vParams == null) {
return;
}
int wSpec = measureSpecFromDimension(vParams.width, maxWidth);
int hSpec = measureSpecFromDimension(vParams.height, maxHeight);
view.measure(wSpec, hSpec);
int width = view.getMeasuredWidth();
int height = view.getMeasuredHeight();
//Cannot make a zero-width or zero-height bitmap
if (width == 0 || height == 0) {
return;
}
view.layout(0, 0, width, height);
}
private int measureSpecFromDimension(int dimension, int maxDimension) {
switch (dimension) {
case ViewGroup.LayoutParams.MATCH_PARENT:
return View.MeasureSpec.makeMeasureSpec(maxDimension, View.MeasureSpec.EXACTLY);
case ViewGroup.LayoutParams.WRAP_CONTENT:
return View.MeasureSpec.makeMeasureSpec(maxDimension, View.MeasureSpec.AT_MOST);
default:
return View.MeasureSpec.makeMeasureSpec(dimension, View.MeasureSpec.EXACTLY);
}
}
I would like to thank the authors of the comments in these posts:
Converting a view to Bitmap without displaying it in Android?
Taking a "screenshot" of a specific layout in Android
Take a screenshot of a whole View
Capture whole scrollview bigger than screen
How to screenshot or snapshot a view before it's rendered?
I found my solution when read them, if my solution will not work for you - check out this posts.

Android OutOfMemoryError when trying to rotate an image

I want to display an image on screen (I have an activity that displays an image):
Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
ExifInterface exif = new ExifInterface(imagePath);
int rotation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
int rotationInDegrees = exifToDegrees(rotation);
Matrix matrix = new Matrix();
matrix.preRotate(rotationInDegrees);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
The last line throws java.lang.OutOfMemoryError
I don't understand how to do this... I have to create the bitmap at first (BitmapFactory.decodeFile) but when I want to rotate it I have to provide the source bitmap already - how can I avoid it?
Thanks
You can try downsizing the image first before decoding it by adding inSampleSize in the bitmap options. as stated at the document: http://developer.android.com/reference/android/graphics/BitmapFactory.Options.html#inSampleSize
If set to a value > 1, requests the decoder to subsample the original image, returning a smaller image to save memory.
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 5;
Bitmap bitmap = BitmapFactory.decodeFile(imagePath, options);
Hope that helps.
If you aren't doing any crazy things elsewhere then your image is probably just too big.
You just need to increase your heap. Add this to your manifest file:
android:largeHeap="true"
You cannot rotate the bitmap in place, because the dimensions can be different. I don't know, why it's impossible to load already rotated bitmap.
You can rotate the bitmap in the place of use. When drawing the bitmap, use the rotation matrix to have it drawn with rotation.
Other thing is that you probably should review your app and try to minimize the memory usage. Maybe the bitmaps you use are too big and you should use Options with inSampleSize set to 2 or more.

Android Imageview: Measure unspecified to calculate Bitmap dimensions

Google suggests to load Bitmaps from resources scaled down, depending on the actual ImageView size ("Loading Large Bitmaps Efficiently" at googles developer guides). Therefor, I have to know the width and height of the ImageView before I can decode the bitmap.
My code looks something like the one posted below. decodeSampledBitmapFromResources returns the bitmap as a scaled down version of the one stored in resources.
public void onCreate(Bundle savedInstanceSate)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.myLayout)
ImageView imageView = (ImageView) findViewById(R.id.myImageView);
/**
At this point, I need to calculate width and height of the ImageView.
**/
Bitmap bitmap = MyBitmapManager.decodeSampledBitmapFromResource(
getResources(), R.drawable.my_icon, width, height);
imageView.setImageBitmap(bitmap);
}
The problem is, as I am in onCreate, my ImageView does not have any width and height, yet. getWidth() and getHeight() are just returning 0. I stumbled over this code to calculate the size of a view before it is actually drawn:
ImageView v = findViewById(R.id.myImageView);
v.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
int width = v.getMeasuredWidth();
int height = v.getMeasuredHeight();
Is this suitable for my situation? I tried it and the above code returns some values for width and height which seem to be correct, but Im not sure if this is the correct way to do it.
UPDATE:
After some more testing, this seems NOT to work.
In the above example, im using a PNG with a size of 192x192 pixels.
After measureing the ImageView as seen above, i get a measured dimension of 128x128.
If I call getWidth() and getHeight() AFTER the bitmap is set to the imageview, the dimension is 100x100.
So in this scenario, the image is downsized from 192x192 to 128x128, but not to 100x100 as it should be.
It seems that Measurespec.UNSPECIFIED always returns dimensions greater than they are at the end.
Thanks in advance,
danijoo
I got it solved on my own with this:
ViewTreeObserver vto = imageView.getViewTreeObserver();
vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
public boolean onPreDraw(){
// at this point, true width and height are already determined
int width = imageView.getMeasuredWidth();
int height = imageView.getMeasuredHeight();
Bitmap bitmap = MyBitmapManager.decodeSampledBitmapFromResource(
getResources(), R.drawable.my_icon, width, height);
imageView.setImageBitmap(bitmap);
// this is important because onPreDrawn is fired multiple times
imageView.getViewTreeObserver().removeOnPreDrawListener(this);
return true;
}
}

The View got Pixelated during Animation to Tilt

The view got pixilated during animation I just wanted to attain a little tilt while the I try to scroll. I am using the Universal-Image-Library to hanle the animation. I'd like to attain a 3D look when tilting the view.
The first picture, is what I want.
But this picture below, I what I have. The View below got pixilated.
private void rotateLeftFrag(View af) {
if (af != null) {
ObjectAnimator.ofFloat(af, "rotationY", 5, 0)
.setDuration(100).start();
}
}
ObjectAnimator com.nineoldandroids.animation.ObjectAnimator.ofFloat(Object target, String
propertyName, float... values)
Are there any resolve to this to attain smooth animation or titling of the view? Thanks
Update:
float density = getResources().getDisplayMetrics().density;
float scale = getResources().getDisplayMetrics().density;
af.setCameraDistance(density * scale);
ObjectAnimator.ofFloat(af, "rotationY", .5f, 0).setDuration(500).start();
I think this video could help you:
http://www.youtube.com/watch?v=pMcu35-tVls
At 2:10 the guy talks about adding 1 extra transparent pixel to each side of a rotating rectangle. That should help smoothing out the edges because they would be inside the rectangle, not on the border.
Link to the source code is below the video.
In case you can't see it:
http://developer.android.com/shareables/devbytes/CardFlip.zip
Class you want to see is CardView, method bitmapWithBorder:
private static final int ANTIALIAS_BORDER = 1;
/**
* Adding a 1 pixel transparent border around the bitmap can be used to
* anti-alias the image as it rotates.
*/
private BitmapDrawable bitmapWithBorder(BitmapDrawable bitmapDrawable) {
Bitmap bitmapWithBorder = Bitmap.createBitmap(bitmapDrawable.getIntrinsicWidth() +
ANTIALIAS_BORDER * 2, bitmapDrawable.getIntrinsicHeight() + ANTIALIAS_BORDER * 2,
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmapWithBorder);
canvas.drawBitmap(bitmapDrawable.getBitmap(), ANTIALIAS_BORDER, ANTIALIAS_BORDER, null);
return new BitmapDrawable(getResources(), bitmapWithBorder);
}
Please try to turn off hardware rendering
if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
mHeaderImage.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}

Categories

Resources