Android 相机开发 闪光灯,前后摄像头切换,调整缩放比例
来源:互联网 发布:优化 英文 编辑:程序博客网 时间:2024/06/05 18:20
我们在开发的过程中,经常会要使用相机,android自己带有一个源生的app可以用来拍照,但是有时候为了更多的功能,我们需要自定义相机。
考虑点:
1、是否一定要用相机,没有相机的设备就不可以安装你的app了吗?
但是要记得再Manifest文件中声明,google play在没有相机的设备 上会自动过滤掉一定要使用相机的App。
2、你的应用将会怎样使用相机,调用系统已经存在的CameraApp,或者是自己定义一个App?调用系统的相机通过Intent就可以实现
3、图片存储,别的app是否可见?app卸载后是否还要可用?
Manifest文件配置
1、如果是通过intent调用相机,不需要申请权限。,通过添加Feature就可以满足
<uses-permission android:name="android.permission.CAMERA" />
2、自定义相机,则需要申请权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
在声明权限之后,google play就会阻止你的app安装在没有相机的设备上。
如果图片需要保存的在SD卡上,需要指明权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
使用已经存在的相机APP步奏:
1、构造一个Intent,使用Intent的类型为,MediaStore.ACTION_IMAGE_CAPTURE
调用一个已经存在的相机应用
Intent可以附带一个参数MediaStore.EXTRA_OUTPUT,参数类型为Uri指定一个路径和
文件名保存相片
2、调用startActivityForResult()
3、在activity的onActivityResult()方法中会收到来自Intent的数据
构建一个Intent对象,设置Action,并将保存图片路径传入
Intent cameraIntent = new Intent(); cameraIntent.setAction(MediaStore.ACTION_IMAGE_CAPTURE); imageUri = getImageFileUri(); cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);//指定了存储路径将返回的data将会是null startActivityForResult(cameraIntent, REQUESt_CODE_CAPTURE_IMAGE);
private Uri getImageFileUri(){ String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); File imageFile = new File(FileUtil.EXAMPLE_PATH + Constant.IMAGE +File.separator + timeStamp + ".jpg"); return Uri.fromFile(imageFile);}
在activity中的onAcivityResult方法中取数据,注意如果指定了保存路径,将不会有返回值,如果没有保存路径,则会返回路径。
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == RESULT_OK) { switch (requestCode) { case REQUESt_CODE_CAPTURE_IMAGE: if (null != data) { }else { } break; } } }
2、自定义相机
遵循以下步奏:
1、检查是否有相机,访问请求
private boolean isCameraExist(){ return getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA);}
2、创建一个Activity类继实现SurfaceHolder接口
3、创建一个预览布局
4、创建动作监听,例如一个按钮拍照
5、拍照并保存
6、释放相机
相机功能:
android支持许多相机特点,例如相片格式,闪光灯模式,焦点设置,等等
这些都是通过Camera.Parameters来控制
这些知识点在代码中通过添加注释的方式来讲解。
开发过程中遇到的问题:
1、在onPause中释放相机后,onResume再为相机绑定SurfaceView的时候,会有异常抛出,相机已释放。
解决方案:添加变量hasSurface.在surfaceDestroyed中置为false。
2、闪光灯设置过程中Camera.Parameters.FLASH_MODE_ON无效果,
解决方案:改为Camera.Parameters.FLASH_MODE_TORCH
3、SurfaceHolder.Callback此接口是设置在SurfaceView中的。
4、使用相机前一定要判断是否支持相机,要在Manifest文件中配置,使用前置相机要记得判断是否支持前置相机。
5、人脸识别是在android 4.0之后添加的,并不是所有的android 4.0都支持人脸识别。笔者系统为 android 4.1,并不支持人脸识别。
6、最重要的一点,相机是有限的公共资源,很多app都可以调用,所以一定要release掉!
package com.example.androidtest;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.text.SimpleDateFormat;import java.util.Date;import java.util.List;import com.example.constant.Constant;import com.example.util.FileUtil;import android.annotation.SuppressLint;import android.app.Activity;import android.hardware.Camera;import android.hardware.Camera.Face;import android.hardware.Camera.FaceDetectionListener;import android.hardware.Camera.Parameters;import android.hardware.Camera.PictureCallback;import android.os.Bundle;import android.util.Log;import android.view.SurfaceHolder;import android.view.SurfaceView;import android.view.View;import android.view.View.OnClickListener;import android.view.Window;import android.widget.SeekBar;import android.widget.SeekBar.OnSeekBarChangeListener;public class CameraActivity extends Activity implements OnClickListener ,SurfaceHolder.Callback{ private Camera mCamera; private Parameters mParameters; private SurfaceView mSurfaceView; /** * 相机位置 */ private int cameraPosition = 0; /** * 这个参数主要是在程序到后台之后,再切换回来的判断 */ private boolean hasSurface = true; /** * 闪光灯是否开启 */ private boolean isLighting = false; /** * 是否支持闪光灯 */ private boolean isSupportedLight = false; /** * 调整Zoom用的seekbar */ private SeekBar mSeekBar; private SurfaceHolder viewHolder; private int cameraCount,maxZoom; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_camera); hasSurface = false; //获取相机个数 cameraCount = Camera.getNumberOfCameras(); } @Override protected void onResume() { super.onResume(); initView(); } private void initCamera(SurfaceHolder viewHolder) { mCamera = getCameraInstance(-1); mCamera.setFaceDetectionListener(mFaceDetectionListener);//添加人脸识别监听 mParameters = mCamera.getParameters(); maxZoom = mParameters.getMaxZoom(); mSeekBar.setMax(maxZoom*100); mSeekBar.setProgress((int) (0.5 * maxZoom * 100)); List<String> features = mParameters.getSupportedFlashModes();//判断是否支持闪光灯 if (features.contains(Camera.Parameters.FLASH_MODE_ON)) { isLighting = false; isSupportedLight = true; } startPreviewOfCamera(viewHolder); startFaceDectection(); } private void startPreviewOfCamera(SurfaceHolder viewHolder) { try { mCamera.setPreviewDisplay(viewHolder); mCamera.setDisplayOrientation(90);//防止预览图片旋转 Parameters mParameters = mCamera.getParameters(); mParameters.setRotation(90);//防止保存的图片旋转 mCamera.setParameters(mParameters); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 初始化控件 * @date 2015年4月3日 * @time 下午5:13:35 * @author Tony */ private void initView() { mSurfaceView = (SurfaceView) findViewById(R.id.mSurfaceview); viewHolder = mSurfaceView.getHolder(); //第一次会再onSurfaceCreated的时候初始化相机,并绑定预览效果 if (hasSurface) { initCamera(viewHolder); } else { viewHolder.addCallback(this);//为viewHolder添加回调 viewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); } findViewById(R.id.btnOpenSplash).setOnClickListener(this); findViewById(R.id.btnCaptureCamera).setOnClickListener(this); findViewById(R.id.btnOpenFront).setOnClickListener(this); mSeekBar = (SeekBar) findViewById(R.id.mSeekBar); mSeekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() { @Override public void onStopTrackingTouch(SeekBar seekBar) { } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { mParameters = mCamera.getParameters(); mParameters.setZoom((int) (progress * 1.0f / (maxZoom * 100) * maxZoom)); mCamera.setParameters(mParameters); } }); } @Override protected void onPause() { super.onPause(); releasedCamera(); } /** * 释放相机 * @date 2015年4月3日 * @time 下午5:17:24 * @author Tony */ private void releasedCamera() { if (null != mCamera) { mCamera.setPreviewCallback(null) ; mCamera.stopPreview(); mCamera.release(); mCamera = null; hasSurface = false; } } @Override public void onClick(View v) { switch (v.getId()) { case R.id.btnOpenSplash: if (isSupportedLight) { String flashMode = isLighting ? Camera.Parameters.FLASH_MODE_OFF:Camera.Parameters.FLASH_MODE_TORCH; mParameters.setFlashMode(flashMode); mCamera.setParameters(mParameters); isLighting = !isLighting; } break; case R.id.btnOpenFront: changeCamera(); break; case R.id.btnCaptureCamera: mCamera.takePicture(null, null, mPictureCallback); break; } } /** * 拍照时候调用,保存图片 */ private PictureCallback mPictureCallback = new PictureCallback() { @Override public void onPictureTaken(byte[] data, Camera camera) { File imageFile = getImageFile(); if (null != imageFile) { try { FileOutputStream fos = new FileOutputStream(imageFile); fos.write(data); fos.close(); } catch (IOException e) { e.printStackTrace(); } } } }; /** * 获得保存图片的文件 * @return * @date 2015年4月3日 * @time 下午5:18:03 * @author Tony */ @SuppressLint("SimpleDateFormat") private File getImageFile() { String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()) + "TONY"; File imageFile = new File(FileUtil.EXAMPLE_PATH + Constant.IMAGE +File.separator + timeStamp + ".jpg"); return imageFile; } /** * 获得相机实例 * @param cameraPosition * @return * @date 2015年4月3日 * @time 下午5:15:25 * @author Tony */ public Camera getCameraInstance(int cameraPosition) { if (cameraPosition < 0 || cameraPosition > cameraCount) { cameraPosition = 0; } Camera mCamera = null; try { mCamera = Camera.open(cameraPosition); } catch (Exception e) { //相机别的app在使用,或者是不存在 } return mCamera; } @Override public void surfaceCreated(SurfaceHolder holder) { if (!hasSurface) { hasSurface = true; if (mCamera == null) { initCamera(holder); } mCamera.startPreview(); } hasSurface = true; } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { hasSurface = false; } private void changeCamera() { if (cameraCount <= 1) { return; } mCamera.stopPreview(); mCamera.release(); mCamera = null; cameraPosition = cameraPosition == 1 ? 0:1; mCamera = getCameraInstance(cameraPosition); mCamera.setFaceDetectionListener(mFaceDetectionListener); startPreviewOfCamera(viewHolder); mCamera.startPreview(); mCamera.startFaceDetection(); } private void startFaceDectection() { // Try starting Face Detection Camera.Parameters params = mCamera.getParameters(); // start face detection only *after* preview has started if (params.getMaxNumDetectedFaces() > 0){ mCamera.startFaceDetection(); } } private FaceDetectionListener mFaceDetectionListener = new FaceDetectionListener() { @Override public void onFaceDetection(Face[] faces, Camera camera) { if (faces.length > 0) { Log.e("====人脸识别====","" + faces[0].leftEye.x ); } } };}
布局文件就不贴了吧。很简单,一个SurfaceView,三个button,还有一个SeekBar
- Android 相机开发 闪光灯,前后摄像头切换,调整缩放比例
- Android surfaceview 自定义相机 拍照(闪光灯、前后摄像头)
- Android surfaceview 自定义相机 拍照(闪光灯、前后摄像头)
- Android 自定义相机 切换相机 参考线(辅助线) 闪光灯 缩放 自动聚焦 Demo
- Android自定义相机,切换前后摄像头,照相机拍照
- android高级技术之相机的前后摄像头切换
- android 相机 前后摄像头判断
- Android 如何切换前后摄像头
- Vuforia SDK---- AR开发vuforia 相机前后摄像头动态切换功能实现
- Vuforia SDK---- AR开发vuforia 相机前后摄像头动态切换功能实现
- 【Android】自定义相机的实现(支持连续拍照、前后摄像头切换、连续对焦)
- 相机的功能丰富,加入前后摄像头的翻转,闪光灯,对焦功能。
- ios开发之设备前后摄像头切换
- 实现android 前后摄像头切换效果
- 自定义Camera,闪光灯,相机切换,相机聚焦
- Android开发Camera类照相机,前后摄像头切换,分辨率读取和调节
- Android 比例缩放viewgroup
- iphone 4 摄像头前后切换
- vector 在循环中删除数据示例
- 在 Android 和 iOS 手机上模拟触屏点击的区别
- java.lang.IllegalAccessError: Class ref in pre-verified class resolved to unexpected implementatio
- dubbo 实例详解
- 分类回归树CART(最容易懂得文章)
- Android 相机开发 闪光灯,前后摄像头切换,调整缩放比例
- 选择网站建设公司的时候,我们应该选择怎么样的一个网站建设公司?
- 文本分类常用算法比较
- linux shell 字符串操作(长度,查找,替换)详解BASH
- 【转载】常见浏览器兼容性问题与解决方案
- 讲解org.springframework.context.ApplicationContextAware
- String.format()方法使用
- android:at android.widget.RelativeLayout.onMeasure(Relayout)
- eclipse res/bin 变成白块。gen already exists but is not a source folder----解决办法