Android自定义Camera实现拍照功能

本文记录了用自定义Camera实现的简单拍照功能。

Camera类在5.0以后不推荐使用了,取而代之的是android.hardware.camera2包下的类,本文使用Camera。
我们首先自定义一个View去继承SurfaceView:

public class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback, Camera.AutoFocusCallback {
 private SurfaceHolder mHolder;
 private Camera mCamera;
 private static final int ORIENTATION = 90;
 private int mScreenWidth;
 private int mScreenHeight;
 private boolean isOpen;

 public CameraSurfaceView(Context context, AttributeSet attrs) {
  super(context, attrs);
  getScreenMatrix(context);
  mHolder = getHolder();
  mHolder.addCallback(this);
  mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
 }

 private void getScreenMatrix(Context context) {
  WindowManager WM = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
  DisplayMetrics outMetrics = new DisplayMetrics();
  WM.getDefaultDisplay().getMetrics(outMetrics);
  mScreenWidth = outMetrics.widthPixels;
  mScreenHeight = outMetrics.heightPixels;
 }

 public void takePicture(Camera.ShutterCallback mShutterCallback, Camera.PictureCallback rawPictureCallback, Camera.PictureCallback jpegPictureCallback) {
  if (mCamera != null)
   mCamera.takePicture(mShutterCallback, rawPictureCallback, jpegPictureCallback);
 }

 public void startPreview() {
  mCamera.startPreview();
 }

 @Override
 public void surfaceCreated(SurfaceHolder holder) {
  if (!checkCameraHardware(getContext()))
   return;
  if (mCamera == null) {
   isOpen = safeCameraOpen(Camera.CameraInfo.CAMERA_FACING_BACK);
  }
  if (!isOpen) {
   return;
  }
  mCamera.setDisplayOrientation(ORIENTATION);
  try {
   mCamera.setPreviewDisplay(holder);

  } catch (IOException e) {
   e.printStackTrace();
  }
 }

 @Override
 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
  if (mCamera != null) {
   setCameraParams(mScreenWidth, mScreenHeight);
   mCamera.startPreview();
  }
 }

 @Override
 public void surfaceDestroyed(SurfaceHolder holder) {
  releaseCameraAndPreview();
 }

 private boolean safeCameraOpen(int id) {
  boolean qOpened = false;
  try {
   releaseCameraAndPreview();
   mCamera = Camera.open(id);
   qOpened = (mCamera != null);
  } catch (Exception e) {
   e.printStackTrace();
  }

  return qOpened;
 }

 private void releaseCameraAndPreview() {
  if (mCamera != null) {
   mCamera.stopPreview();
   mCamera.release();
   mCamera = null;
  }
 }

 private boolean checkCameraHardware(Context context) {
  if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
   return true;
  } else {
   return false;
  }
 }

 @Override
 public void onAutoFocus(boolean success, Camera camera) {

 }

 private void setCameraParams(int width, int height) {
  Camera.Parameters parameters = mCamera.getParameters();
  // 获取摄像头支持的PictureSize列表
  List<Camera.Size> pictureSizeList = parameters.getSupportedPictureSizes();
  /**从列表中选取合适的分辨率*/
  Camera.Size picSize = getProperSize(pictureSizeList, ((float) height / width));
  if (null == picSize) {
   picSize = parameters.getPictureSize();
  }
  // 根据选出的PictureSize重新设置SurfaceView大小
  float w = picSize.width;
  float h = picSize.height;
  parameters.setPictureSize(picSize.width, picSize.height);
  this.setLayoutParams(new RelativeLayout.LayoutParams((int) (height * (h / w)), height));
  // 获取摄像头支持的PreviewSize列表
  List<Camera.Size> previewSizeList = parameters.getSupportedPreviewSizes();
  Camera.Size preSize = getProperSize(previewSizeList, ((float) height) / width);
  if (null != preSize) {
   parameters.setPreviewSize(preSize.width, preSize.height);
  }

  parameters.setJpegQuality(100); // 设置照片质量
  if (parameters.getSupportedFocusModes().contains(android.hardware.Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
   parameters.setFocusMode(android.hardware.Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);// 连续对焦模式
  }

  mCamera.setDisplayOrientation(90);// 设置PreviewDisplay的方向,效果就是将捕获的画面旋转多少度显示
  mCamera.setParameters(parameters);

 }

 /**
  * 选取合适的分辨率
  */
 private Camera.Size getProperSize(List<Camera.Size> pictureSizeList, float screenRatio) {
  Camera.Size result = null;
  for (Camera.Size size : pictureSizeList) {
   float currentRatio = ((float) size.width) / size.height;
   if (currentRatio - screenRatio == 0) {
    result = size;
    break;
   }
  }

  if (null == result) {
   for (Camera.Size size : pictureSizeList) {
    float curRatio = ((float) size.width) / size.height;
    if (curRatio == 4f / 3) {// 默认w:h = 4:3
     result = size;
     break;
    }
   }
  }

  return result;
 }
}

