Show rectangle in camera preview and crop image within it using android camera2


I have been trying to achieve something like <a href="https://i.stack.imgur.com/j9IU6.jpg" rel="nofollow">this</a> using android camera2.

I want a rectangle to load on top of my camera preview and once i press a button to capture the image then the image should be cropped within the rectangle preview. I have tried numerous solutions i could find but most of them are using the deprecated android hardware.camera and not camera2. The ones i could find with camera2 and textureview does not have the code for cropping. In the above image, I have put an overlay on my texture view using an image I made in photoshop. So how should i crop it just within the rectangle bounds?



Try this code, Its working for me


package com.example.myapplication; import android.app.Activity; import android.content.pm.ActivityInfo; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Matrix; import android.hardware.Camera; import android.hardware.Camera.PictureCallback; import android.os.Bundle; import android.util.Log; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.View; import android.widget.Button; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.RelativeLayout; import android.widget.Toast; public class MainActivity extends Activity { private ImageSurfaceView mImageSurfaceView; private Camera camera; RelativeLayout rl,cameraLayout; LinearLayout saveLayout; private FrameLayout cameraPreviewLayout; private ImageView capturedImageHolder,saveImage; int imageL,imageT,imageW,imageH,width,height,dpsize; Bitmap resizedBitmap; Camera mCamera = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); cameraPreviewLayout = (FrameLayout)findViewById(R.id.camera_preview); capturedImageHolder = (ImageView)findViewById(R.id.captured_image); rl = findViewById(R.id.rr2); cameraLayout = findViewById(R.id.cameraLayout); saveLayout = findViewById(R.id.saveLayout); saveImage = findViewById(R.id.saveImage); width= getWindowManager().getDefaultDisplay().getWidth(); height= getWindowManager().getDefaultDisplay().getHeight(); camera = checkDeviceCamera(); mImageSurfaceView = new ImageSurfaceView(MainActivity.this, camera); cameraPreviewLayout.addView(mImageSurfaceView); dpsize = (int) (getResources().getDimension(R.dimen._150sdp)); capturedImageHolder.setX((width-dpsize)/2); capturedImageHolder.setY((height -dpsize)/2); imageL= (int) capturedImageHolder.getX(); imageT= (int) capturedImageHolder.getY(); capturedImageHolder.setOnTouchListener(new MoveViewTouchListener(capturedImageHolder)); Button captureButton = (Button)findViewById(R.id.button); captureButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { camera.takePicture(null, null, pictureCallback); } }); } private Camera checkDeviceCamera(){ try { mCamera = Camera.open(); } catch (Exception e) { e.printStackTrace(); } return mCamera; } public void resetCamera() { if(mCamera!=null) { mCamera.release(); } } PictureCallback pictureCallback = new PictureCallback() { @Override public void onPictureTaken(byte[] data, Camera camera) { Bitmap b = BitmapFactory.decodeByteArray(data, 0, data.length); BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; final int REQUIRED_SIZE = 512; int scale = 1; int wd= b.getWidth(); while (wd >=( REQUIRED_SIZE)) { wd= wd/2; scale *= 2; } options.inSampleSize = scale; options.inJustDecodeBounds = false; Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length,options); if(bitmap==null){ Toast.makeText(MainActivity.this, "Captured image is empty", Toast.LENGTH_LONG).show(); return; } Matrix matrix = new Matrix(); matrix.postRotate(90); bitmap= Bitmap.createBitmap(bitmap,0,0,bitmap.getWidth(),bitmap.getHeight(),matrix,false); int bh= bitmap.getHeight(); int bw= bitmap.getWidth(); width= rl.getWidth(); height= rl.getHeight(); int l = imageL*bw/width; int t = imageT*bh/height; int w = capturedImageHolder.getWidth()*bw/width; int h = capturedImageHolder.getHeight()*bh/height; cameraPreviewLayout.setVisibility(View.GONE); capturedImageHolder.setVisibility(View.VISIBLE); resizedBitmap= Bitmap.createBitmap(bitmap,l,t,w,h); if(resizedBitmap!=null) { cameraLayout.setVisibility(View.GONE); saveLayout.setVisibility(View.VISIBLE); saveImage.setImageBitmap(resizedBitmap); } } }; public class MoveViewTouchListener implements View.OnTouchListener { private GestureDetector mGestureDetector; private View mView; public MoveViewTouchListener(View view) { mGestureDetector = new GestureDetector(view.getContext(), mGestureListener); mView = view; } @Override public boolean onTouch(View v, MotionEvent event) { return mGestureDetector.onTouchEvent(event); } private GestureDetector.OnGestureListener mGestureListener = new GestureDetector.SimpleOnGestureListener() { private float mMotionDownX, mMotionDownY; @Override public boolean onDown(MotionEvent e) { mMotionDownX = e.getRawX() - mView.getTranslationX(); mMotionDownY = e.getRawY() - mView.getTranslationY(); imageL= (int) mView.getX(); imageT= (int) mView.getY(); Log.d("imageview"," down"); return true; } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { mView.setTranslationX(e2.getRawX() - mMotionDownX); mView.setTranslationY(e2.getRawY() - mMotionDownY); imageL= (int) mView.getX(); imageT= (int) mView.getY(); if((distanceX==0)&&(distanceY==0)) { Log.d("imageview"," zoomed"); } return true; } @Override public boolean onSingleTapUp(MotionEvent e) { Log.d("imageview"," tapped"); return true; } }; } }


