extra padding while taking screenshot using MediaProjection API - java

I am using the following code to obtain a screenshot. I get the screenshot but there is black padding attached to the image. The code samples found on the internet to take screenshot and to remove padding are used here:
// requesting permission
MediaProjectionManager projectionManager = (MediaProjectionManager) getSystemService(
Context.MEDIA_PROJECTION_SERVICE);
startActivityForResult(projectionManager.createScreenCaptureIntent(), REQUEST_SCREENSHOT);
// requesting screenshot on successful permission (in onActivityResult)
if (requestCode == REQUEST_SCREENSHOT && resultCode == RESULT_OK) {
MediaProjectionManager projectionManager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);
final MediaProjection mProjection = projectionManager.getMediaProjection(resultCode, data);
Display mDisplay = getWindowManager().getDefaultDisplay();
Point size = new Point();
mDisplay.getSize(size);
final int width = size.x;
final int height = size.y;
final ImageReader mImageReader = ImageReader.newInstance(width, height, PixelFormat.RGBA_8888, 2);
mProjection.createVirtualDisplay("screen-mirror", width, height,
getResources().getDisplayMetrics().densityDpi,
DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY |
DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC, mImageReader.getSurface(),
null, null);
mImageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
#Override
public void onImageAvailable(ImageReader imageReader) {
final Image image = imageReader.acquireLatestImage();
if (image != null) {
mImageReader.setOnImageAvailableListener(null, null);
mProjection.stop();
final Image.Plane[] planes = image.getPlanes();
final ByteBuffer buffer = planes[0].getBuffer();
int pixelStride = planes[0].getPixelStride();
int rowStride = planes[0].getRowStride();
int rowPadding = rowStride - pixelStride * width;
// create bitmap
Bitmap bmp = Bitmap.createBitmap(
width + rowPadding / pixelStride, height, Bitmap.Config.ARGB_8888);
bmp.copyPixelsFromBuffer(buffer);
image.close();
ImageView iv = findViewById(R.id.iv);
iv.setImageBitmap(bmp);
}
}
}, null);
}
Here is a screenshot showing what I am getting. I am loading the bitmap into an ImageView within my Activity.

First, the size that you got is incorrect.
You should change to:
WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
windowManager.getDefaultDisplay().getRealSize(size);
Then you should create another bitmap base on the bitmap you get from buffer
Bitmap newBitmap = Bitmap.createBitmap(bmp, 0, 0, mWidth, mHeight);
bmp.recycle();
ImageView iv = findViewById(R.id.iv);
iv.setImageBitmap(newBitmap);

Related

Java android get one bitmap from imageView and TextView

I have in my view imageView and textView in linearLayout and I want to get a one bitmap from this two controls. I try do this :
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;
}
But my application is crash and I see this :
Caused by: java.lang.IllegalArgumentException: width and height must be > 0
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;
}

Change Picture Size/Resolution of IMAGE_CAPTURE Intent

Is it possible to change the settings of an Intent for taking a picture to set the size or resolution of the resulting Image?
So right now I take a picture and the resulting Image was taken with 16MP and 4608x2304.
I'd like to know if its possible to get a resulting image such as (for example):
2MP and 460x230...
I know there is this way:
intent.putExtra("outputX", 460);
intent.putExtra("outputY", 230);
But I'm looking for something that works with all devices (cause of course they all don't have the same image sizes and if I crop them with hard coded values it'll suck)...
Hope you can understand what my issue is..
You need to take a photo without saving it in a file:
static final int REQUEST_IMAGE_CAPTURE = 1;
private void dispatchTakePictureIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
}
}
After that you need to scale a result Bitmap with saving of aspect ratio:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
Bundle extras = data.getExtras();
Bitmap imageBitmap = (Bitmap) extras.get("data");
Bitmap scaledImage = scaleBitmap(imageBitmap , 460, 230);
mImageView.setImageBitmap(scaledImage);
}
}
private Bitmap scaleBitmap(Bitmap bm, int maxWidth, int maxHeight) {
int width = bm.getWidth();
int height = bm.getHeight();
if (width > height) {
// landscape
int ratio = width / maxWidth;
width = maxWidth;
height = height / ratio;
} else if (height > width) {
// portrait
int ratio = height / maxHeight;
height = maxHeight;
width = width / ratio;
} else {
// square
height = maxHeight;
width = maxWidth;
}
bm = Bitmap.createScaledBitmap(bm, width, height, true);
return bm;
}

