camera 共有两个api,即Camera 和 Camera2,这里我们谈论的是Camera
Camera开发一般伴随着SurfaceView
1,SurfaceView需要放置在FrameLayout中,在activity中执行三个方法
mHolder = surfaceView.getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
2,callback有三个回调方法,surfaceCreated,surfaceChanged,surfaceDestroyed
3,surfaceCreated 在创建时调用;surfaceChanged 在surfaceview发生变化调用,创建至少调用一次;surfaceDestroyed在surfaceview销毁调用
4,获取摄像头
private Camera getCameraInstance() {
Camera c = null;
try {
int cameraCount = 0;
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
cameraCount = Camera.getNumberOfCameras(); // get cameras number
c = Camera.open(0);
mCameraId = 0;
Log.d(TAG, "getCameraInstance: ");
for (int camIdx = 0; camIdx < cameraCount; camIdx++) {
Camera.getCameraInfo(camIdx, cameraInfo);
// 代表摄像头的方位,目前有定义值两个分别为CAMERA_FACING_FRONT前置和CAMERA_FACING_BACK后置
if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
try {
c = Camera.open(camIdx); //打开后置摄像头
mCameraId = camIdx;
} catch (RuntimeException e) {
}
}
if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
try {
c = Camera.open(camIdx); //打开前置摄像头
mCameraId = camIdx;
} catch (RuntimeException e) {
}
}
}
} catch (Exception e) {
e.printStackTrace();
Log.d(TAG, "getCameraInstance: Exception");
}
Log.d(TAG, "getCameraInstance: success");
return c;
}
5,设置相机参数
private void setupCamera(Camera camera) {
Camera.Parameters parameters = camera.getParameters();
parameters.setPictureFormat(PixelFormat.JPEG);
if (parameters.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); //连续对焦
}
// camera.cancelAutoFocus();
//获取预览画面大小,从小排列
Camera.Size previewSize = getLastMinCameraFrameSize(camera, 4);
//获取拍照的画面大小,从小排列
Camera.Size pictrueSize = getLastMinCamera(camera, 4);
//获取最大的曝光度,这里只会使预览的亮度增加,但是拍照的效果不会改变
parameters.setExposureCompensation(parameters.getMaxExposureCompensation());
camera.setParameters(parameters);
//将参数设置在surface中并居中显示
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(1080, 1920);
params.gravity = Gravity.CENTER;
surfaceView.setLayoutParams(params);
}
private Camera.Size getLastMinCameraFrameSize(Camera camera, int last) {
//获取支持的预览大小
ArrayList so = sort((ArrayList) camera.getParameters().getSupportedPreviewSizes());
return so.get(last);
}
private Camera.Size getLastMinCamera(Camera camera, int last) {
//获取支持的照片大小
ArrayList so = sort((ArrayList) camera.getParameters().getSupportedPictureSizes());
return so.get(last);
}
private ArrayList sort(ArrayList sizes) {
Collections.sort(sizes, new Comparator() {
@Override
public int compare(Camera.Size o1, Camera.Size o2) {
return o1.height * o1.width > o2.height * o2.width ? 1 : -1;
}
});
return sizes;
}
6,设置surfaceview的预览
camera.setPreviewDisplay(holder);
setCameraDisplayOrientation(this, mCameraId, mCamera);//设置预览方向
camera.startPreview();
/**
* 保证预览方向正确
*
* @param activity
* @param cameraId
* @param camera
*/
private void setCameraDisplayOrientation(Activity activity, int cameraId, Camera camera) {
android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(cameraId, info);
int rotation = activity.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);
camera.setDisplayOrientation(0);
}
7,拍照
mCamera.takePicture(mShutterCallback, null, mPictureCallback);
Camera.ShutterCallback mShutterCallback = new Camera.ShutterCallback() {
@Override
public void onShutter() {
//添加快门声音
}
};
/**
* 拍照完成回调
*/
Camera.PictureCallback mPictureCallback = new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
//再次进入预览
mCamera.startPreview();
}
};
8,执行拍照回调,生成照片
Bitmap b = null;
if (null != data) {
b = BitmapFactory.decodeByteArray(data, 0, data.length);//data是字节数据,将其解析成位图
mCamera.stopPreview();
}
//保存图片到sdcard
if (null != b) {
Bitmap rotaBitmap = Util.getRotateBitmap(b, 0.0f);
long dateTaken = System.currentTimeMillis();
final String filename = DateFormat.format("yyyy-MM-dd kk-mm-ss", dateTaken).toString() + ".jpg";
tinyImg(rotaBitmap, filename);//压缩存储
translate(rotaBitmap); //直接存储
}
9,生成照片(未压缩)
private void translate(Bitmap bitmap) {
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) // 判断是否可以对SDcard进行操作
{ // 获取SDCard指定目录下
String sdCardDir = Environment.getExternalStorageDirectory() + "/ddd/";
File dirFile = new File(sdCardDir); //目录转化成文件夹
if (!dirFile.exists()) { //如果不存在,那就建立这个文件夹
dirFile.mkdirs();
} //文件夹有啦,就可以保存图片啦
File file = new File(sdCardDir, System.currentTimeMillis() + ".jpg");// 在SDcard的目录下创建图片文,以当前时间为其命名
FileOutputStream out = null;
try {
out = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out);
Log.d(TAG, "保存到sd指定目录文件夹下");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
try {
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
10,生成照片(Tiny压缩——https://github.com/tianyingzhong/Tiny)
private void tinyImg(final Bitmap bitmap, final String path) {
Tiny.FileCompressOptions compressOptions = new Tiny.FileCompressOptions();
compressOptions.config = Bitmap.Config.ARGB_8888;
compressOptions.isKeepSampling = true;
compressOptions.outfile = path;
//将bitmap转换为file
Tiny.getInstance().source(bitmap).asFile().withOptions(compressOptions).compress(new FileCallback() {
@Override
public void callback(boolean isSuccess, String outfile) {
}
});
}
11,释放资源
private void releaseCamera() {
Log.d(TAG, "releaseCamera: ");
if (mCamera != null) {
mCamera.setPreviewCallback(null);
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
}
注意事项:
获取系统相机的时候,有时候会获取不到(前面的应用没有释放完成),会报错(Camera X is busy)