<?xml version="1.0" encoding="utf-8"?> <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:id="@+id/rl" > <RelativeLayout android:id="@+id/cameraLayout" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_alignParentStart="true" android:layout_alignParentTop="true" android:visibility="visible"> <RelativeLayout android:id="@+id/rr2" android:layout_width="match_parent" android:layout_height="match_parent" android:elevation="5sp" android:gravity="center"> <ImageView android:id="@+id/captured_image" android:layout_width="180sp" android:layout_height="180sp" android:elevation="8sp" /> <FrameLayout android:id="@+id/camera_preview" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_alignParentStart="true" android:layout_alignParentTop="true" /> </RelativeLayout> <Button android:gravity="center_horizontal" android:id="@+id/button" android:layout_width="50sp" android:layout_height="49dp" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:background="@drawable/squarecamera__camera_snap_selected" android:elevation="10dp" /> </RelativeLayout> <LinearLayout android:visibility="gone" android:id="@+id/saveLayout" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:minHeight="200sp" android:minWidth="200sp" android:layout_gravity="center" android:id="@+id/saveImage" android:layout_width="200sp" android:layout_height="200sp" /> </LinearLayout> </LinearLayout> </RelativeLayout>


package com.example.myapplication; import android.content.Context; import android.hardware.Camera; import android.util.Log; import android.view.Display; import android.view.Surface; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.WindowManager; import java.io.IOException; import static android.content.Context.WINDOW_SERVICE; public class ImageSurfaceView extends SurfaceView implements SurfaceHolder.Callback { private Camera mCamera; private SurfaceHolder surfaceHolder; Context context; boolean isPreviewRunning = false; public ImageSurfaceView(Context context, Camera camera) { super(context); this.mCamera = camera; this.context = context; this.surfaceHolder = getHolder(); this.surfaceHolder.addCallback(this); } @Override public void surfaceCreated(SurfaceHolder holder) { try { this.mCamera.setPreviewDisplay(holder); this.mCamera.startPreview(); } catch (IOException e) { e.printStackTrace(); } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { if (isPreviewRunning) { mCamera.stopPreview(); } Display display = ((WindowManager)context.getSystemService(WINDOW_SERVICE)).getDefaultDisplay(); if(display.getRotation() == Surface.ROTATION_0) { mCamera.setDisplayOrientation(90); } if(display.getRotation() == Surface.ROTATION_90) { } if(display.getRotation() == Surface.ROTATION_180) { } if(display.getRotation() == Surface.ROTATION_270) { mCamera.setDisplayOrientation(180); } previewCamera(); } public void previewCamera() { try { mCamera.setPreviewDisplay(surfaceHolder); mCamera.startPreview(); isPreviewRunning = true; } catch(Exception e) { Log.d("hsfhj", "Cannot start preview", e); } } @Override public void surfaceDestroyed(SurfaceHolder holder) { this.mCamera.stopPreview(); this.mCamera.release(); } } <ol><li><strong>ImageSurfaceView</strong> is for camera functions.</li> <li><strong>MoveViewTouchListener</strong> is the class for moving the square image over camera surface view.</li> <li>The cropping action works inside <strong>pictureCallback</strong>;</li> </ol>


To add the rectangle you can simply define an image in your xml layout file and position it in the centre of your preview.

Cropping uses the SCALAR_CROP_REGION:


Rect cropRect = new Rect(0, 0, 1755, 3120); captureRequestBuilder.set(CaptureRequest.SCALER_CROP_REGION, cropRect);



  • Android Universal Image Loader AutoResize
  • Android Paypal Integration: Sandbox to Production
  • Android: ListAdapter example redraws same content
  • Android: setOnClickListener to Buttons. Firing twice when pressed too quick
  • android popup window not displaying
  • Getting the location periodically and plotting markers to map
  • Fragment tabhost is not working in Fragment
  • How does Instagram embed clickable text in stories?
  • openOptionsMenu() not working
  • Why setOnCheckedChangeListener not working in a popup that uses LayoutInflater?
  • How to set the percentage height/width of child views of PercentFrameLayout at runtime
  • Do I need to set Internet permission for opening a website in Android?
  • DFP not serving Ads for Google Nexus7 using SmartBanner
  • How to acces variable in arrayadapter getView from onItemClick
  • Toggle button in a list view loose their state when scrolled of screen in Android
  • HoloEverywhere SeekBar ClassCastException
  • how to passing listview images passing another activity [closed]
  • Show progress of seekbar in a textview inside a custom alert dialog
  • Select Address from MapActivity and return back to MainActivity
  • Android Floating Window
  • What other Adapters can I use for ListView?
  • Populatate the spinner from Firebase database
  • Android Media player seekbar play from stopped position
  • Android how to set a transparent image resource of a view? or Remove the image?
  • RxJava,Retrofit Error :Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $
  • Update Search Results to Lazy Adapter in android
  • Why does .addView throw this parent/child exception?
  • Eventbus onMessageEvent not getting called
  • How to Handle Click on Imageview in Custom Listview with image and Textview?
  • Android: How do you create an EditText field in java class
  • CloseOptionsMenu doesn't work?
  • Unable to resolve Static method?
  • Incrementing object id automatically JS constructor (static method and variable)
  • How to check if every primary key value is being referenced as foreign key in another table
  • Can I have the cursor start on a particular column by default in jqgrid's edit mode?
  • jquery mobile loadPage not working
  • How to delete a row from a dynamic generate table using jquery?
  • json Serialization in asp
  • Rails 2: use form_for to build a form covering multiple objects of the same class
  • How to stop GridView from loading again when I press back button?