认证身份证的正反面,我现在只是做了一个demo。基本效果如下:
1,先看清单文件,这需要配置权限,以及CameraActivity的一些属性:
...
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FLASHLIGHT" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-feature
android:name="android.hardware.camera"
android:required="true" />
<uses-feature
android:name="android.hardware.camera.autofocus"
android:required="true" />
...
2,MainActivity.java
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private ImageView iv_front;
private ImageView iv_back;
private ImageView iv_show_front;
private ImageView iv_show_back;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
iv_front = (ImageView) findViewById(R.id.iv_show_z);
iv_back = (ImageView) findViewById(R.id.iv_show_f);
iv_show_back = (ImageView) findViewById(R.id.iv_back_img);
iv_show_front = (ImageView) findViewById(R.id.iv_front_img);
iv_show_back.setOnClickListener(this);
iv_show_front.setOnClickListener(this);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode != RESULT_OK) {
return;
}
if (requestCode == CameraActivity.REQUEST_CODE) {
//获取文件路径,显示图片
if (data != null) {
String path = data.getStringExtra("result_front");
String path_b = data.getStringExtra("result_back");
if (!TextUtils.isEmpty(path)) {
iv_front.setImageBitmap(BitmapFactory.decodeFile(path));
}
if (!TextUtils.isEmpty(path_b)) {
iv_back.setImageBitmap(BitmapFactory.decodeFile(path_b));
}
}
}
}
/**
* 拍摄证件照片
*
* @param type 拍摄证件类型
*/
private void takePhoto(int type) {
if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},1);
}
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 0x12);
return;
}
CameraActivity.navToCamera(this, type);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.iv_front_img :
takePhoto(CameraActivity.TYPE_ID_CARD_FRONT);
break;
case R.id.iv_back_img :
takePhoto(CameraActivity.TYPE_ID_CARD_BACK);
break;
}
}
}
3,activity_main.xml布局文件,这里使用的约束布局 ConstraintLayout 。
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
tools:layout_editor_absoluteY="25dp">
<android.support.constraint.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.5" />
<ImageView
android:id="@+id/iv_show_z"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="67dp"
app:layout_constraintEnd_toStartOf="@+id/guideline"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_front" />
<ImageView
android:id="@+id/iv_show_f"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="66dp"
android:layout_marginTop="69dp"
app:layout_constraintBottom_toTopOf="@+id/button"
app:layout_constraintEnd_toEndOf="@+id/iv_show_z"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="@+id/iv_show_z"
app:layout_constraintTop_toBottomOf="@+id/iv_front_img"
app:srcCompat="@drawable/ic_back" />
<ImageView
android:id="@+id/iv_front_img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toBottomOf="@+id/iv_show_z"
app:layout_constraintStart_toEndOf="@+id/iv_show_z"
app:layout_constraintTop_toTopOf="@+id/iv_show_z"
app:srcCompat="@drawable/icon_img_front" />
<ImageView
android:id="@+id/iv_back_img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toBottomOf="@+id/iv_show_f"
app:layout_constraintStart_toEndOf="@+id/iv_show_f"
app:layout_constraintTop_toTopOf="@+id/iv_show_f"
app:srcCompat="@drawable/icon_img_back" />
<Button
android:id="@+id/button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="52dp"
android:layout_marginEnd="8dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginStart="8dp"
android:background="@android:color/holo_red_light"
android:textColor="#ffffff"
android:textSize="18sp"
android:text="认证"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</android.support.constraint.ConstraintLayout>
4,点击上传身份证正面(反面),跳转到相应界面 CameraActivity:
public class CameraActivity extends Activity implements View.OnClickListener {
/**
* 身份证正面
*/
public final static int TYPE_ID_CARD_FRONT = 1;
/**
* 身份证反面
*/
public final static int TYPE_ID_CARD_BACK = 2;
public final static int REQUEST_CODE = 0X13;
private CustomCameraPreview customCameraPreview;
private View containerView;
private ImageView cropView;
private View optionView;
private int type;
/**
* 跳转到拍照页面
*/
public static void navToCamera(Context context, int type) {
Intent intent = new Intent(context, CameraActivity.class);
intent.putExtra("type", type);
((Activity) context).startActivityForResult(intent, REQUEST_CODE);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
type = getIntent().getIntExtra("type", 0);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
setContentView(R.layout.activity_camera);
customCameraPreview = (CustomCameraPreview) findViewById(R.id.camera_surface);
containerView = findViewById(R.id.camera_crop_container);
cropView = (ImageView) findViewById(R.id.camera_crop);
optionView = findViewById(R.id.camera_option);
//获取屏幕最小边,设置为cameraPreview较窄的一边
float screenMinSize = Math.min(getResources().getDisplayMetrics().widthPixels, getResources().getDisplayMetrics().heightPixels);
//根据screenMinSize,计算出cameraPreview的较宽的一边,长宽比为标准的16:9
float maxSize = screenMinSize / 9.0f * 16.0f;
RelativeLayout.LayoutParams layoutParams;
layoutParams = new RelativeLayout.LayoutParams((int) maxSize, (int) screenMinSize);
layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT);
customCameraPreview.setLayoutParams(layoutParams);
float height = (int) (screenMinSize * 0.75);
float width = (int) (height * 75.0f / 47.0f);
LinearLayout.LayoutParams containerParams = new LinearLayout.LayoutParams((int) width, ViewGroup.LayoutParams.MATCH_PARENT);
LinearLayout.LayoutParams cropParams = new LinearLayout.LayoutParams((int) width, (int) height);
containerView.setLayoutParams(containerParams);
cropView.setLayoutParams(cropParams);
switch (type) {
case TYPE_ID_CARD_FRONT:
cropView.setImageResource(R.mipmap.camera_front);
break;
case TYPE_ID_CARD_BACK:
cropView.setImageResource(R.mipmap.camera_back);
break;
}
customCameraPreview.setOnClickListener(this);
findViewById(R.id.camera_close).setOnClickListener(this);
findViewById(R.id.camera_take).setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.camera_surface:
customCameraPreview.focus();
break;
case R.id.camera_close:
finish();
break;
case R.id.camera_take:
takePhoto();
}
}
private void takePhoto() {
optionView.setVisibility(View.GONE);
customCameraPreview.setEnabled(false);
customCameraPreview.takePhoto(new Camera.PictureCallback() {
public void onPictureTaken(final byte[] data, final Camera camera) {
//子线程处理图片,防止ANR
new Thread(new Runnable() {
@Override
public void run() {
Bitmap bitmap = null;
if (data != null) {
bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
camera.stopPreview();
}
if (bitmap != null) {
//计算裁剪位置
float left = ((float) containerView.getLeft() - (float) customCameraPreview.getLeft()) / (float) customCameraPreview.getWidth();
float top = (float) cropView.getTop() / (float) customCameraPreview.getHeight();
float right = (float) containerView.getRight() / (float) customCameraPreview.getWidth();
float bottom = (float) cropView.getBottom() / (float) customCameraPreview.getHeight();
//裁剪及保存到文件
Bitmap resBitmap = Bitmap.createBitmap(bitmap,
(int) (left * (float) bitmap.getWidth()),
(int) (top * (float) bitmap.getHeight()),
(int) ((right - left) * (float) bitmap.getWidth()),
(int) ((bottom - top) * (float) bitmap.getHeight()));
FileUtil.saveBitmap(resBitmap,type);
if (!bitmap.isRecycled()) {
bitmap.recycle();
}
if (!resBitmap.isRecycled()) {
resBitmap.recycle();
}
//拍照完成,返回对应图片路径
Intent intent = new Intent();
intent.putExtra("result_front", FileUtil.getImgPath());
intent.putExtra("result_back", FileUtil.getImgPath2());
setResult(RESULT_OK, intent);
finish();
}
return;
}
}).start();
}
});
}
@Override
public void onPointerCaptureChanged(boolean hasCapture) {
}
}
5,相应的布局文件,还有需要放在layout-land文件夹下:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000">
<com.gyq.constraintlayouttest.camera.CustomCameraPreview
android:id="@+id/camera_surface"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="horizontal">
<View
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@color/preview_mock" />
<LinearLayout
android:id="@+id/camera_crop_container"
android:layout_width="0dp"
android:layout_height="0dp"
android:orientation="vertical">
<View
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="@color/preview_mock" />
<ImageView
android:id="@+id/camera_crop"
android:layout_width="0dp"
android:layout_height="0dp"
android:scaleType="fitXY" />
<TextView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="@color/preview_mock"
android:gravity="center"
android:text="@string/touch_to_focus"
android:textColor="#afff"
android:textSize="16dp" />
</LinearLayout>
</LinearLayout>
<FrameLayout
android:layout_width="136dp"
android:layout_height="match_parent"
android:background="@color/preview_mock">
<LinearLayout
android:id="@+id/camera_option"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/camera_take"
android:layout_width="72dp"
android:layout_height="72dp"
android:layout_margin="32dp"
android:src="@mipmap/camera_take" />
<ImageView
android:id="@+id/camera_close"
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@mipmap/camera_close" />
</LinearLayout>
</FrameLayout>
</LinearLayout>
</RelativeLayout>
,6,自定义CustomCameraPreview.java
public class CustomCameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private static String TAG = CustomCameraPreview.class.getName();
private Camera mCamera;
public CustomCameraPreview(Context context) {
super(context);
init();
}
public CustomCameraPreview(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CustomCameraPreview(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
SurfaceHolder surfaceHolder = getHolder();
surfaceHolder.addCallback(this);
surfaceHolder.setKeepScreenOn(true);
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void surfaceCreated(SurfaceHolder holder) {
mCamera = CamParaUtil.openCamera();
if (mCamera != null) {
startPreview(holder);
}
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
mCamera.stopPreview();
startPreview(holder);
}
public void surfaceDestroyed(SurfaceHolder holder) {
//回收释放资源
release();
}
/**
* 预览相机
*/
private void startPreview( SurfaceHolder holder) {
try {
mCamera.setPreviewDisplay(holder);
Camera.Parameters parameters = mCamera.getParameters();
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
//竖屏拍照时,需要设置旋转90度,否者看到的相机预览方向和界面方向不相同
mCamera.setDisplayOrientation(90);
parameters.setRotation(90);
} else {
mCamera.setDisplayOrientation(0);
parameters.setRotation(0);
}
Camera.Size bestSize = CamParaUtil.getBestSize(parameters.getSupportedPreviewSizes());
if (bestSize != null) {
parameters.setPreviewSize(bestSize.width, bestSize.height);
parameters.setPictureSize(bestSize.width, bestSize.height);
} else {
parameters.setPreviewSize(1920, 1080);
parameters.setPictureSize(1920, 1080);
}
mCamera.setParameters(parameters);
mCamera.startPreview();
focus();
} catch (Exception e) {
try {
Camera.Parameters parameters = mCamera.getParameters();
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
mCamera.setDisplayOrientation(90);
parameters.setRotation(90);
} else {
mCamera.setDisplayOrientation(0);
parameters.setRotation(0);
}
mCamera.setParameters(parameters);
mCamera.startPreview();
focus();
} catch (Exception e1) {
e.printStackTrace();
mCamera = null;
}
}
}
/**
* 释放资源
*/
private void release() {
if (mCamera != null) {
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
}
/**
* 对焦,在CameraActivity中触摸对焦
*/
public void focus() {
if (mCamera != null) {
mCamera.autoFocus(null);
}
}
/**
* 拍摄照片
*
* @param pictureCallback 在pictureCallback处理拍照回调
*/
public void takePhoto(Camera.PictureCallback pictureCallback) {
if (mCamera != null) {
mCamera.takePicture(null, null, pictureCallback);
}
}
}
相应的工具类及图片等可以查看 传送门