说明:本文使用的是Camera,不是Camera2,CameraX。
1、首先AndroidManifest添加相机使用权限
html
<!-- 相机相关 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
使用的activity添加硬件加速(默认开启,为啥要开启可自行百度)
java
android:hardwareAccelerated="true"
2、创建继承于TextureView的类MyTextureView(添贴代码)
java
package com.nxm.textureviewdemo;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.graphics.PixelFormat;
import android.graphics.RectF;
import android.graphics.SurfaceTexture;
import android.graphics.drawable.BitmapDrawable;
import android.hardware.Camera;
import android.os.Build;
import android.os.Environment;
import android.util.AttributeSet;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import android.view.WindowManager;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
/**
* **************************************************************************************************
* 修改日期 修改人 任务名称 功能或Bug描述
* 2018/10/12 10:36 MUZI102 TextureView类目
* **************************************************************************************************
*/
public class MyTextureView extends TextureView implements View.OnLayoutChangeListener {
public Camera mCamera;
private Context context;
private Camera.Parameters param;
private boolean isCanTakePicture = false;
Matrix matrix;
Camera camera;
int mWidth = 0;
int mHeight = 0;
int mDisplayWidth = 0;
int mDisplayHeight = 0;
int mPreviewWidth = 640;
int mPreviewHeight = 480;
int orientation = 0;
public MyTextureView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
init();
}
private void init() {
if (null == mCamera) {
mCamera = Camera.open();
}
this.setSurfaceTextureListener(new SurfaceTextureListener() {
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) {
param = mCamera.getParameters();
param.setPictureFormat(PixelFormat.JPEG);
param.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
if (!Build.MODEL.equals("KORIDY H30")) {
param.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);// 1连续对焦
} else {
param.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
}
mCamera.setParameters(param);
//变形处理
RectF previewRect = new RectF(0, 0, mWidth, mHeight);
double aspect = (double) mPreviewWidth / mPreviewHeight;
if (getResources().getConfiguration().orientation
== Configuration.ORIENTATION_PORTRAIT) {
aspect = 1 / aspect;
}
if (mWidth < (mHeight * aspect)) {
mDisplayWidth = mWidth;
mDisplayHeight = (int) (mHeight * aspect + .5);
} else {
mDisplayWidth = (int) (mWidth / aspect + .5);
mDisplayHeight = mHeight;
}
RectF surfaceDimensions = new RectF(0, 0, mDisplayWidth, mDisplayHeight);
Matrix matrix = new Matrix();
matrix.setRectToRect(previewRect, surfaceDimensions, Matrix.ScaleToFit.FILL);
MyTextureView.this.setTransform(matrix);
//<-处理变形
int displayRotation = 0;
WindowManager windowManager = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
int rotation = windowManager.getDefaultDisplay().getRotation();
switch (rotation) {
case Surface.ROTATION_0:
displayRotation = 0;
break;
case Surface.ROTATION_90:
displayRotation = 90;
break;
case Surface.ROTATION_180:
displayRotation = 180;
break;
case Surface.ROTATION_270:
displayRotation = 270;
break;
}
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(0, info);
int orientation;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
orientation = (info.orientation - displayRotation + 360) % 360;
} else {
orientation = (info.orientation + displayRotation) % 360;
orientation = (360 - orientation) % 360;
}
mCamera.setParameters(param);
mCamera.setDisplayOrientation(orientation);
try {
mCamera.setPreviewTexture(surfaceTexture);
mCamera.startPreview();
isCanTakePicture = true;
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int width, int height) {
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
if (mCamera != null) {
mCamera.stopPreview();
mCamera.release();
mCamera = null;
isCanTakePicture = true;
}
return true;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
}
});
}
/**
* 拍照
*/
public void take() {
if (mCamera != null && isCanTakePicture) {
isCanTakePicture = false;
mCamera.takePicture(new Camera.ShutterCallback() {
@Override
public void onShutter() {
}
}, null, mPictureCallback);
}
}
public void startPreview() {
if (mCamera != null && !isCanTakePicture) {
MyTextureView.this.setBackgroundDrawable(null);
mCamera.startPreview();
isCanTakePicture = true;
}
}
public void stopPreview() {
if (mCamera != null) {
mCamera.stopPreview();
}
}
public void releaseTextureView(){
if (mCamera != null) {
mCamera.stopPreview();
mCamera.release();
mCamera = null;
isCanTakePicture = true;
}
}
Camera.PictureCallback mPictureCallback = new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
if (mCamera != null) {
mCamera.stopPreview();
new FileSaver(data).save();
}
}
};
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
mWidth = right - left;
mHeight = bottom - top;
}
private class FileSaver implements Runnable {
private byte[] buffer;
public FileSaver(byte[] buffer) {
this.buffer = buffer;
}
public void save() {
new Thread(this).start();
}
@Override
public void run() {
try {
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM),
System.currentTimeMillis() + ".png");
file.createNewFile();
FileOutputStream os = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(os);
Bitmap bitmap = BitmapFactory.decodeByteArray(buffer, 0, buffer.length);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, bos);
bos.flush();
bos.close();
os.close();
MyTextureView.this.setBackgroundDrawable(new BitmapDrawable(bitmap));
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
3、acticity中使用
1、xml的布局
java
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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">
<com.nxm.textureviewdemo.MyTextureView
android:id="@+id/mytextureview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<Button
android:id="@+id/paizhai"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="拍照" />
<Button
android:id="@+id/yulan"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/paizhai"
android:text="预览" />
</RelativeLayout>
2、使用
java
package com.nxm.textureviewdemo;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
public class MainActivity extends AppCompatActivity {
private MyTextureView myTextureView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myTextureView = findViewById(R.id.mytextureview);
findViewById(R.id.paizhai).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
myTextureView.take();
}
});
findViewById(R.id.yulan).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
myTextureView.startPreview();
}
});
}
@Override
protected void onStart() {
super.onStart();
myTextureView.startPreview();
}
@Override
protected void onStop() {
myTextureView.stopPreview();
super.onStop();
}
@Override
protected void onDestroy() {
myTextureView.releaseTextureView();
super.onDestroy();
}
}