Android 自定义相机 - 在矩形内裁剪图像
Android Custom Camera - Crop image inside Rectangle
我有一个自定义相机应用程序,它有一个居中的矩形视图,如下所示:
当我拍照时,我想忽略矩形以外的一切。该视图与我的 XML 视图中的 Camera Preview 或 SurfaceView 没有任何关系,如下所示:
<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>
有人可以帮我如何正确裁剪图像吗?我试图根据我的 XML 创建一个新的位图,但显然它没有用,比如:
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);
//.../
}
我输入了 x 和 y 的初始值,并尝试从宽度和高度中减去(基于 XML 来自 View 的值,指的是 marginTop、Bottom 等...),但我没有成功,因为我不知道如何将视图坐标与从相机获取的图像坐标相匹配。另外,我觉得 Bitmap.createBitmap 裁剪有限,显然我不能直接裁剪成矩形。
要控制裁剪,必须控制图片大小和矩形大小。
重要的是a)选择与预览相同宽高比的图片尺寸,b)确保预览在屏幕上没有失真。如果您为各种设备准备您的应用程序,那么这两项任务都不是微不足道的。要实现后者,您需要同时控制预览大小和 SurfaceView 大小。我已经更详细地解释了这一点 elsewhere。
为简单起见,我建议忽略可能具有自然横向方向的平板电脑。在手机上,即使您将相机方向设置为纵向(仅影响预览),捕获的图像也会是 "rotated" 90°。不要指望 setRotation() 会为您解决这个问题:根据书本,允许简单地为捕获的图像设置 EXIF 标志。
您将 viewTamanho 的边距设置为 px。这在各种屏幕上可能无法很好地扩展。我建议以编程方式设置此视图的尺寸,作为预览表面的一定百分比。您可以使用 support library 在 XML 中定义它,但恐怕这不会给您足够的控制权。
有了这些,假设我们有1280×720的预览,2560×1440的图片,我们的屏幕是1280×800,矩形在中间,616×400像素(这是或多或少是根据您的屏幕截图缩放的尺寸)。
屏幕上的实际预览大小可能为 1000x562,左右填充 79 像素的黑边距。然后下面的代码将产生预期的捕获图片:
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);
//.../
}
这里我用的是这个
implementation 'com.otaliastudios:cameraview:2.6.2'
拍照后获取位图图像的库。
这是我如何实现的代码
public void croppingRectangle (Bitmap bitmap, CameraView mCameraView, FrameLayout rectangle) {
int cameraHeight = mCameraView.getHeight();
int cameraWidth = mCameraView.getWidth();
DisplayMetrics displayMetrics = new DisplayMetrics();
getActivity().getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int leftAndRightMarginsInPixels = Math.round(Math.round(getResources().getDimension(Your_dimens) * 2));`
这里我做了缩放,拍照后
int left = (int) Math.round(((double)rectangle.getX()/(double)cameraWidth) * bitmap.getWidth();
int top = (int) Math.round(((double)rectangle.getY()/(double)cameraHeight) * bitmap.getHeight();
int width =
(int) (capturedWidth - Math.round(((double)leftAndRightMarginsInPixels / (double) displayMetrics.widthPixels) * bitmap.getWidth()));
int height = (int) Math.round(((double) rectangle.getHeight() / (double) displayMetrics.heightPixels) * bitmap.getHeight());
Matrix rotationMatrix = new Matrix();
rotationMatrix.postRotate(0);
Bitmap croppedImage = Bitmap.createBitmap(bitmap, left, top, width, height, rotationMatrix, false);
}
P.S : 我已经达到了 95% 的顶部和底部准确率,70% 的框架宽度
我有一个自定义相机应用程序,它有一个居中的矩形视图,如下所示:
当我拍照时,我想忽略矩形以外的一切。该视图与我的 XML 视图中的 Camera Preview 或 SurfaceView 没有任何关系,如下所示:
<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>
有人可以帮我如何正确裁剪图像吗?我试图根据我的 XML 创建一个新的位图,但显然它没有用,比如:
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);
//.../
}
我输入了 x 和 y 的初始值,并尝试从宽度和高度中减去(基于 XML 来自 View 的值,指的是 marginTop、Bottom 等...),但我没有成功,因为我不知道如何将视图坐标与从相机获取的图像坐标相匹配。另外,我觉得 Bitmap.createBitmap 裁剪有限,显然我不能直接裁剪成矩形。
要控制裁剪,必须控制图片大小和矩形大小。
重要的是a)选择与预览相同宽高比的图片尺寸,b)确保预览在屏幕上没有失真。如果您为各种设备准备您的应用程序,那么这两项任务都不是微不足道的。要实现后者,您需要同时控制预览大小和 SurfaceView 大小。我已经更详细地解释了这一点 elsewhere。
为简单起见,我建议忽略可能具有自然横向方向的平板电脑。在手机上,即使您将相机方向设置为纵向(仅影响预览),捕获的图像也会是 "rotated" 90°。不要指望 setRotation() 会为您解决这个问题:根据书本,允许简单地为捕获的图像设置 EXIF 标志。
您将 viewTamanho 的边距设置为 px。这在各种屏幕上可能无法很好地扩展。我建议以编程方式设置此视图的尺寸,作为预览表面的一定百分比。您可以使用 support library 在 XML 中定义它,但恐怕这不会给您足够的控制权。
有了这些,假设我们有1280×720的预览,2560×1440的图片,我们的屏幕是1280×800,矩形在中间,616×400像素(这是或多或少是根据您的屏幕截图缩放的尺寸)。
屏幕上的实际预览大小可能为 1000x562,左右填充 79 像素的黑边距。然后下面的代码将产生预期的捕获图片:
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);
//.../
}
这里我用的是这个
implementation 'com.otaliastudios:cameraview:2.6.2'
拍照后获取位图图像的库。
这是我如何实现的代码
public void croppingRectangle (Bitmap bitmap, CameraView mCameraView, FrameLayout rectangle) {
int cameraHeight = mCameraView.getHeight();
int cameraWidth = mCameraView.getWidth();
DisplayMetrics displayMetrics = new DisplayMetrics();
getActivity().getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int leftAndRightMarginsInPixels = Math.round(Math.round(getResources().getDimension(Your_dimens) * 2));`
这里我做了缩放,拍照后
int left = (int) Math.round(((double)rectangle.getX()/(double)cameraWidth) * bitmap.getWidth();
int top = (int) Math.round(((double)rectangle.getY()/(double)cameraHeight) * bitmap.getHeight();
int width =
(int) (capturedWidth - Math.round(((double)leftAndRightMarginsInPixels / (double) displayMetrics.widthPixels) * bitmap.getWidth()));
int height = (int) Math.round(((double) rectangle.getHeight() / (double) displayMetrics.heightPixels) * bitmap.getHeight());
Matrix rotationMatrix = new Matrix();
rotationMatrix.postRotate(0);
Bitmap croppedImage = Bitmap.createBitmap(bitmap, left, top, width, height, rotationMatrix, false);
}
P.S : 我已经达到了 95% 的顶部和底部准确率,70% 的框架宽度