代码没什么难度,在View创建的时候完成Camera的初始化,然后对Camera进行参数的设置(图片尺寸,质量之类的),最后别忘了在View销毁的时候对资源进行释放。

控件定义完了之后我们就要去使用它,在布局文件中添加就OK:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
 xmlns:android="http://schemas.android.com/apk/res/android"
 android:id="@+id/activity_main"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 >

 <com.padoon.cameratest.CameraSurfaceView
  android:id="@+id/sv_camera"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:layout_weight="4"/>

 <ImageView
  android:id="@+id/img_take_photo"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:layout_alignParentBottom="true"
  android:layout_alignParentRight="true"
  android:layout_gravity="bottom"
  android:layout_marginBottom="10dp"
  android:layout_marginRight="10dp"
  android:src="@mipmap/icon_camera"/>
</RelativeLayout>

然后在Activity中去完成拍照功能:

public class CameraActivity extends AppCompatActivity {
 private boolean isClick = true;
 private static final String PATH_IMAGES = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "easy_check";
 private CameraSurfaceView mCameraSurfaceView;
 //拍照快门的回调
 private Camera.ShutterCallback mShutterCallback = new Camera.ShutterCallback() {
  @Override
  public void onShutter() {

  }
 };
 //拍照完成之后返回原始数据的回调
 private Camera.PictureCallback rawPictureCallback = new Camera.PictureCallback() {
  @Override
  public void onPictureTaken(byte[] data, Camera camera) {

  }
 };
 //拍照完成之后返回压缩数据的回调
 private Camera.PictureCallback jpegPictureCallback = new Camera.PictureCallback() {
  @Override
  public void onPictureTaken(byte[] data, Camera camera) {
   mCameraSurfaceView.startPreview();
   saveFile(data);
   Toast.makeText(CameraActivity.this, "拍照成功", Toast.LENGTH_SHORT).show();
   isClick = true;

  }
 };

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  ImageView img_take_photo = (ImageView) findViewById(R.id.img_take_photo);
  mCameraSurfaceView = (CameraSurfaceView) findViewById(R.id.sv_camera);
  img_take_photo.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
    takePhoto();
   }
  });
 }

 public void takePhoto() {
  if (isClick) {
   isClick = false;
   mCameraSurfaceView.takePicture(mShutterCallback, rawPictureCallback, jpegPictureCallback);
  }
 }
 //保存图片到硬盘
 public void saveFile(byte[] data) {
  String fileName = UUID.randomUUID().toString() + ".jpg";
  FileOutputStream outputStream = null;
  try {
   File file = new File(PATH_IMAGES);
   if (!file.exists()) {
    file.mkdirs();
   }
   outputStream = new FileOutputStream(PATH_IMAGES + File.separator + fileName);
   BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream);
   bufferedOutputStream.write(data, 0, data.length);
  } catch (Exception e) {
   e.printStackTrace();
  } finally {
   try {
    outputStream.close();
   } catch (IOException e) {
    e.printStackTrace();
   }
  }
 }
}

最后记得添加拍照跟磁盘操作权限:

<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

到这一个非常简单的拍照Demo就完成了,只能当做Demo使用,离开发正式使用还有一段的距离,再次特地记录一下。

