Android自定义相机简介

使用最简单直接的方式,自定义Android相机,并有拍照,对焦功能,可以以此为基础对相机进一步开发。

下面直接上代码:

主文件 CameraActivity.java

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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
public class CameraActivity extends Activity {
private Camera camera;
private Camera.Parameters parameters = null;

Bundle bundle = null; // 声明一个Bundle对象,用来存储数据
private String mUserId;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 显示界面
setContentView(R.layout.activity_camera);
mUserId = getIntent().getStringExtra("userId");
SurfaceView surfaceView = (SurfaceView) findViewById(R.id.camera_surfaceView);
surfaceView.getHolder()
.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
surfaceView.getHolder().setFixedSize(176, 144); //设置Surface分辨率
surfaceView.getHolder().setKeepScreenOn(true);// 屏幕常亮
surfaceView.getHolder().addCallback(new SurfaceCallback());//为SurfaceView的句柄添加一个回调函数
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
int result = data.getIntExtra("result", 0);
if (result == 0) {//确定
setResult(RESULT_OK, data);
finish();
}
}
}

/**
* 按钮被点击触发的事件
*
* @param v
*/
public void btnOnclick(View v) {
if (camera != null) {
switch (v.getId()) {
case R.id.camera_takepicture:
// 拍照
camera.takePicture(null, null, new MyPictureCallback());
break;
}
}
}

/** 拍照回调 */
private final class MyPictureCallback implements Camera.PictureCallback {

@Override
public void onPictureTaken(byte[] data, Camera camera) {

if (data != null) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 4; //这里表示原来图片的1/4
Bitmap bitmap2 = BitmapFactory.decodeByteArray(data, 0,
data.length, options);
try {
String image = saveFile(bitmap2);//保存图片

Toast.makeText(getApplicationContext(), "保存成功",
Toast.LENGTH_SHORT).show();
camera.startPreview(); // 拍完照后,重新开始预览
if (image != null) {
Intent intent = new Intent(CameraActivity.this, PictureSureActivity.class);
intent.putExtra("userId", mUserId);
intent.putExtra("image", image);
CameraActivity.this.startActivityForResult(intent, 123);
}

} catch (IOException e) {
e.printStackTrace();
}
bitmap2.recycle();
}
}
/*********************************直接保存二进制图片数据************************************/
// try {
// bundle = new Bundle();
// bundle.putByteArray("bytes", data); //将图片字节数据保存在bundle当中,实现数据交换
// String image = saveToSDCard(data);// 保存图片到sd卡中
// Toast.makeText(getApplicationContext(), "保存成功",
// Toast.LENGTH_SHORT).show();
// camera.startPreview(); // 拍完照后,重新开始预览
// } catch (Exception e) {
// e.printStackTrace();
// }

}

/**
* 将拍下来的照片存放在SD卡中
* bitmap格式图片保存
* @param bm
* @return
* @throws IOException
*/
public String saveFile(Bitmap bm) throws IOException {
Date date = new Date();
SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss"); // 格式化时间
String filename = format.format(date) + ".jpg";
File fileFolder = new File(Environment.getExternalStorageDirectory()
+ "/com.simple.images/");
if (!fileFolder.exists()) { // 如果目录不存在,则创建一个名为"finger"的目录
fileFolder.mkdir();
}
File jpgFile = new File(fileFolder, filename);
String imageUrl = jpgFile.getPath();
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(jpgFile));
bm.compress(Bitmap.CompressFormat.JPEG, 100, bos);
bos.flush();
bos.close();
return imageUrl;
}

