Camera类在5.0以后不推荐使用了,取而代之的是android.hardware.camera2包下的类,本文使用Camera。
我们首先自定义一个View去继承SurfaceView:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
|
public class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback, Camera.AutoFocusCallback {
private SurfaceHolder mHolder;
private Camera mCamera;
private static final int ORIENTATION = 90 ;
private int mScreenWidth;
private int mScreenHeight;
private boolean isOpen;
public CameraSurfaceView(Context context, AttributeSet attrs) {
super (context, attrs);
getScreenMatrix(context);
mHolder = getHolder();
mHolder.addCallback( this );
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
private void getScreenMatrix(Context context) {
WindowManager WM = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
WM.getDefaultDisplay().getMetrics(outMetrics);
mScreenWidth = outMetrics.widthPixels;
mScreenHeight = outMetrics.heightPixels;
}
public void takePicture(Camera.ShutterCallback mShutterCallback, Camera.PictureCallback rawPictureCallback, Camera.PictureCallback jpegPictureCallback) {
if (mCamera != null )
mCamera.takePicture(mShutterCallback, rawPictureCallback, jpegPictureCallback);
}
public void startPreview() {
mCamera.startPreview();
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
if (!checkCameraHardware(getContext()))
return ;
if (mCamera == null ) {
isOpen = safeCameraOpen(Camera.CameraInfo.CAMERA_FACING_BACK);
}
if (!isOpen) {
return ;
}
mCamera.setDisplayOrientation(ORIENTATION);
try {
mCamera.setPreviewDisplay(holder);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if (mCamera != null ) {
setCameraParams(mScreenWidth, mScreenHeight);
mCamera.startPreview();
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
releaseCameraAndPreview();
}
private boolean safeCameraOpen( int id) {
boolean qOpened = false ;
try {
releaseCameraAndPreview();
mCamera = Camera.open(id);
qOpened = (mCamera != null );
} catch (Exception e) {
e.printStackTrace();
}
return qOpened;
}
private void releaseCameraAndPreview() {
if (mCamera != null ) {
mCamera.stopPreview();
mCamera.release();
mCamera = null ;
}
}
private boolean checkCameraHardware(Context context) {
if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
return true ;
} else {
return false ;
}
}
@Override
public void onAutoFocus( boolean success, Camera camera) {
}
private void setCameraParams( int width, int height) {
Camera.Parameters parameters = mCamera.getParameters();
// 获取摄像头支持的PictureSize列表
List<Camera.Size> pictureSizeList = parameters.getSupportedPictureSizes();
/**从列表中选取合适的分辨率*/
Camera.Size picSize = getProperSize(pictureSizeList, (( float ) height / width));
if ( null == picSize) {
picSize = parameters.getPictureSize();
}
// 根据选出的PictureSize重新设置SurfaceView大小
float w = picSize.width;
float h = picSize.height;
parameters.setPictureSize(picSize.width, picSize.height);
this .setLayoutParams( new RelativeLayout.LayoutParams(( int ) (height * (h / w)), height));
// 获取摄像头支持的PreviewSize列表
List<Camera.Size> previewSizeList = parameters.getSupportedPreviewSizes();
Camera.Size preSize = getProperSize(previewSizeList, (( float ) height) / width);
if ( null != preSize) {
parameters.setPreviewSize(preSize.width, preSize.height);
}
parameters.setJpegQuality( 100 ); // 设置照片质量
if (parameters.getSupportedFocusModes().contains(android.hardware.Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
parameters.setFocusMode(android.hardware.Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); // 连续对焦模式
}
mCamera.setDisplayOrientation( 90 ); // 设置PreviewDisplay的方向,效果就是将捕获的画面旋转多少度显示
mCamera.setParameters(parameters);
}
/**
* 选取合适的分辨率
*/
private Camera.Size getProperSize(List<Camera.Size> pictureSizeList, float screenRatio) {
Camera.Size result = null ;
for (Camera.Size size : pictureSizeList) {
float currentRatio = (( float ) size.width) / size.height;
if (currentRatio - screenRatio == 0 ) {
result = size;
break ;
}
}
if ( null == result) {
for (Camera.Size size : pictureSizeList) {
float curRatio = (( float ) size.width) / size.height;
if (curRatio == 4f / 3 ) { // 默认w:h = 4:3
result = size;
break ;
}
}
}
return result;
}
}
|
代码没什么难度,在View创建的时候完成Camera的初始化,然后对Camera进行参数的设置(图片尺寸,质量之类的),最后别忘了在View销毁的时候对资源进行释放。
控件定义完了之后我们就要去使用它,在布局文件中添加就OK:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
<? xml version = "1.0" encoding = "utf-8" ?>
< RelativeLayout
xmlns:android = "http://schemas.android.com/apk/res/android"
android:id = "@+id/activity_main"
android:layout_width = "match_parent"
android:layout_height = "match_parent"
>
< com.padoon.cameratest.CameraSurfaceView
android:id = "@+id/sv_camera"
android:layout_width = "match_parent"
android:layout_height = "match_parent"
android:layout_weight = "4" />
< ImageView
android:id = "@+id/img_take_photo"
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:layout_alignParentBottom = "true"
android:layout_alignParentRight = "true"
android:layout_gravity = "bottom"
android:layout_marginBottom = "10dp"
android:layout_marginRight = "10dp"
android:src = "@mipmap/icon_camera" />
</ RelativeLayout >
|
然后在Activity中去完成拍照功能:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
|
public class CameraActivity extends AppCompatActivity {
private boolean isClick = true ;
private static final String PATH_IMAGES = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "easy_check" ;
private CameraSurfaceView mCameraSurfaceView;
//拍照快门的回调
private Camera.ShutterCallback mShutterCallback = new Camera.ShutterCallback() {
@Override
public void onShutter() {
}
};
//拍照完成之后返回原始数据的回调
private Camera.PictureCallback rawPictureCallback = new Camera.PictureCallback() {
@Override
public void onPictureTaken( byte [] data, Camera camera) {
}
};
//拍照完成之后返回压缩数据的回调
private Camera.PictureCallback jpegPictureCallback = new Camera.PictureCallback() {
@Override
public void onPictureTaken( byte [] data, Camera camera) {
mCameraSurfaceView.startPreview();
saveFile(data);
Toast.makeText(CameraActivity. this , "拍照成功" , Toast.LENGTH_SHORT).show();
isClick = true ;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super .onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ImageView img_take_photo = (ImageView) findViewById(R.id.img_take_photo);
mCameraSurfaceView = (CameraSurfaceView) findViewById(R.id.sv_camera);
img_take_photo.setOnClickListener( new View.OnClickListener() {
@Override
public void onClick(View v) {
takePhoto();
}
});
}
public void takePhoto() {
if (isClick) {
isClick = false ;
mCameraSurfaceView.takePicture(mShutterCallback, rawPictureCallback, jpegPictureCallback);
}
}
//保存图片到硬盘
public void saveFile( byte [] data) {
String fileName = UUID.randomUUID().toString() + ".jpg" ;
FileOutputStream outputStream = null ;
try {
File file = new File(PATH_IMAGES);
if (!file.exists()) {
file.mkdirs();
}
outputStream = new FileOutputStream(PATH_IMAGES + File.separator + fileName);
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream);
bufferedOutputStream.write(data, 0 , data.length);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
|
最后记得添加拍照跟磁盘操作权限:
1
2
|
<uses-permission android:name= "android.permission.CAMERA" />
<uses-permission android:name= "android.permission.WRITE_EXTERNAL_STORAGE" />
|
到这一个非常简单的拍照Demo就完成了,只能当做Demo使用,离开发正式使用还有一段的距离,再次特地记录一下。
下载:源码
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/ww55555577/article/details/62041140