View:
//SurfaceView是专用于显示动态影像的view 它的内部实现了双缓冲区等技术
//可以使画面的刷新更为平滑 所以像视频的播放或者游戏的显示一般都是用SurfaceView
public class MyPreviewView extends SurfaceView
implements Callback
{
Context context=null;
Camera camera=null;
SurfaceHolder mHolder=null;
boolean previewRunning=false;
public MyPreviewView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
public MyPreviewView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
}
public MyPreviewView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context=context;
mHolder=this.getHolder();//获得SurfaceView的控制器
mHolder.addCallback(this);//设置Holder的回调接口
//holder将会通过这个回调接口控制SurfaceView的显示或者刷新等行为
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
//拍照的方法
public void takePic()
{
if(camera!=null)
{
//这三个参数分别是三个回调函数
//shutter表示 按下快门时 要执行的操作
//raw 表示要把图片保存成raw格式时所作的操作
//jpeg表示要把图片保存成jpg格式
camera.takePicture(shutter,null, jpeg);
previewRunning=false;
startPreview();
}
}
ShutterCallback shutter=new ShutterCallback() {
@Override
public void onShutter() {
// 你可以去实现一个快门的动画效果 或者发出快门的声效
Toast.makeText(context, "拍照了!!咔嚓", Toast.LENGTH_LONG).show();
}
};
PictureCallback jpeg=new PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
// TODO Auto-generated method stub
String path=Environment.getExternalStorageDirectory()+"/mypic.jpg";
try {
//保存图片
FileOutputStream fos=new FileOutputStream(path);
fos.write(data, 0, data.length);
fos.flush();
fos.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
//这个方法在SurfaceView的显示区域发生改变时会执行
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
iniPreview(width,height);
startPreview();
}
public void iniPreview(int width,int height)
{
// 获得摄像头的默认设置参数 你可以自由设置这些参数 来修改摄像头的拍摄特性
Parameters parms=camera.getParameters();
Log.i("test", "screen w:"+width+" h:"+height);
Camera.Size size=getBestPreviewSize(width,height,parms);
//设置预览的尺寸
parms.setPreviewSize(size.width, size.height);
parms.setPictureFormat(ImageFormat.JPEG);
setCameraDisplayOrientation(cameraId);
try {
camera.setPreviewDisplay(mHolder);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//开始预览
public void startPreview()
{
if(previewRunning && camera!=null)
{
//如果已经处于预览状态 需要先结束 再启动
camera.stopPreview();
previewRunning=false;
}
camera.startPreview();
previewRunning=true;
}
//设置预览图像的旋转角度
@SuppressLint("NewApi")
public void setCameraDisplayOrientation(int cameraId) {
android.hardware.Camera.CameraInfo info =
new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(cameraId, info);
//获得显示屏的旋转角度 rotation是方向的代码 0 0度 1.旋转90度 2 代表旋转180度
//3.代表旋转270 这四种方向状态并不是每一款手机都有的,有的手机只有一种横屏
int rotation =((Activity) context).getWindowManager().getDefaultDisplay()
.getRotation();
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0: degrees = 0; break;
case Surface.ROTATION_90: degrees = 90; break;
case Surface.ROTATION_180: degrees = 180; break;
case Surface.ROTATION_270: degrees = 270; break;
}
int result;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else { // back-facing
result = (info.orientation - degrees + 360) % 360;
}
camera.setDisplayOrientation(result);
}
//确定预览尺寸的最合适的size大小
public Camera.Size getBestPreviewSize(int width,int height,Parameters parms)
{
Camera.Size result=null;
List<Camera.Size> sizeList=parms.getSupportedPreviewSizes();
for(Camera.Size s:sizeList)
{
Log.i("test", "-----w:"+s.width+" h:"+s.height);
if(result==null && s.width<=width && s.height<=height)
{
result=s;
//预览尺寸不能大于显示屏幕的尺寸
}else if(result!=null &&s.width<=width && s.height<=height)
{
//把新尺寸的显示面积与老尺寸对比
int newArea=s.width*s.height;
int oldArea=result.width*result.height;
if(newArea>oldArea)
{
result=s;//新尺寸的显示面积大 则替换老尺寸
}
}
}
Log.i("test", "result w:"+result.width+" h:"+result.height);
return result;
}
//在SurfaceView创建时被执行
@SuppressLint("NewApi")
@Override
public void surfaceCreated(SurfaceHolder holder) {
//SurfaceView创建时 打开相机
int count=Camera.getNumberOfCameras();//获得手机所拥有的摄像头的数量
cameraId=getBackCameraId();
//打开后置摄像头
camera=Camera.open(cameraId);
}
int cameraId=0;
@SuppressLint("NewApi")
public int getBackCameraId()
{
int count=Camera.getNumberOfCameras();//获得手机所拥有的摄像头的数量
for(int cameraId=0;cameraId<count;cameraId++)
{
//获得指定ID的摄像头的信息
CameraInfo info=new CameraInfo();
Camera.getCameraInfo(cameraId,info);
if(info.facing==CameraInfo.CAMERA_FACING_BACK)
{
//判断该摄像头是不是后置摄像头
return cameraId;
}
}
return 0;
}
//销毁时被执行
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
if(camera!=null)
{
camera.release();
camera=null;
previewRunning=false;
}
}
}
public class MyOwnCameraActivity extends Activity {
MyPreviewView myview=null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_own_camera);
myview=(MyPreviewView)findViewById(R.id.myview);
myview.setOnClickListener(lst);
}
View.OnClickListener lst=new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
myview.takePic();
}
};
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.my_own_camera, menu);
return true;
}
}
xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MyOwnCameraActivity" >
<camera.own.MyPreviewView
android:id="@+id/myview"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</RelativeLayout>
权限:
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>