简单的相机界面布局
SURFACE_TYPE_NORMAL:用RAM缓存原生数据的普通Surface
SURFACE_TYPE_HARDWARE:适用于DMA(Direct memory access )引擎和硬件加速的Surface
SURFACE_TYPE_GPU:适用于GPU加速的Surface
SURFACE_TYPE_PUSH_BUFFERS:表明该Surface不包含原生数据,Surface用到的数据由其他对象提供,在Camera图像预览中就使用该类型的Surface,有Camera负责提供给预览Surface数据,这样图像预览会比较流畅。如果设置这种类型则就不能调用lockCanvas来获取Canvas对象了。
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 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"
android:fitsSystemWindows="true"
tools:context="com.a520it.xiangji.MainActivity">
<SurfaceView
android:id="@+id/sfv"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|center_horizontal"
android:layout_margin="@dimen/fab_margin"
android:src="@mipmap/ic_launcher"
app:layout_anchor="@+id/sfv"
app:layout_anchorGravity="bottom|center_horizontal" />
</android.support.design.widget.CoordinatorLayout>
建立一个类实现SurfaceHolder.Callback在重载的方法(surfaceCreated ,surfaceChanged ,surfaceDestroyed)里面操作surfaceview
public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback {
private SurfaceView sufaceview;
private SurfaceHolder holder;
private Camera camera;
private boolean isPreview = false;
private FloatingActionButton fab;
private Bitmap bitmap;
private Camera.AutoFocusCallback myAutoFocusCallback = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
fab = (FloatingActionButton) findViewById(R.id.fab);
//拍照的点击事件
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(isPreview&&camera!=null){
camera.takePicture(new Camera.ShutterCallback() {
@Override
public void onShutter() {
//快门按下的回调,在这里我们可以设置类似播放“咔嚓”声之类的操作。默认的就是咔嚓。
Log.i("paizhao","啪啪啪");
}
}, null, new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] bytes, Camera camera) {
if(null!=bytes){
//解码数组成一张Bitmap图片
bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
//相机停止预览
camera.stopPreview();
isPreview=false;
}
//构造一个矩形来填充图片
Matrix matrix = new Matrix();
Bitmap rotbitmap = Bitmap.createBitmap(MainActivity.this.bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false);
if(null!=rotbitmap){
//保存相片
saveBitmap(rotbitmap);
}
//再次进入预览
camera.startPreview();
isPreview = true;
}
});
}
}
});
//自动聚焦变量回调
myAutoFocusCallback = new Camera.AutoFocusCallback() {
public void onAutoFocus(boolean success, Camera camera) {
// TODO Auto-generated method stub
if(success)//success表示对焦成功
{
Log.i("tag", "myAutoFocusCallback: success...");
camera.setOneShotPreviewCallback(null);
}
else
{
//未对焦成功
Log.i("tag", "myAutoFocusCallback: 失败了...");
}
}
};
fab.setOnTouchListener(new MyOnTouchListener());
sufaceview = (SurfaceView) findViewById(R.id.sfv);
holder = sufaceview.getHolder();
holder.setFormat(PixelFormat.TRANSLUCENT);
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);//后面有几种类型的解释
}
private void saveBitmap(Bitmap rotbitmap) {
String savePath = "/mnt/sdcard/xiangjiPhoto/";
File savefile = new File(savePath);
if(!savefile.exists()){
savefile.mkdir();
}
long data = System.currentTimeMillis();
String jpegName = savePath + data + ".jpg";
try {
FileOutputStream fos = new FileOutputStream(jpegName);
BufferedOutputStream bos = new BufferedOutputStream(fos);
bitmap.compress(Bitmap.CompressFormat.JPEG,100,bos);
bos.flush();
bos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
//开启摄像头
camera = Camera.open();
try {
camera.setPreviewDisplay(surfaceHolder);
} catch (IOException e) {
if(null != camera){
camera.release();
camera = null;
}
e.printStackTrace();
}
}
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
initCamera();
}
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
if(null != camera)
{
camera.setPreviewCallback(null); /*在启动PreviewCallback时这个必须在前不然退出出错。
这里实际上注释掉也没关系*/
camera.stopPreview();
isPreview = false;
camera.release();
camera = null;
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
//初始化相机
public void initCamera(){
if(isPreview){
camera.stopPreview();
}
if(null != camera){
Camera.Parameters myParam = camera.getParameters();
// //查询屏幕的宽和高
// WindowManager wm = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
// Display display = wm.getDefaultDisplay();
// Log.i(tag, "屏幕宽度:"+display.getWidth()+" 屏幕高度:"+display.getHeight());
myParam.setPictureFormat(PixelFormat.JPEG);//设置拍照后存储的图片格式
// //查询camera支持的picturesize和previewsize
// List<Size> pictureSizes = myParam.getSupportedPictureSizes();
// List<Size> previewSizes = myParam.getSupportedPreviewSizes();
// for(int i=0; i<pictureSizes.size(); i++){
// Size size = pictureSizes.get(i);
// Log.i(tag, "initCamera:摄像头支持的pictureSizes: width = "+size.width+"height = "+size.height);
// }
// for(int i=0; i<previewSizes.size(); i++){
// Size size = previewSizes.get(i);
// Log.i(tag, "initCamera:摄像头支持的previewSizes: width = "+size.width+"height = "+size.height);
//
// }
//设置大小和方向等参数
myParam.setPictureSize(1280, 960);
myParam.setPreviewSize(960, 720);
//myParam.set("rotation", 90);
camera.setDisplayOrientation(90);
myParam.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
camera.setParameters(myParam);
camera.startPreview();
camera.autoFocus(myAutoFocusCallback);
isPreview = true;
}
}
/*为了使图片按钮按下和弹起状态不同,采用过滤颜色的方法.按下的时候让图片颜色变淡*/
public class MyOnTouchListener implements View.OnTouchListener {
public final float[] BT_SELECTED=new float[]
{ 2, 0, 0, 0, 2,
0, 2, 0, 0, 2,
0, 0, 2, 0, 2,
0, 0, 0, 1, 0 };
public final float[] BT_NOT_SELECTED=new float[]
{ 1, 0, 0, 0, 0,
0, 1, 0, 0, 0,
0, 0, 1, 0, 0,
0, 0, 0, 1, 0 };
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
if(event.getAction() == MotionEvent.ACTION_DOWN){
v.getBackground().setColorFilter(new ColorMatrixColorFilter(BT_SELECTED));
v.setBackgroundDrawable(v.getBackground());
}
else if(event.getAction() == MotionEvent.ACTION_UP){
v.getBackground().setColorFilter(new ColorMatrixColorFilter(BT_NOT_SELECTED));
v.setBackgroundDrawable(v.getBackground());
}
return false;
}
}
}
SURFACE_TYPE_NORMAL:用RAM缓存原生数据的普通Surface
SURFACE_TYPE_HARDWARE:适用于DMA(Direct memory access )引擎和硬件加速的Surface
SURFACE_TYPE_GPU:适用于GPU加速的Surface
SURFACE_TYPE_PUSH_BUFFERS:表明该Surface不包含原生数据,Surface用到的数据由其他对象提供,在Camera图像预览中就使用该类型的Surface,有Camera负责提供给预览Surface数据,这样图像预览会比较流畅。如果设置这种类型则就不能调用lockCanvas来获取Canvas对象了。