/**
* 将拍下来的照片存放在SD卡中
*
* @param data 二进制图片数据
* @throws IOException
*/
public static String saveToSDCard(byte[] data) throws IOException {
Date date = new Date();
SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss"); // 格式化时间
String filename = format.format(date) + ".jpg";
File fileFolder = new File(Environment.getExternalStorageDirectory()
+ "/com.simple.images/");
if (!fileFolder.exists()) { // 如果目录不存在,则创建一个名为"finger"的目录
fileFolder.mkdir();
}
File jpgFile = new File(fileFolder, filename);
String imageUrl = jpgFile.getPath();
FileOutputStream outputStream = new FileOutputStream(jpgFile); // 文件输出流
outputStream.write(data); // 写入sd卡中
outputStream.close(); // 关闭输出流

return imageUrl;
}

private final class SurfaceCallback implements SurfaceHolder.Callback {

// 拍照状态变化时调用该方法
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
parameters = camera.getParameters(); // 获取各项参数
parameters.setPictureFormat(PixelFormat.JPEG); // 设置图片格式
parameters.setPreviewSize(width, height); // 设置预览大小
parameters.setPreviewFrameRate(5); //设置每秒显示4帧
parameters.setPictureSize(width, height); // 设置保存的图片尺寸
parameters.setJpegQuality(100); // 设置照片质量
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
}

// 开始拍照时调用该方法
@Override
public void surfaceCreated(SurfaceHolder holder) {
try {
camera = Camera.open(); // 打开摄像头
camera.setPreviewDisplay(holder); // 设置用于显示拍照影像的SurfaceHolder对象
camera.setDisplayOrientation(getPreviewDegree(CameraActivity.this));
camera.startPreview(); // 开始预览
camera.setAutoFocusMoveCallback(new Camera.AutoFocusMoveCallback() {
@Override
public void onAutoFocusMoving(boolean b, Camera camera) {

}
});
} catch (Exception e) {
e.printStackTrace();
}

}

// 停止拍照时调用该方法
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
if (camera != null) {
camera.release(); // 释放照相机
camera = null;
}
}
}

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_CAMERA: // 按下拍照按钮
if (camera != null && event.getRepeatCount() == 0) {
// 拍照
//注:调用takePicture()方法进行拍照是传入了一个PictureCallback对象——当程序获取了拍照所得的图片数据之后
//,PictureCallback对象将会被回调,该对象可以负责对相片进行保存或传入网络
camera.takePicture(null, null, new MyPictureCallback());
}
}
return super.onKeyDown(keyCode, event);
}

// 提供一个静态方法,用于根据手机方向获得相机预览画面旋转的角度
public static int getPreviewDegree(Activity activity) {
// 获得手机的方向
int rotation = activity.getWindowManager().getDefaultDisplay()
.getRotation();
int degree = 0;
// 根据手机的方向计算相机预览画面应该选择的角度
switch (rotation) {
case Surface.ROTATION_0:
degree = 90;
break;
case Surface.ROTATION_90:
degree = 0;
break;
case Surface.ROTATION_180:
degree = 270;
break;
case Surface.ROTATION_270:
degree = 180;
break;
}
return degree;
}

public void goBack(View v) {
finish();
}
}

布局文件 activity_camera.xml

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
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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">
<!-- 显示预览图形 -->
<SurfaceView
android:id="@+id/camera_surfaceView"
android:layout_width="match_parent"
android:layout_height="match_parent" />

<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/smoke_oranger">

<com.irobotcity.smokeverify.widget.TitleBar
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:layout_centerVertical="true"
app:addEvelation="false">

</com.irobotcity.smokeverify.widget.TitleBar>

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_marginLeft="10dp"
android:text="取消"
android:textColor="@color/whitesmoke"
android:onClick="goBack"
android:textSize="16dp" />

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:layout_gravity="center"
android:paddingBottom="15dp"
android:paddingTop="15dp"
android:text="拍照"
android:textColor="@color/white"
android:textSize="20sp" />

</RelativeLayout>

<!-- 相对布局,放置两个按钮 -->
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp">
<!-- 拍照按钮 -->
<Button
android:id="@+id/camera_takepicture"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:background="@drawable/main_take"
android:onClick="btnOnclick" />
</RelativeLayout>
</FrameLayout>