一、android中相机开发的两种方式
Android系统提供了两种使用手机相机资源实现拍摄功能的方法,一种是直接通过Intent调用系统相机组件,这种方法快速方便,适用于直接获得照片的场景,如上传相册,微博、朋友圈发照片等。另一种是使用相机API来定制自定义相机,这种方法适用于需要定制相机界面或者开发特殊相机功能的场景,如需要对照片做裁剪、滤镜处理,添加贴纸,表情,地点标签等。
使用intent拍摄照片
startActivityForResult(new Intent(MediaStore.ACTION_IMAGE_CAPTURE),TAKE_PICTURE);
- 启动手机的相机应用拍摄照片,拍摄完成后,在onActivityResult方法中就可以通过Intent拿到照片。默认情况下拍摄的照片将作为一个缩略图返回.
- 要获得完整图像,必须制定一个用于存储改图像的目标文件,文件路径定义为URI,在启动Intent时使用MediaStore.EXTRA_OUTPUT extra传入URI:
File file = new File(Environment.getExternalStorageDirectory(),"test.jpg");
Uri outputFileUri = Uri.fromFile(file);
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT,outputFileUri);
startActivityForResult(intent,TAKE_PICTURE);
然后,相机在拍摄完图像后就会被保存到制定位置,onActivityResult中不会返回缩略图,接收到的intent的数据将会是null。
protected void onActivityResult(int requestCode,int resultCode,Intent data){
if(requestCode == TAKE_PICTURE){
//检查结果是否包含缩略图
if(){
Bitmap thumnail = data.getParcelableExtra("data");
imageView.setImageBitmap(thumbnail);
}else{
//如果没有缩略图,则说明图像存储在目标URI中
//resize the full image to fit in out image view
int width = imageView.getWidth();
int height = imageView.getHeight();
BitmapFactory.Options facotryOptions = new BitmapFactory.Options();
facotryOptons.inJustDecodebounds = true;
BitmapFacotry.decodeFile(outputFileUri.getPath(),factoryOptions);
int imageWidth = facotryOptions.outWidth;
int imageHeight = facotryOptions.outHeight;
//确定将图像缩小多少
int scaleFactor = Math.min(imageWidht/widht,imageHeight/height);
//将图像文件解码为imageView的大小
factoryOptions.inJustDecodebounds = false;
factoryOptions.inSampleSize = scaleFactor;
factoryOptions.inPurgeable = true;
Bitmap bitmap = BitmapFactory.decodeFile(outputFileUri.getPath(),factoryOptions);
imageView.setIamgeBitmap(bitmap);
}
}
二、直接控制相机
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
直接调用相机,使用到的权限。
调用相机:
Camera camera = Camera.open();
使用完,要记得释放它:
camera.release();
修改相机设置,需要使用set方法来修改Parameters参数。
Camera.Parameters parameters = camera.getParameters();
camera.setParameters(parameters);
- [get/set]SceneMode场景模式,每个场景模式都为特定的场景优化了相机参数的设置
- [get/set]FlashMode 设置闪光灯模式
- [get/set]WhiteBalance 可以使用getSupportedWhiteBalance()来确认有哪些设置可用。
- [get/set]AutoWhiteBalanceLock 启用自动白平衡锁,可以使用isAutoWhiteBalanceLockSupported()确认设备是否支持这种功能。
- [get/set]ColorEffect 特殊颜色效果
- [get/set]FocuMode 相机对焦方式getSupportedFocusModes()找出可以使用的模式。
为了能在自动对焦操作完成后做些操作,需要使用autofocus()启动自动对焦,传入AutoFocusCallBack实现。
Camera.Parameters parameters = camera.getParameters();
if(parameters.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)){
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
camera.autoFocus(new AutoFocusCallback());
}
获取是否支持、定义对焦区域:
camera.getMaxNumFocusAreas();
camera.setFocusAreas();
获取是否支持、定义测光区域:
camera.getMaxNumMeteringAreas();
camera.setMeteringAreas();
使用相机预览
不先显示一个预览,是无法使用camera对象拍照的。
相机预览的是使用SurfaceHolder显示的,必须在UI层次包含一个Surface View。需要实现一个SurfaceHolder.Callback。
示例代码:
public class CameraActivity extends Activity implements SurfaceHolder.Callback{
private static final String TAG = "CameraActivity";
private Camera camera;
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
SurfaceView surface = (SurfaceView)findViewById(R.id.surfaceView);
SurfaceHolder holder = surface.getHolder();
holder.addCallback(this);
holder.setType(surfaceHolder.SURFACE_TYPE_BUFFERS);
holder.setFixedSize(400,300);
}
public void serfaceCreated(SurfaceHolder holder){
try{
camera.setPreviewDisplay(holder);
camera.startPreview();
//todo 必要时在预览上进行绘制
}catch(IOException e){
}
}
public void surfaceChanged(SurfaceHolder holder,int format,int width,int heigh){
}
public void surffaceDestoryed(SurfaceHolder holder){
camera.stopPreview();
}
@Override
protected void onPause(){
super.onPause();
camera.release();
}
@Override
protected void onResume(){
super.onResume();
camera = camera.open();
}
}
还可以分配一个PreviewCallback实现,使其在每个预览帧中出发,一遍可以实时操纵或者分析每一个预览帧。
camera.setPreviewCallback(New PreviewCallback(){
public void onPreviewFrame(byte[] data,Camera camera){
int quality = 60;
Size previewSize = camera.getParameters().getPreviewSize();
YuvImage image = new YuvImage(data,ImageFormat.Nv21,previewSize.width,previewSize.height,null);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
image.compressToJpeg(new Rect(0,0,previewSize.width,previewSize,height),quality,stream);
//todo 对预览图像执行一些操作。
}
});
拍摄照片
调用Camera对象的takePicture,并传入一个ShutterCallback和两个PictureCallback实现(一个用于RAW图像,一个用于JPEG编码的图像)。
示例代码:
private void takePicture(){
camera.takePicture(shutterCallback,rawCallback,jpegCallback);
}
ShutterCallback shutterCallback = new ShutterCallback(){
public void onShutter(){
//todo 快门关闭时执行一些操作
}
};
PictureCallback rawCallback = new PictureCallback(){
public ovid onPictureTaken(byte[] data,Camera camera){
//todo 对图像的原始数据做一些处理
}
};
PictureCallback jpgCallback = new PictureCallback(){
public ovid onPictureTaken(byte[] data,Camera camera){
//todo 对图像的原始数据做一些处理
}
};
JPEG EXIF 图像详细信息
通过将目标JPEG图像的完整文件名传入ExifInterface构造函数来创建一个新的的实例。
EXIF数据用于为照片存储各种不同的元数据,包括拍摄日期和时间、相机设置、图像设置、以及图像描述和位置。
ExifInterface exif = new ExifInterface(file.getCanonicalPath);
参考文档:
android高级编程第3版
博客:android相机开发的那些坑