本博文将通过实例实现自定义Camera的功效。具体功能如下:
1.实现自定义Camera拍照;
2.实现前后置摄像头的切换;
3.实现Camera拍照后图片缩小显示以及正常预览;
4.实现Camera拍照后图片保存;
在具体实现代码之前,我们先来了解一下Android api对实现自定义Camera的介绍。
根据api的介绍,对于Camera应用可以简单总结以下几个步骤。
1.检查Camera是否存在,并在AndroidManifest.xml中赋予相关的权限;
2.创建一个继承于SurfaceView并实现SurfaceHolder接口的Camera Preview类;
3.在2的基础上新建一个Camera Preview布局文件;
4.设置一个拍照的监听事件,例如单击按钮事件等;
5.实现拍照,并保存拍照后的图片到设备;
6.释放Camera,以方便其他应用可以使用。
下面将通过具体代码实现我们给出的三个功能。
一.相关的xml文件
1.AndroidManifest.xml相关配置以及相关权限,实现步骤一当中的权限配置
01.
"1.0"
encoding=
"utf-8"
?>
02.
"http://schemas.android.com/apk/res/android"
03.
package
=
"com.example.camerasurfacedemo"
04.
android:versionCode=
"1"
05.
android:versionName=
"1.0"
>
06.
07.
08.
android:minSdkVersion=
"11"
09.
android:targetSdkVersion=
"19"
/>
10.
11.
"android.permission.CAMERA"
/>
12.
"android.permission.WRITE_EXTERNAL_STORAGE"
/>
13.
14.
"android.hardware.camera"
/>
15.
16.
17.
android:allowBackup=
"true"
18.
android:icon=
"@drawable/ic_launcher"
19.
android:label=
"@string/app_name"
20.
android:theme=
"@style/AppTheme"
>
21.
22.
android:name=
"com.example.camerasurfacedemo.MainActivity"
23.
android:label=
"@string/app_name"
>
24.
25.
"android.intent.action.MAIN"
/>
26.
27.
"android.intent.category.LAUNCHER"
/>
28.
29.
30.
31.
"com.example.camerasurfacedemo.CameraActivity"
32.
>
33.
"com.example.camerasurfacedemo.PreviewActivity"
34.
>
35.
36.
37.
01.
"http://schemas.android.com/apk/res/android"
02.
xmlns:tools=
"http://schemas.android.com/tools"
03.
android:layout_width=
"match_parent"
04.
android:layout_height=
"match_parent"
05.
android:gravity=
"center_horizontal"
06.
android:orientation=
"vertical"
>
07.
"
08.
09.
10.
android:id=
"@+id/id_go_camera_btn"
11.
android:layout_width=
"match_parent"
12.
android:layout_height=
"wrap_content"
13.
android:gravity=
"center"
14.
android:text=
"进入拍照界面"
/>
15.
16.
17.
android:id=
"@+id/id_show_camera_iv"
18.
android:layout_width=
"150dp"
19.
android:layout_height=
"200dp"
20.
android:gravity=
"center"
/>
21.
22.
23.
android:layout_width=
"match_parent"
24.
android:layout_height=
"match_parent"
25.
android:gravity=
"center"
26.
android:text=
"拍照图片显示区域"
27.
android:textColor=
"#FF0000"
28.
android:textSize=
"20sp"
/>
29.
30.
01.
"http://schemas.android.com/apk/res/android"
02.
xmlns:tools=
"http://schemas.android.com/tools"
03.
android:layout_width=
"match_parent"
04.
android:layout_height=
"match_parent"
05.
>
06.
07.
android:id=
"@+id/id_process_btns_ll"
08.
android:layout_width=
"match_parent"
09.
android:layout_height=
"wrap_content"
10.
android:orientation=
"horizontal"
11.
android:layout_alignParentTop=
"true"
12.
>
13.
14.
android:id=
"@+id/id_switch_camera_btn"
15.
android:layout_width=
"wrap_content"
16.
android:layout_height=
"wrap_content"
17.
android:layout_weight=
"1"
18.
android:gravity=
"center"
19.
android:text=
"切换前后摄像头"
20.
/>
21.
22.
android:id=
"@+id/id_capture_btn"
23.
android:layout_width=
"wrap_content"
24.
android:layout_height=
"wrap_content"
25.
android:layout_weight=
"1"
26.
android:gravity=
"center"
27.
android:text=
"拍照"
28.
/>
29.
30.
31.
android:id=
"@+id/id_area_sv"
32.
android:layout_width=
"match_parent"
33.
android:layout_height=
"match_parent"
34.
android:layout_below=
"@id/id_process_btns_ll"
35.
android:text=
"拍照区域"
/>
36.
37.
01.
"http://schemas.android.com/apk/res/android"
02.
xmlns:tools=
"http://schemas.android.com/tools"
03.
android:layout_width=
"match_parent"
04.
android:layout_height=
"match_parent"
05.
android:background=
"#000000"
06.
android:orientation=
"vertical"
>
07.
08.
09.
android:layout_width=
"match_parent"
10.
android:layout_height=
"wrap_content"
11.
android:gravity=
"center"
12.
android:text=
"拍照图片预览"
13.
android:textColor=
"#FF0000"
14.
android:textSize=
"20sp"
15.
/>
16.
17.
18.
android:id=
"@+id/id_preview_camera_iv"
19.
android:layout_width=
"wrap_content"
20.
android:layout_height=
"wrap_content"
21.
android:gravity=
"center"
/>
22.
23.
1.帮助类HelpUtil.java
01.
package
com.example.camerasurfacedemo;
02.
03.
import
java.io.FileInputStream;
04.
import
java.io.FileNotFoundException;
05.
import
java.io.IOException;
06.
import
java.text.SimpleDateFormat;
07.
import
java.util.Date;
08.
09.
import
android.annotation.SuppressLint;
10.
import
android.content.ContentResolver;
11.
import
android.graphics.Bitmap;
12.
import
android.graphics.BitmapFactory;
13.
import
android.graphics.Matrix;
14.
import
android.net.Uri;
15.
16.
public
class
HelpUtil {
17.
/**
18.
* 根据图片路径获取本地图片的Bitmap
19.
*
20.
* @param url
21.
* @return
22.
*/
23.
public
static
Bitmap getBitmapByUrl(String url) {
24.
FileInputStream fis =
null
;
25.
Bitmap bitmap =
null
;
26.
try
{
27.
fis =
new
FileInputStream(url);
28.
bitmap = BitmapFactory.decodeStream(fis);
29.
30.
}
catch
(FileNotFoundException e) {
31.
// TODO Auto-generated catch block
32.
e.printStackTrace();
33.
bitmap =
null
;
34.
}
finally
{
35.
if
(fis !=
null
) {
36.
try
{
37.
fis.close();
38.
}
catch
(IOException e) {
39.
// TODO Auto-generated catch block
40.
e.printStackTrace();
41.
}
42.
fis =
null
;
43.
}
44.
}
45.
46.
return
bitmap;
47.
}
48.
49.
/**
50.
* bitmap旋转90度
51.
*
52.
* @param bitmap
53.
* @return
54.
*/
55.
public
static
Bitmap createRotateBitmap(Bitmap bitmap) {
56.
if
(bitmap !=
null
) {
57.
Matrix m =
new
Matrix();
58.
try
{
59.
m.setRotate(
90
, bitmap.getWidth() /
2
, bitmap.getHeight() /
2
);
// 90就是我们需要选择的90度
60.
Bitmap bmp2 = Bitmap.createBitmap(bitmap,
0
,
0
,
61.
bitmap.getWidth(), bitmap.getHeight(), m,
true
);
62.
bitmap.recycle();
63.
bitmap = bmp2;
64.
}
catch
(Exception ex) {
65.
System.out.print(
"创建图片失败!"
+ ex);
66.
}
67.
}
68.
return
bitmap;
69.
}
70.
71.
public
static
Bitmap getBitmapByUri(Uri uri,ContentResolver cr){
72.
Bitmap bitmap =
null
;
73.
try
{
74.
bitmap = BitmapFactory.decodeStream(cr
75.
.openInputStream(uri));
76.
}
catch
(FileNotFoundException e) {
77.
// TODO Auto-generated catch block
78.
e.printStackTrace();
79.
bitmap =
null
;
80.
}
81.
return
bitmap;
82.
}
83.
84.
/**
85.
* 获取格式化日期字符串
86.
* @param date
87.
* @return
88.
*/
89.
@SuppressLint
(
"SimpleDateFormat"
)
90.
public
static
String getDateFormatString(Date date) {
91.
if
(date ==
null
)
92.
date =
new
Date();
93.
String formatStr =
new
String();
94.
SimpleDateFormat matter =
new
SimpleDateFormat(
"yyyyMMdd_HHmmss"
);
95.
formatStr = matter.format(date);
96.
return
formatStr;
97.
}
98.
}
01.
package
com.example.camerasurfacedemo;
02.
03.
import
android.app.Activity;
04.
import
android.content.Intent;
05.
import
android.net.Uri;
06.
import
android.os.Bundle;
07.
import
android.text.TextUtils;
08.
import
android.view.View;
09.
import
android.view.View.OnClickListener;
10.
import
android.widget.Button;
11.
import
android.widget.ImageView;
12.
13.
public
class
MainActivity
extends
Activity {
14.
15.
private
Button goCameraBtn;
16.
private
ImageView showCameraIv;
17.
private
static
final
int
CAMERA_CODE =
1
;
18.
@Override
19.
protected
void
onCreate(Bundle savedInstanceState) {
20.
super
.onCreate(savedInstanceState);
21.
setContentView(R.layout.activity_main);
22.
23.
goCameraBtn = (Button)
this
.findViewById(R.id.id_go_camera_btn);
24.
goCameraBtn.setOnClickListener(
new
OnClickListener(){
25.
26.
@Override
27.
public
void
onClick(View v) {
28.
processGoCamera();
29.
}
30.
31.
});
32.
33.
showCameraIv = (ImageView)
this
.findViewById(R.id.id_show_camera_iv);
34.
showCameraIv.setOnClickListener(
new
OnClickListener(){
35.
36.
@Override
37.
public
void
onClick(View v) {
38.
processShowCamera(v);
39.
}
40.
41.
});
42.
}
43.
44.
/**
45.
* 处理进入camera事件
46.
*/
47.
private
void
processGoCamera(){
48.
Intent intent =
new
Intent();
49.
intent.setClass(
this
, CameraActivity.
class
);
50.
startActivityForResult(intent,CAMERA_CODE);
51.
}
52.
53.
/**
54.
* 处理图片跳转进入预览界面
55.
*/
56.
private
void
processShowCamera(View v){
57.
Intent intent =
new
Intent();
58.
intent.setClass(
this
, PreviewActivity.
class
);
59.
/**
60.
* 将图片url传给PreviewActivity
61.
*/
62.
intent.putExtra(
"cameraUrl"
, v.getContentDescription().toString());
63.
startActivity(intent);
64.
}
65.
66.
@Override
67.
public
void
onActivityResult(
int
requestCode,
int
resultCode,Intent data){
68.
super
.onActivityResult(requestCode, resultCode, data);
69.
70.
if
(RESULT_OK == resultCode){
71.
if
(CAMERA_CODE == requestCode){
72.
/**
73.
* 获取activity返回的url
74.
*/
75.
Uri uri = data.getData();
76.
String url = uri.toString().substring(uri.toString().indexOf(
"///"
)+
2
);
77.
if
(url !=
null
&& !TextUtils.isEmpty(url)){
78.
showCameraIv.setContentDescription(url);
79.
showCameraIv.setImageBitmap(HelpUtil.getBitmapByUrl(url));
80.
}
81.
}
82.
}
83.
84.
}
85.
86.
}
注意:这里通过startActivityForResult(intent,CAMERA_CODE)跳转和 onActivityResult(int requestCode,int resultCode,Intent data)返回拍照后的图片路径信息
3.自定义Camera preview类CameraActivity.java
001.
package
com.example.camerasurfacedemo;
002.
003.
import
java.io.File;
004.
import
java.io.FileNotFoundException;
005.
import
java.io.FileOutputStream;
006.
import
java.io.IOException;
007.
import
java.util.Date;
008.
009.
import
android.annotation.SuppressLint;
010.
import
android.app.Activity;
011.
import
android.content.Context;
012.
import
android.content.Intent;
013.
import
android.content.pm.PackageManager;
014.
import
android.graphics.ImageFormat;
015.
import
android.hardware.Camera;
016.
import
android.hardware.Camera.CameraInfo;
017.
import
android.hardware.Camera.Parameters;
018.
import
android.hardware.Camera.PictureCallback;
019.
import
android.net.Uri;
020.
import
android.os.Bundle;
021.
import
android.os.Environment;
022.
import
android.util.Log;
023.
import
android.view.SurfaceHolder;
024.
import
android.view.SurfaceView;
025.
import
android.view.View;
026.
import
android.view.View.OnClickListener;
027.
import
android.view.Window;
028.
import
android.widget.Button;
029.
030.
public
class
CameraActivity
extends
Activity
implements
OnClickListener,
031.
SurfaceHolder.Callback {
032.
033.
private
static
final
String TAG = CameraActivity.
class
.getSimpleName();
034.
private
static
final
int
MEDIA_TYPE_IMAGE =
1
;
035.
private
Button switchCameraBtn, captureBtn;
036.
private
SurfaceView surfaceSv;
037.
038.
private
SurfaceHolder mHolder;
039.
private
Camera mCamera;
040.
// 0表示后置,1表示前置
041.
private
int
cameraPosition =
1
;
042.
043.
@Override
044.
protected
void
onCreate(Bundle savedInstanceState) {
045.
super
.onCreate(savedInstanceState);
046.
// 不显示标题
047.
this
.requestWindowFeature(Window.FEATURE_NO_TITLE);
048.
setContentView(R.layout.activity_camera);
049.
050.
findById();
051.
initData();
052.
}
053.
054.
/**
055.
* 初始化view
056.
*/
057.
private
void
findById() {
058.
switchCameraBtn = (Button)
this
.findViewById(R.id.id_switch_camera_btn);
059.
captureBtn = (Button)
this
.findViewById(R.id.id_capture_btn);
060.
surfaceSv = (SurfaceView)
this
.findViewById(R.id.id_area_sv);
061.
062.
switchCameraBtn.setOnClickListener(
this
);
063.
captureBtn.setOnClickListener(
this
);
064.
}
065.
066.
/**
067.
* 初始化相关data
068.
*/
069.
private
void
initData() {
070.
// 获得句柄
071.
mHolder = surfaceSv.getHolder();
072.
// 添加回调
073.
mHolder.addCallback(
this
);
074.
}
075.
076.
@Override
077.
public
void
onStart() {
078.
super
.onStart();
079.
if
(
this
.checkCameraHardware(
this
) && (mCamera ==
null
)) {
080.
// 打开camera
081.
mCamera = getCamera();
082.
if
(mHolder !=
null
) {
083.
setStartPreview(mCamera,mHolder);
084.
}
085.
}
086.
}
087.
088.
private
Camera getCamera() {
089.
Camera camera =
null
;
090.
try
{
091.
camera = Camera.open();
092.
}
catch
(Exception e) {
093.
// Camera is not available (in use or does not exist)
094.
camera =
null
;
095.
Log.e(TAG,
"Camera is not available (in use or does not exist)"
);
096.
}
097.
return
camera;
098.
}
099.
100.
@Override
101.
public
void
onPause() {
102.
super
.onPause();
103.
/**
104.
* 记得释放camera,方便其他应用调用
105.
*/
106.
releaseCamera();
107.
}
108.
109.
@Override
110.
public
void
onDestroy() {
111.
super
.onDestroy();
112.
}
113.
114.
/**
115.
* 释放mCamera
116.
*/
117.
private
void
releaseCamera() {
118.
if
(mCamera !=
null
) {
119.
mCamera.setPreviewCallback(
null
);
120.
mCamera.stopPreview();
// 停掉原来摄像头的预览
121.
mCamera.release();
122.
mCamera =
null
;
123.
}
124.
}
125.
126.
@Override
127.
public
void
onClick(View v) {
128.
switch
(v.getId()) {
129.
case
R.id.id_switch_camera_btn:
130.
// 切换前后摄像头
131.
int
cameraCount =
0
;
132.
CameraInfo cameraInfo =
new
CameraInfo();
133.
cameraCount = Camera.getNumberOfCameras();
// 得到摄像头的个数
134.
135.
for
(
int
i =
0
; i < cameraCount; i++) {
136.
Camera.getCameraInfo(i, cameraInfo);
// 得到每一个摄像头的信息
137.
if
(cameraPosition ==
1
) {
138.
// 现在是后置,变更为前置
139.
if
(cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
140.
/**
141.
* 记得释放camera,方便其他应用调用
142.
*/
143.
releaseCamera();
144.
// 打开当前选中的摄像头
145.
mCamera = Camera.open(i);
146.
// 通过surfaceview显示取景画面
147.
setStartPreview(mCamera,mHolder);
148.
cameraPosition =
0
;
149.
break
;
150.
}
151.
}
else
{
152.
// 现在是前置, 变更为后置
153.
if
(cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
154.
/**
155.
* 记得释放camera,方便其他应用调用
156.
*/
157.
releaseCamera();
158.
mCamera = Camera.open(i);
159.
setStartPreview(mCamera,mHolder);
160.
cameraPosition =
1
;
161.
break
;
162.
}
163.
}
164.
165.
}
166.
break
;
167.
case
R.id.id_capture_btn:
168.
// 拍照,设置相关参数
169.
Camera.Parameters params = mCamera.getParameters();
170.
params.setPictureFormat(ImageFormat.JPEG);
171.
params.setPreviewSize(
800
,
400
);
172.
// 自动对焦
173.
params.setFocusMode(Parameters.FOCUS_MODE_AUTO);
174.
mCamera.setParameters(params);
175.
mCamera.takePicture(
null
,
null
, picture);
176.
break
;
177.
}
178.
}
179.
180.
@Override
181.
public
void
surfaceCreated(SurfaceHolder holder) {
182.
183.
setStartPreview(mCamera,mHolder);
184.
}
185.
186.
@Override
187.
public
void
surfaceChanged(SurfaceHolder holder,
int
format,
int
width,
188.
int
height) {
189.
// If your preview can change or rotate, take care of those events here.
190.
// Make sure to stop the preview before resizing or reformatting it.
191.
192.
if
(mHolder.getSurface() ==
null
) {
193.
// preview surface does not exist
194.
return
;
195.
}
196.
197.
// stop preview before making changes
198.
try
{
199.
mCamera.stopPreview();
200.
}
catch
(Exception e) {
201.
// ignore: tried to stop a non-existent preview
202.
}
203.
204.
// set preview size and make any resize, rotate or
205.
// reformatting changes here
206.
207.
// start preview with new settings
208.
setStartPreview(mCamera,mHolder);
209.
}
210.
211.
@Override
212.
public
void
surfaceDestroyed(SurfaceHolder holder) {
213.
// 当surfaceview关闭时,关闭预览并释放资源
214.
/**
215.
* 记得释放camera,方便其他应用调用
216.
*/
217.
releaseCamera();