下载:源码

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • android自定义Camera拍照并查看图片

    本文实例为大家分享了android自定义Camera拍照并查看图片的具体代码,供大家参考,具体内容如下 1.打开相机 a.预览拍摄图片,需用到SurfaceView,并且实现其回调函数implements SurfaceHolder.Callback: activity_camera.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http:/

  • Android 2.3.7.r1 camera录像过程中按menu菜单键时会停止录像

    Android 2.3.7.r1 按menu键时会停止录像.改成录像时按menu键不做处理,可做如下修改: 在packages/apps/CameraOpen/src/com/mediatek/camera/VideoCamera.java onKeyDown()方法中: 修改 复制代码 代码如下: case KeyEvent.KEYCODE_MENU: if (mHeadUpDisplay != null && mGLRootView != null && !mAlert

  • android自定义Camera实现录像和拍照

    本文实例为大家分享了android自定义Camera实现录像和拍照的具体代码,供大家参考,具体内容如下 源码: package com.example.myvideocamera; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; im

  • Android编程中调用Camera时预览画面有旋转问题的解决方法

    本文实例讲述了Android编程中调用Camera时预览画面有旋转问题的解决方法.分享给大家供大家参考,具体如下: 在调用Camera写应用的时候,前后摄像头的情况有时候是不一样的.有时候,明明后摄像头没有问题,而调用到前摄像头时,却倒转了180°,或者其他角度,百思不得其解.在查看了Android源码之后,发现它的解决办法很是好,接下来贴个源码,以备日后查看. public static int getDisplayRotation(Activity activity) { int rotat

  • android系统在静音模式下关闭camera拍照声音的方法

    话说为了防止偷拍,业内有不成文规定,手机公司在做camera时,点击拍照和录像键的时候,必须要有提示音.因此,google也就非常人性化的将播放拍照声音的函数,放到了cameraService中,防止开发者能开发出不响的camera,从而只要调用拍照函数,一定会响,这是写死在framework中的. 话说这个规定在当今有点不合时宜,这不,今天我收到测试提的一个BUG,说是公司的新需求,要求在静音模式下拍照声音也得取消.这么无耻的需求,也许就在我们中国最大的山寨手机公司才会提到.废话不多说,看看是

  • Android camera实时预览 实时处理,人脸识别示例

    Android camera实时预览 实时处理,面部认证. 预览操作是网友共享的代码,我在继承SurfaceView 的CameraSurfaceView 中加入了帧监听事件,每次预览监听前五个数据帧,在处理做一个面部识别. 先看目录关系 自定义控件CameraSurfaceView.java 自定义接口方法CameraInterface.java CameraActivity预览界面. CameraSurfaceView.Java package com.centaur.camera.prev

  • Android实现Camera2预览和拍照效果

    简介 网上对于 Camera2 的介绍有很多,在 Github 上也有很多关于 Camera2 的封装库,但是对于那些库,封装性太强,有时候我们仅仅是需要个简简单单的拍照功能而已,因此,自定义一个 Camera 使之变得轻量级那是非常重要的了.(本文并非重复造轮子, 而是在于学习 Camera2API 的基本功能, 笔记之.) 学习要点: 使用 Android Camera2 API 的基本功能. 迭代连接到设备的所有相机的特征. 显示相机预览和拍摄照片. Camera2 API 为连接到 An

  • Android Camera实现毫秒级拍照实例

    我们知道自定义Camera需要以下几步 打开相机,即实例化Camera对象,Camera camera = Camera.open(); 设置Camera的相关参数,Camera.Parameters parameters = camera.getParameters(); 打开预览,camera.setPreviewDisplay(surfaceholder); camera.startPreview(); 获取图片,这里只是从预览中获取因此使用,camera.setPreviewCallb

  • android之camera用法实例详解

    本文实例讲述了android之camera用法.分享给大家供大家参考.具体如下: 1.关于预览横竖差90度的问题 原因分析 经过查证和实验,可以证实:Android提供的SDK(android.hardware.Camera)里大概不能正常的使用竖屏(portrait layout)加载照相机,当用竖屏模式加载照相机时会产生以下情况: ①. 照相机成像左倾90度(倾斜): ②. 照相机成像长宽比例不对(失比). 之所以是"大概",原因是因为可能可以通过一些比较复杂的手段解决.如果以上成

  • Android中使用Camera类编写手机拍照App的实例教程

    Camera是Android摄像头硬件的相机类,位于硬件包"android.hardware.Camera"下.它主要用于摄像头捕获图片.启动/停止预览图片.拍照.获取视频帧等,它是设备本地的服务,负责管理设备上的摄像头硬件. Camera既然用于管理设备上的摄像头硬件,那么它也为开发人员提供了相应的方法,并且这些方法大部分都是native的,用C++在底层实现,下面简单介绍一下Camera的一些方法: static Camera open():打开Camera,返回一个Camera实

随机推荐