I have a custom camera app which have a centered rectangle view, as you can see below:
When I take a picture I want to ignore everything outside the rectangle. The view hasn’t any connection with the Camera Preview or SurfaceView in my XML view, as follows:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent"> <FrameLayout android:id="@+id/preview" android:layout_width="fill_parent" android:layout_height="fill_parent"> <SurfaceView android:id="@+id/cameraview" android:name="com.kut.camera.KutCameraFragment" android:layout_width="fill_parent" android:layout_height="fill_parent" /> <View android:id="@+id/viewTamanho" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginBottom="400px" android:layout_marginTop="300px" android:layout_marginStart="70px" android:layout_marginEnd="70px" android:background="@drawable/border" /> <RelativeLayout android:id="@+id/rel_layout" android:layout_width="match_parent" android:layout_height="match_parent" > <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:alpha="1" android:background="@android:color/black" android:orientation="vertical" android:padding="10dp" > <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" > <TextView android:id="@+id/textViewReferan" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:text="Evidência" android:textColor="@android:color/white" android:textSize="16sp" /> <Button android:id="@+id/button_exit" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentEnd="true" android:layout_alignParentRight="true" android:layout_alignParentTop="true" android:background="@android:color/transparent" android:text="Sair" android:textColor="#2799CF" /> </RelativeLayout> <LinearLayout android:id="@+id/progress_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center" android:gravity="center" android:orientation="vertical" android:visibility="gone" > <ProgressBar android:id="@+id/progressBar1" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:id="@+id/islem_value_textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Carregando..." /> </LinearLayout> </LinearLayout> <RelativeLayout android:id="@+id/RelativeLayout1" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:alpha="0.9" android:background="@android:color/black" android:padding="10dp" > <ImageView android:id="@+id/imageView_foto" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:src="@drawable/camera" /> <ImageView android:id="@+id/imageView_photo" android:layout_width="80dp" android:layout_height="100dp" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:layout_centerVertical="true" android:layout_marginRight="5dp" android:layout_marginEnd="5dp" android:padding="5dp" android:scaleType="fitCenter" android:src="@drawable/fotoicon" /> </RelativeLayout> </RelativeLayout> </FrameLayout>
Can somebody help me how to crop the image properly? I tried to create a new Bitmap based on my XML but obviously it didn’t work, something like:
Camera.PictureCallback jpegCallback = new Camera.PictureCallback() { public void onPictureTaken(byte[] data, Camera camera) { //.../ Bitmap imagemOriginal = BitmapFactory.decodeByteArray(data, 0, data.length); Bitmap imagemCortada = Bitmap.createBitmap(imagemOriginal, 70, 400, imagemOriginal.getWidth() - 70, imagemOriginal.getHeight() - 400); //.../ }
I put those initial values for x and y, and tried to subtract (based on XML values from View referring to marginTop, Bottom, etc…) from width and Height but I hadn’t success because I don’t know how to match View coordinates with the image coordinates taken from Camera. Also, it seems for me Bitmap.createBitmap does limited crop, apparently I can’t crop it to a rectangle directly.
Advertisement
Answer
To control cropping, you must control the picture size and the rectangle size.
It is very important to a) choose the picture size with same aspect ratio as the preview, and b) make sure that the preview is not distorted on the screen. If you prepare your app for a wide range of devices, both tasks are not trivial. To achieve the latter, you need to control both preview size and the SurfaceView size. I have explained this in more detail elsewhere.
To keep it simple, I suggest to ignore the tablets that may have natural Landscape orientation. On phones, the captured image will be “rotated” 90° even if you set camera orientation to portrait (which only effects preview). Don’t expect setRotation() to fix this for you: by the book, it is allowed to simply set the EXIF flag for the captured image.
You set the margins for viewTamanho in px. This may not scale well on variety of screens. I suggest setting the dimensions of this view programmatically, as certain percent of the preview surface. You can use support library to define this in XML, but I am afraid this will not give you enough control.
With all this at hand, let’s say that we have preview of 1280×720, picture of 2560×1440, our screen is 1280×800, and the rectangle is in the middle, 616×400 pixels (which is more or less the size scaled from your screenshot).
The actual preview size on screen will be probably 1000×562, padded on the right and left with black margins of 79px. Then the following code will produce the expected captured picture:
public void onPictureTaken(byte[] data, Camera camera) { //.../ Bitmap imagemOriginal = BitmapFactory.decodeByteArray(data, 0, data.length); // 2560×1440 float scale = 1280/1000F; int left = (int) scale*(imagemOriginal.getWidth()-400)/2; int top = (int) scale*(imagemOriginal.getHeight()-616)/2; int width = (int) scale*400; int height = (int) scale*616; Matrix rotationMatrix = new Matrix(); rotationMatrix.postRotate(90); Bitmap imagemCortada = Bitmap.createBitmap(imagemOriginal, left, top, width, height, rotationMatrix, false); //.../ }