when trying to make circle bitmap the background remains square

so i am trying now for about a week to get this thing working but to no avail....
i want the user to pick an image from his gallery and then crop that image into a nice circle profile photo i get the photo to crop but the background is still square.... i found this question and tried implementing the answer he gave but still the background is square Cropping circular area from bitmap in Android
i googled and just found more ways to do it but still gets the square background.... any help will be appreciated
public class RegisterActivity extends Fragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
private String mParam1;
private String mParam2;
RoundedImageView roundImageView ;
String numberToPass = "1";//default 1 for male
String selectedImagePath;
EditText etNickname, etAge;
Button btnNext;
ImageView profilePhoto, imageview;
Bitmap bitmap;
private OnRegisterListener mListener;
public RegisterActivity() {
// Required empty public constructor
}
public static RegisterActivity newInstance(String param1, String param2) {
RegisterActivity fragment = new RegisterActivity();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_register, container, false);
etNickname = (EditText) view.findViewById(R.id.etNickName);
btnNext = (Button) view.findViewById(R.id.btnNextRegister);
profilePhoto = (ImageView) view.findViewById(R.id.imageButton);
bitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.blender);
// profilePhoto.setImageBitmap(bitmap);
/* Bitmap bitmap2 = BitmapFactory.decodeResource(this.getResources(),R.drawable.blender);
Bitmap circularBitmap = ImageConverter.getRoundedCornerBitmap(bitmap2, 100);
ImageView circularImageView = (ImageView)view.findViewById(R.id.imageButton);
circularImageView.setImageBitmap(circularBitmap); */
profilePhoto.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
openGallery();
}
});
return view;
}
// TODO: Rename method, update argument and hook method into UI event
public void onButtonPressed(Uri uri) {
if (mListener != null) {
mListener.onFragmentInteraction(uri);
}
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnRegisterListener) {
mListener = (OnRegisterListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnRegisterListener");
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
public interface OnRegisterListener {
// TODO: Update argument type and name
void onFragmentInteraction(Uri uri);
}
//this allows the uset to select one image from openGallery
public void openGallery() {
Intent gallery = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.INTERNAL_CONTENT_URI);
startActivityForResult(gallery, 1);
}
//when starting activity for result and choose an image, the code will automatically continue here
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK && requestCode == 1 && null != data) {
if (requestCode == 1) {
Uri current_ImageURI = data.getData();
/* String[] filePathColumn = { MediaStore.Images.Media.DATA };
Cursor cursor = getActivity().getContentResolver().query(current_ImageURI,
filePathColumn, null, null, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
String picturePath = cursor.getString(columnIndex);
cursor.close();*/
selectedImagePath = getPath(current_ImageURI);
profilePhoto.setImageBitmap(circleBitmap(decodeSampledBitmap(new File(selectedImagePath), 250, 250)));
}
}
}
public String getPath(Uri contentUri) {
// we have to check for sdk version because from lollipop the retrieval of path is different
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// can post image
String[] proj = {MediaStore.Images.Media.DATA};
Cursor cursor = getActivity().getApplicationContext().getContentResolver().query(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
} else {
String filePath = "";
String wholeID = DocumentsContract.getDocumentId(contentUri);
// Split at colon, use second item in the array
String id = wholeID.split(":")[1];
String[] column = {MediaStore.Images.Media.DATA};
// where id is equal to
String sel = MediaStore.Images.Media._ID + "=?";
Cursor cursor = getActivity().getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, column, sel, new String[]{id}, null);
int columnIndex = cursor.getColumnIndex(column[0]);
if (cursor.moveToFirst()) {
filePath = cursor.getString(columnIndex);
}
cursor.close();
return filePath;
}
}
public Bitmap decodeSampledBitmap(File res, int reqWidth, int reqHeight) {
if (res != null) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
try {
FileInputStream stream2 = null;
try {
stream2 = new FileInputStream(res);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
BitmapFactory.decodeStream(stream2, null, options);
stream2.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// Calculate inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
o2.inJustDecodeBounds = false;
FileInputStream stream = null;
try {
stream = new FileInputStream(res);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
Bitmap bitmap = BitmapFactory.decodeStream(stream, null, o2);
try {
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
return bitmap;
} else
return null;
}
public int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
//-----------------------------------------------------------------
private Bitmap circleBitmap(Bitmap bitmap) {
final Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
bitmap.getHeight(), Bitmap.Config.ARGB_8888);
int squareBitmapWidth = Math.min(bitmap.getWidth(), bitmap.getHeight());
/* Canvas
The Canvas class holds the "draw" calls. To draw something, you need 4 basic
components: A Bitmap to hold the pixels, a Canvas to host the draw calls (writing
into the bitmap), a drawing primitive (e.g. Rect, Path, text, Bitmap), and a paint
(to describe the colors and styles for the drawing). */
final Canvas canvas = new Canvas(output);
final int color = Color.RED;
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
// final Rect rect = new Rect(0, 0, squareBitmapWidth, squareBitmapWidth);
final RectF rectF = new RectF(rect);
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
canvas.drawCircle(bitmap.getWidth() / 2, bitmap.getHeight() / 2, bitmap.getWidth() / 2, paint);
//canvas.drawOval(rectF, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
//float left = (squareBitmapWidth - bitmap.getWidth()) / 2;
//float top = (squareBitmapWidth - bitmap.getHeight()) / 2;
//canvas.drawBitmap(bitmap, left, top, paint);
canvas.drawBitmap(bitmap, rect, rect, paint);
//bitmap.recycle();
return output;
}
//---------------------------------------------------------------------------------------------
//end img upload
I use this code and it works perfectly:
public static Bitmap getCircularBitmap(Bitmap bitmap) {
Bitmap output;
if (bitmap.getWidth() > bitmap.getHeight()) {
output = Bitmap.createBitmap(bitmap.getHeight(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
} else {
output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getWidth(), Bitmap.Config.ARGB_8888);
}
Canvas canvas = new Canvas(output);
final int color = 0xff424242;
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
float r = 0;
if (bitmap.getWidth() > bitmap.getHeight()) {
r = bitmap.getHeight() / 2;
} else {
r = bitmap.getWidth() / 2;
}
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
canvas.drawCircle(r, r, r, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
return output;
}
You can custom ImageView to make its all drawing things circular. Here is my implementation(not the best solution for performance-eager application but good enough for condition that don't invalidate ImageView much):
class CircleImageView extends ImageView {
private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
public CircleImageView(Context context) {
super(context);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int radiusMeasureSpec = widthMeasureSpec;
super.onMeasure(radiusMeasureSpec, radiusMeasureSpec);
int radiusMeasureSize = MeasureSpec.getSize(widthMeasureSpec);
setMeasuredDimension(radiusMeasureSize, radiusMeasureSize);
}
#Override
public void draw(Canvas viewCanvas) {
final int EDGE_SIZE = viewCanvas.getWidth();
// Draw this View's things.
Bitmap fgBm = Bitmap.createBitmap(EDGE_SIZE, EDGE_SIZE, Bitmap.Config.ARGB_8888);
Canvas fgCanvas = new Canvas(fgBm);
super.draw(fgCanvas);
// Transfer to a special shape.
Bitmap shapedBm = Bitmap.createBitmap(EDGE_SIZE, EDGE_SIZE, Bitmap.Config.ARGB_8888);
Canvas shapedCanvas = new Canvas(shapedBm);
shapedCanvas.drawCircle(EDGE_SIZE/2, EDGE_SIZE/2, EDGE_SIZE/2, mPaint);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
shapedCanvas.drawBitmap(fgBm, 0, 0, mPaint);
mPaint.setXfermode(null);
// Move drawn things to View's canvas.
viewCanvas.drawBitmap(shapedBm, 0, 0, mPaint);
fgBm.recycle();
shapedBm.recycle();
}
}
There's someone who customizes ImageView using BitmapShader in an SO post without Xfermode and create extra Bitmap instances. Here's his implementation.
you can use trusted library like This one
Adding circle image adding border to your image and some other feature

Take a screenshot of RecyclerView in FULL length

I want to get a "full page" screenshot of the activity. The view contains a RecyclerView with many items.
I can take a screenshot of the current view with this function:
public Bitmap getScreenBitmap() {
View v= findViewById(R.id.container).getRootView();
v.setDrawingCacheEnabled(true);
v.buildDrawingCache(true);
Bitmap b = Bitmap.createBitmap(v.getDrawingCache());
v.setDrawingCacheEnabled(false); // clear drawing cache
return b;
}
But it contains only the items I can view normally (as expected).
Is there some way to make the RecyclerView magically show in full length (display all items at once) when I take the screenshot?
If not, how should I approach this problem?
Inspired from Yoav's answer. This code works for recyclerview item types and probably regardless of it's size.
It was tested with a recyclerview having linearlayout manager and three item types. Yet to check it with other layout managers.
public Bitmap getScreenshotFromRecyclerView(RecyclerView view) {
RecyclerView.Adapter adapter = view.getAdapter();
Bitmap bigBitmap = null;
if (adapter != null) {
int size = adapter.getItemCount();
int height = 0;
Paint paint = new Paint();
int iHeight = 0;
final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
// Use 1/8th of the available memory for this memory cache.
final int cacheSize = maxMemory / 8;
LruCache<String, Bitmap> bitmaCache = new LruCache<>(cacheSize);
for (int i = 0; i < size; i++) {
RecyclerView.ViewHolder holder = adapter.createViewHolder(view, adapter.getItemViewType(i));
adapter.onBindViewHolder(holder, i);
holder.itemView.measure(View.MeasureSpec.makeMeasureSpec(view.getWidth(), View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
holder.itemView.layout(0, 0, holder.itemView.getMeasuredWidth(), holder.itemView.getMeasuredHeight());
holder.itemView.setDrawingCacheEnabled(true);
holder.itemView.buildDrawingCache();
Bitmap drawingCache = holder.itemView.getDrawingCache();
if (drawingCache != null) {
bitmaCache.put(String.valueOf(i), drawingCache);
}
// holder.itemView.setDrawingCacheEnabled(false);
// holder.itemView.destroyDrawingCache();
height += holder.itemView.getMeasuredHeight();
}
bigBitmap = Bitmap.createBitmap(view.getMeasuredWidth(), height, Bitmap.Config.ARGB_8888);
Canvas bigCanvas = new Canvas(bigBitmap);
bigCanvas.drawColor(Color.WHITE);
for (int i = 0; i < size; i++) {
Bitmap bitmap = bitmaCache.get(String.valueOf(i));
bigCanvas.drawBitmap(bitmap, 0f, iHeight, paint);
iHeight += bitmap.getHeight();
bitmap.recycle();
}
}
return bigBitmap;
}
Here is my solution for LinearLayoutManager when all the items are on same size and there is only one type of item. This solution is based on This answer.
Note: It can possibly lead to out of memory error.
public static Bitmap getRecyclerViewScreenshot(RecyclerView view) {
int size = view.getAdapter().getItemCount();
RecyclerView.ViewHolder holder = view.getAdapter().createViewHolder(view, 0);
view.getAdapter().onBindViewHolder(holder, 0);
holder.itemView.measure(View.MeasureSpec.makeMeasureSpec(view.getWidth(), View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
holder.itemView.layout(0, 0, holder.itemView.getMeasuredWidth(), holder.itemView.getMeasuredHeight());
Bitmap bigBitmap = Bitmap.createBitmap(view.getMeasuredWidth(), holder.itemView.getMeasuredHeight() * size,
Bitmap.Config.ARGB_8888);
Canvas bigCanvas = new Canvas(bigBitmap);
bigCanvas.drawColor(Color.WHITE);
Paint paint = new Paint();
int iHeight = 0;
holder.itemView.setDrawingCacheEnabled(true);
holder.itemView.buildDrawingCache();
bigCanvas.drawBitmap(holder.itemView.getDrawingCache(), 0f, iHeight, paint);
holder.itemView.setDrawingCacheEnabled(false);
holder.itemView.destroyDrawingCache();
iHeight += holder.itemView.getMeasuredHeight();
for (int i = 1; i < size; i++) {
view.getAdapter().onBindViewHolder(holder, i);
holder.itemView.setDrawingCacheEnabled(true);
holder.itemView.buildDrawingCache();
bigCanvas.drawBitmap(holder.itemView.getDrawingCache(), 0f, iHeight, paint);
iHeight += holder.itemView.getMeasuredHeight();
holder.itemView.setDrawingCacheEnabled(false);
holder.itemView.destroyDrawingCache();
}
return bigBitmap;
}
Note 2: It has originally been written in Kotlin. Here is the original code used by me.
Take the Screenshot of complete Recyclerview regardless of its items and item types:
This piece of code works like a charm.
Here is a clean way to do this short and precise:
recyclerView.measure(
View.MeasureSpec.makeMeasureSpec(recyclerView.getWidth(), View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
Bitmap bm = Bitmap.createBitmap(recyclerView.getWidth(), recyclerView.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
recyclerView.draw(new Canvas(bm));
saveImage(bm);
ImageView im
= new ImageView(getActivity());
im.setImageBitmap(bm);
new AlertDialog.Builder(getActivity()).setView(im).show();
The best solution I found is
create a new NestedScrollView
add it to recyclerview's parent
remove recyclerview from its parent "it's important to add it to a new parent"
add recyclerview to nestedscrollview
take screenshot of nestedscrollview
add recyclerview to its main parent.
nestedScreenShot = new NestedScrollView(getContext());
constraintLayout.removeView(recyclerView);
ConstraintLayout.LayoutParams params =new
Constraints.LayoutParams(viewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
nestedScreenShot.setLayoutParams(params);
Drawable scrollBackground = scrollView.getBackground();
if (scrollBackground != null) {
tempNestedScreenShot.setBackground(scrollBackground);
}
tempNestedScreenShot.setPadding(scrollView.getLeft(),
scrollView.getTop(), scrollView.getRight(), scrollView.getBottom());
constraintLayout.addView(nestedScreenShot);
nestedScreenShot.addView(recyclerView, params);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
nestedScreenShot.removeView(recyclerView);
constraintLayout.removeView(nestedScreenShot);
nestedScreenShot = null;
constraintLayout.addView(recyclerView, params);
}
}, 8000);
takescreenshotOfNested(nestedScreenShot);
This method will return screenshot of nestedscrollview
private Bitmap takescreenshotOfNested(View u) {
NestedScrollView viewNested = null;
ScrollView viewScroll = null;
if (u instanceof NestedScrollView) {
viewNested = (NestedScrollView) u;
} else if (u instanceof ScrollView) {
viewScroll = (ScrollView) u;
}
Bitmap bitmap;
if (viewNested != null) {
viewNested.setDrawingCacheEnabled(false);
viewNested.invalidate();
viewNested.getChildAt(0).setDrawingCacheEnabled(false);
viewNested.getChildAt(0).invalidate();
bitmap = Bitmap.createBitmap(viewNested.getChildAt(0).getWidth(),
viewNested.getChildAt(0).getHeight() + 8, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.drawColor(activity.getResources().getColor(R.color.layout_background));
viewNested.draw(canvas);
} else {
try {
viewScroll.setDrawingCacheEnabled(false);
viewScroll.invalidate();
} catch (Exception ignored) {
}
viewScroll.getChildAt(0).setDrawingCacheEnabled(false);
viewScroll.getChildAt(0).invalidate();
bitmap = Bitmap.createBitmap(viewScroll.getChildAt(0).getWidth(),
viewScroll.getChildAt(0).getHeight() + 8, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.drawColor(activity.getResources().getColor(R.color.layout_background));
viewScroll.draw(canvas);
}
return bitmap;
}
don't forget to recycle the bitmap after using it
I wrote a method to get a screenshot of a few different views:
private static Bitmap getBitmapFromView(View view) {
if (view.getVisibility() != View.VISIBLE) {
view = getNextView(view);
Log.d(TAG, "New view id: " + view.getId());
}
//Define a bitmap with the same size as the view
Bitmap returnedBitmap;
if (view instanceof ScrollView) {
returnedBitmap = Bitmap.createBitmap(((ViewGroup) view).getChildAt(0).getWidth(), ((ViewGroup) view).getChildAt(0).getHeight(), Bitmap.Config.ARGB_8888);
} else if (view instanceof RecyclerView) {
view.measure(
View.MeasureSpec.makeMeasureSpec(view.getWidth(), View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
returnedBitmap = Bitmap.createBitmap(view.getWidth(), view.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
} else {
returnedBitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888);
}
//Bind a canvas to it
Canvas canvas = new Canvas(returnedBitmap);
//Get the view's background
Drawable bgDrawable = view.getBackground();
if (bgDrawable != null) {
//has background drawable, then draw it on the canvas
bgDrawable.draw(canvas);
} else {
//does not have background drawable, then draw white background on the canvas
canvas.drawColor(Color.WHITE);
}
// draw the view on the canvas
view.draw(canvas);
//return the bitmap
return returnedBitmap;
}
/**
* If the base view is not visible, then it has no width or height.
* This causes a problem when we are creating a PDF based on its size.
* This method gets the next visible View.
*
* #param view The invisible view
* #return The next visible view after the given View, or the original view if there's no more
* visible views.
*/
private static View getNextView(View view) {
if (view.getParent() != null && (view.getParent() instanceof ViewGroup)) {
ViewGroup group = (ViewGroup) view.getParent();
View child;
boolean getNext = false;
//Iterate through all views from parent
for (int i = 0; i < group.getChildCount(); i++) {
child = group.getChildAt(i);
if (getNext) {
//Make sure the view is visible, else iterate again until we find a visible view
if (child.getVisibility() == View.VISIBLE) {
Log.d(TAG, String.format(Locale.ENGLISH, "CHILD: %s : %s", child.getClass().getSimpleName(), child.getId()));
view = child;
}
}
//Iterate until we find out current view,
// then we want to get the NEXT view
if (child.getId() == view.getId()) {
getNext = true;
}
}
}
return view;
}

How to resize input image

How to resize 2 images in android , as one image which remain constant ( .png image in drawable folder) should be equal to the size of input image (image enter from the user from mobile gallery) . I use resize(src, dst) function in opencv for resizing two images , don't have any idea of this kind of function in java end as I check this post as well but it look some kind of extra loaded work to me.
I know some method about image operation in android.
Transform Drawable to Bitmap:
public static Bitmap drawableToBitmap(Drawable drawable) {
int width = drawable.getIntrinsicWidth();
int height = drawable.getIntrinsicHeight();
Bitmap bitmap = Bitmap.createBitmap(width, height, drawable
.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888
: Bitmap.Config.RGB_565);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, width, height);
drawable.draw(canvas);
return bitmap;
}
Resize Bitmap:
public static Bitmap zoomBitmap(Bitmap bitmap, int w, int h) {
int width = bitmap.getWidth();
int height = bitmap.getHeight();
Matrix matrix = new Matrix();
float scaleWidht = ((float) w / width);
float scaleHeight = ((float) h / height);
matrix.postScale(scaleWidht, scaleHeight);
Bitmap newbmp = Bitmap.createBitmap(bitmap, 0, 0, width, height,
matrix, true);
return newbmp;
}
You can transform your first Drawable image to Bitmap, then resize it with the second method. Use getWidth() and getHeight() to get parameters of the image.
I don't know whether this is the best solution. If I didn't understand your intent well, make a comment and I can edit my answer.
Edit:
You can get Uri or the path of the image right?
If you get Uri, use String path = uri.getPath(); to get the path.
Then
Decode Bitmap from file:
public static Bitmap getBitmap(String path) {
return BitmapFactory.decodeFile(String path);
}
If the size of image is not too big, load it directly wouldn't cause memory leaks, everything is OK.
But if you don't know the size, I recommend the next method.
Decode BitmapDrawable from path:
public static BitmapDrawable getScaledDrawable(Activity a, String path) {
Display display = a.getWindowManager().getDefaultDisplay();
float destWidth = display.getWidth();
float destHeight = display.getHeight();
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
float srcWidth = options.outWidth;
float srcHeight = options.outHeight;
int inSampleSize = 1;
if (srcHeight > destHeight || srcWidth > destWidth) {
if (srcWidth > srcHeight) {
inSampleSize = Math.round(srcHeight / destHeight);
} else {
inSampleSize = Math.round(srcWidth / destWidth);
}
}
options = new BitmapFactory.Options();
options.inSampleSize = inSampleSize;
Bitmap bitmap = BitmapFactory.decodeFile(path, options);
return new BitmapDrawable(a.getResources(), bitmap);
}
This method will return a scaled BitmapDrawable object to prevent memory leaks.
If you need Bitmap not BitmapDrawable , just return bitmap.
Edit2:
ThirdActivity.java :
public class ThirdActivity extends ActionBarActivity {
private static final int REQUEST_IMAGE = 0;
private Bitmap bitmapToResize;
private Button mGetImageButton;
private Button mResizeButton;
private ImageView mImageViewForGallery;
private ImageView mImageVIewForDrable;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_third);
mGetImageButton = (Button) findViewById(R.id.button_getImage);
mGetImageButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// SET action AND miniType
Intent intent = new Intent();
intent.setAction(Intent.ACTION_PICK);
intent.setType("image/*");
// REQUEST Uri of image
startActivityForResult(intent, REQUEST_IMAGE);
}
});
mResizeButton = (Button) findViewById(R.id.button_resize);
mResizeButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
resize();
}
});
mImageViewForGallery = (ImageView) findViewById(R.id.imageView);
mImageVIewForDrable = (ImageView) findViewById(R.id.imageViewFromDrable);
mImageVIewForDrable.setImageDrawable(getResources().getDrawable(R.drawable.ic_launcher));
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode != Activity.RESULT_OK) {return;}
if (requestCode == REQUEST_IMAGE) {
Uri uri = data.getData();
// SET image
mImageViewForGallery.setImageURI(uri);
Drawable drawable = mImageViewForGallery.getDrawable();
Log.e("asd", "Height:" + drawable.getIntrinsicHeight());
Log.e("asd", "Width:" + drawable.getIntrinsicWidth());
}
}
private void resize() {
if (mImageViewForGallery.getDrawable() != null) {
bitmapToResize = drawableToBitmap(mImageVIewForDrable.getDrawable());
int width = mImageViewForGallery.getDrawable().getIntrinsicWidth();
int height = mImageViewForGallery.getDrawable().getIntrinsicHeight();
bitmapToResize = zoomBitmap(bitmapToResize, width, height);
mImageVIewForDrable.setImageBitmap(bitmapToResize);
} else {
Log.e("asd", "setImageFirst");
}
}
public static Bitmap zoomBitmap(Bitmap bitmap, int w, int h) {
int width = bitmap.getWidth();
int height = bitmap.getHeight();
Matrix matrix = new Matrix();
float scaleWidht = ((float) w / width);
float scaleHeight = ((float) h / height);
matrix.postScale(scaleWidht, scaleHeight);
Bitmap newbmp = Bitmap.createBitmap(bitmap, 0, 0, width, height,
matrix, true);
return newbmp;
}
public static Bitmap drawableToBitmap(Drawable drawable) {
int width = drawable.getIntrinsicWidth();
int height = drawable.getIntrinsicHeight();
Bitmap bitmap = Bitmap.createBitmap(width, height, drawable
.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888
: Bitmap.Config.RGB_565);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, width, height);
drawable.draw(canvas);
return bitmap;
}
}
activity_third.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
android:background="#android:color/darker_gray"
tools:context="com.ch.summerrunner.ThirdActivity">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/darker_gray">
<Button
android:id="#+id/button_getImage"
android:text="#string/gallery"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button
android:id="#+id/button_resize"
android:text="#string/resize"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_toRightOf="#id/button_getImage"/>
<ImageView
android:id="#+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:background="#android:color/white"
android:layout_below="#id/button_getImage"/>
<ImageView
android:id="#+id/imageViewFromDrable"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#android:color/white"
android:layout_below="#id/imageView"/>
</RelativeLayout>
</ScrollView>
</RelativeLayout>
Bitmap bmpIn = BitmapFactory.decodeResource(view.getResources(), R.drawable.image);
BitMap bmpOut = Bitmap.createScaledBitmap(bmpIn, width, height, false);

Categories