Android实现调用摄像头进行拍照功能

Android实现调用摄像头进行拍照功能,第1张

概述现在Android智能手机的像素都会提供照相的功能,大部分的手机的摄像头的像素都在1000万以上的像素,有的甚至会更高。它们大多都会支持光学变焦、曝光以及快门等等。

现在AndroID智能手机的像素都会提供照相的功能,大部分的手机的摄像头的像素都在1000万以上的像素,有的甚至会更高。它们大多都会支持光学变焦、曝光以及快门等等。

下面的程序Demo实例示范了使用Camera v2来进行拍照,当用户按下拍照键时,该应用会自动对焦,当对焦成功时拍下照片。

layout/activity_main.xml界面布局代码如下:

<?xml version="1.0" enCoding="utf-8"?><manifest xmlns:androID="http://schemas.androID.com/apk/res/androID" package="com.fukaimei.camerav2test"> <!-- 授予该程序使用摄像头的权限 --> <uses-permission androID:name="androID.permission.CAMERA" /> <application  androID:allowBackup="true"  androID:icon="@mipmap/ic_launcher"  androID:label="@string/app_name"  androID:roundIcon="@mipmap/ic_launcher_round"  androID:supportsRtl="true"  androID:theme="@style/Apptheme">   <activity androID:name=".MainActivity">   <intent-filter>    <action androID:name="androID.intent.action.MAIN" />    <category androID:name="androID.intent.category.LAUNCHER" />   </intent-filter>  </activity> </application></manifest>

上面的程序的界面提供了一个自定义TextureVIEw来显示预览取景,十分简单。该自定义TextureVIEw类的代码如下:

autoFitTextureVIEw.java逻辑代码如下:

package com.fukaimei.camerav2test;import androID.content.Context;import androID.util.AttributeSet;import androID.vIEw.TextureVIEw;/** * Created by FuKaimei on 2017/9/29. */public class autoFitTextureVIEw extends TextureVIEw { private int mRatioWIDth = 0; private int mRatioHeight = 0; public autoFitTextureVIEw(Context context,AttributeSet attrs) {  super(context,attrs); } public voID setAspectRatio(int wIDth,int height) {  mRatioWIDth = wIDth;  mRatioHeight = height;  requestLayout(); } @OverrIDe protected voID onMeasure(int wIDthMeasureSpec,int heightmeasureSpec) {  super.onMeasure(wIDthMeasureSpec,heightmeasureSpec);  int wIDth = MeasureSpec.getSize(wIDthMeasureSpec);  int height = MeasureSpec.getSize(heightmeasureSpec);  if (0 == mRatioWIDth || 0 == mRatioHeight) {   setMeasuredDimension(wIDth,height);  } else {   if (wIDth < height * mRatioWIDth / mRatioHeight) {    setMeasuredDimension(wIDth,wIDth * mRatioHeight / mRatioWIDth);   } else {    setMeasuredDimension(height * mRatioWIDth / mRatioHeight,height);   }  } }}

接来了的MainActivity.java程序将会使用CameraManager来打开CameraDevice,并通过CameraDevice创建CameraCaptureSession,然后即可通过CameraCaptureSession进行预览或拍照了。

MainActivity.java逻辑代码如下:

package com.fukaimei.camerav2test;import androID.Manifest;import androID.app.Activity;import androID.content.Context;import androID.content.pm.PackageManager;import androID.content.res.Configuration;import androID.graphics.ImageFormat;import androID.graphics.SurfaceTexture;import androID.harDWare.camera2.CameraAccessException;import androID.harDWare.camera2.CameraCaptureSession;import androID.harDWare.camera2.Cameracharacteristics;import androID.harDWare.camera2.CameraDevice;import androID.harDWare.camera2.CameraManager;import androID.harDWare.camera2.CameraMetadata;import androID.harDWare.camera2.CaptureRequest;import androID.harDWare.camera2.TotalCaptureResult;import androID.harDWare.camera2.params.StreamConfigurationMap;import androID.media.Image;import androID.media.ImageReader;import androID.os.Build;import androID.os.Bundle;import androID.support.annotation.RequiresAPI;import androID.support.v4.app.ActivityCompat;import androID.util.Log;import androID.util.Size;import androID.util.SparseIntArray;import androID.vIEw.Surface;import androID.vIEw.TextureVIEw;import androID.vIEw.VIEw;import androID.Widget.Toast;import java.io.file;import java.io.fileOutputStream;import java.nio.ByteBuffer;import java.util.ArrayList;import java.util.Arrays;import java.util.Collections;import java.util.Comparator;import java.util.List;@RequiresAPI(API = Build.VERSION_CODES.LolliPOP)public class MainActivity extends Activity implements VIEw.OnClickListener { private static final SparseIntArray ORIENTATIONS = new SparseIntArray(); private static final String TAG = "MainActivity"; static {  ORIENTATIONS.append(Surface.ROTATION_0,90);  ORIENTATIONS.append(Surface.ROTATION_90,0);  ORIENTATIONS.append(Surface.ROTATION_180,270);  ORIENTATIONS.append(Surface.ROTATION_270,180); } private autoFitTextureVIEw textureVIEw; // 摄像头ID(通常0代表后置摄像头,1代表前置摄像头) private String mCameraID = "0"; // 定义代表摄像头的成员变量 private CameraDevice cameraDevice; // 预览尺寸 private Size prevIEwSize; private CaptureRequest.Builder prevIEwRequestBuilder; // 定义用于预览照片的捕获请求 private CaptureRequest prevIEwRequest; // 定义CameraCaptureSession成员变量 private CameraCaptureSession captureSession; private ImageReader imageReader; private final TextureVIEw.SurfaceTextureListener mSurfaceTextureListener   = new TextureVIEw.SurfaceTextureListener() {  @OverrIDe  public voID onSurfaceTextureAvailable(SurfaceTexture texture,int wIDth,int height) {   // 当TextureVIEw可用时,打开摄像头   openCamera(wIDth,height);  }  @OverrIDe  public voID onSurfaceTextureSizeChanged(SurfaceTexture texture,int height) {  }  @OverrIDe  public boolean onSurfaceTextureDestroyed(SurfaceTexture texture) {   return true;  }  @OverrIDe  public voID onSurfaceTextureUpdated(SurfaceTexture texture) {  } }; private final CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {  // 摄像头被打开时激发该方法  @OverrIDe  public voID onopened(CameraDevice cameraDevice) {   MainActivity.this.cameraDevice = cameraDevice;   // 开始预览   createCameraPrevIEwSession(); // ②  }  // 摄像头断开连接时激发该方法  @OverrIDe  public voID ondisconnected(CameraDevice cameraDevice) {   cameraDevice.close();   MainActivity.this.cameraDevice = null;  }  // 打开摄像头出现错误时激发该方法  @OverrIDe  public voID onError(CameraDevice cameraDevice,int error) {   cameraDevice.close();   MainActivity.this.cameraDevice = null;   MainActivity.this.finish();  } }; @OverrIDe protected voID onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  setContentVIEw(R.layout.activity_main);  textureVIEw = (autoFitTextureVIEw) findVIEwByID(R.ID.texture);  // 为该组件设置监听器  textureVIEw.setSurfaceTextureListener(mSurfaceTextureListener);  findVIEwByID(R.ID.capture).setonClickListener(this); } @OverrIDe public voID onClick(VIEw vIEw) {  captureStillPicture(); } private voID captureStillPicture() {  try {   if (cameraDevice == null) {    return;   }   // 创建作为拍照的CaptureRequest.Builder   final CaptureRequest.Builder captureRequestBuilder =     cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);   // 将imageReader的surface作为CaptureRequest.Builder的目标   captureRequestBuilder.addTarget(imageReader.getSurface());   // 设置自动对焦模式   captureRequestBuilder.set(CaptureRequest.CONTRol_AF_MODE,CaptureRequest.CONTRol_AF_MODE_CONTINUOUS_PICTURE);   // 设置自动曝光模式   captureRequestBuilder.set(CaptureRequest.CONTRol_AE_MODE,CaptureRequest.CONTRol_AE_MODE_ON_auto_FLASH);   // 获取设备方向   int rotation = getwindowManager().getDefaultdisplay().getRotation();   // 根据设备方向计算设置照片的方向   captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION,ORIENTATIONS.get(rotation));   // 停止连续取景   captureSession.stopRepeating();   // 捕获静态图像   captureSession.capture(captureRequestBuilder.build(),new CameraCaptureSession.CaptureCallback() // ⑤     {      // 拍照完成时激发该方法      @OverrIDe      public voID onCaptureCompleted(CameraCaptureSession session,CaptureRequest request,TotalCaptureResult result) {       try {        // 重设自动对焦模式        prevIEwRequestBuilder.set(CaptureRequest.CONTRol_AF_TRIGGER,CameraMetadata.CONTRol_AF_TRIGGER_CANCEL);        // 设置自动曝光模式        prevIEwRequestBuilder.set(CaptureRequest.CONTRol_AE_MODE,CaptureRequest.CONTRol_AE_MODE_ON_auto_FLASH);        // 打开连续取景模式        captureSession.setRepeatingRequest(prevIEwRequest,null,null);       } catch (CameraAccessException e) {        e.printstacktrace();       }      }     },null);  } catch (CameraAccessException e) {   e.printstacktrace();  } } // 打开摄像头 private voID openCamera(int wIDth,int height) {  setUpCameraOutputs(wIDth,height);  CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);  try {   // 打开摄像头   if (ActivityCompat.checkSelfPermission(this,Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {    // Todo: ConsIDer calling    // ActivityCompat#requestPermissions    // here to request the missing permissions,and then overrIDing    // public voID onRequestPermissionsResult(int requestCode,String[] permissions,//           int[] grantResults)    // to handle the case where the user grants the permission. See the documentation    // for ActivityCompat#requestPermissions for more details.    return;   }   manager.openCamera(mCameraID,stateCallback,null); // ①  } catch (CameraAccessException e) {   e.printstacktrace();  } } private voID createCameraPrevIEwSession() {  try {   SurfaceTexture texture = textureVIEw.getSurfaceTexture();   texture.setDefaultBufferSize(prevIEwSize.getWIDth(),prevIEwSize.getHeight());   Surface surface = new Surface(texture);   // 创建作为预览的CaptureRequest.Builder   prevIEwRequestBuilder = cameraDevice     .createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);   // 将textureVIEw的surface作为CaptureRequest.Builder的目标   prevIEwRequestBuilder.addTarget(new Surface(texture));   // 创建CameraCaptureSession,该对象负责管理处理预览请求和拍照请求   cameraDevice.createCaptureSession(Arrays.asList(surface,imageReader.getSurface()),new CameraCaptureSession.StateCallback() // ③     {      @OverrIDe      public voID onConfigured(CameraCaptureSession cameraCaptureSession) {       // 如果摄像头为null,直接结束方法       if (null == cameraDevice) {        return;       }       // 当摄像头已经准备好时,开始显示预览       captureSession = cameraCaptureSession;       try {        // 设置自动对焦模式        prevIEwRequestBuilder.set(CaptureRequest.CONTRol_AF_MODE,CaptureRequest.CONTRol_AF_MODE_CONTINUOUS_PICTURE);        // 设置自动曝光模式        prevIEwRequestBuilder.set(CaptureRequest.CONTRol_AE_MODE,CaptureRequest.CONTRol_AE_MODE_ON_auto_FLASH);        // 开始显示相机预览        prevIEwRequest = prevIEwRequestBuilder.build();        // 设置预览时连续捕获图像数据        captureSession.setRepeatingRequest(prevIEwRequest,null); // ④       } catch (CameraAccessException e) {        e.printstacktrace();       }      }      @OverrIDe      public voID onConfigureFailed(CameraCaptureSession cameraCaptureSession) {       Toast.makeText(MainActivity.this,"配置失败!",Toast.LENGTH_SHORT).show();      }     },null   );  } catch (CameraAccessException e) {   e.printstacktrace();  } } private voID setUpCameraOutputs(int wIDth,int height) {  CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);  try {   // 获取指定摄像头的特性   Cameracharacteristics characteristics     = manager.getCameracharacteristics(mCameraID);   // 获取摄像头支持的配置属性   StreamConfigurationMap map = characteristics.get(     Cameracharacteristics.SCALER_STREAM_CONfigURATION_MAP);   // 获取摄像头支持的最大尺寸   Size largest = Collections.max(     Arrays.asList(map.getoutputSizes(ImageFormat.JPEG)),new CompareSizesByArea());   // 创建一个ImageReader对象,用于获取摄像头的图像数据   imageReader = ImageReader.newInstance(largest.getWIDth(),largest.getHeight(),ImageFormat.JPEG,2);   imageReader.setonImageAvailableListener(     new ImageReader.OnImageAvailableListener() {      // 当照片数据可用时激发该方法      @OverrIDe      public voID onImageAvailable(ImageReader reader) {       // 获取捕获的照片数据       Image image = reader.acquireNextimage();       ByteBuffer buffer = image.getPlanes()[0].getBuffer();       byte[] bytes = new byte[buffer.remaining()];       // 使用IO流将照片写入指定文件       file file = new file(getExternalfilesDir(null),"pic.jpg");       buffer.get(bytes);       try (         fileOutputStream output = new fileOutputStream(file)) {        output.write(bytes);        Toast.makeText(MainActivity.this,"保存: " + file,Toast.LENGTH_LONG).show();       } catch (Exception e) {        e.printstacktrace();       } finally {        image.close();       }      }     },null);   // 获取最佳的预览尺寸   prevIEwSize = chooSEOptimalSize(map.getoutputSizes(     SurfaceTexture.class),wIDth,height,largest);   // 根据选中的预览尺寸来调整预览组件(TextureVIEw的)的长宽比   int orIEntation = getResources().getConfiguration().orIEntation;   if (orIEntation == Configuration.ORIENTATION_LANDSCAPE) {    textureVIEw.setAspectRatio(      prevIEwSize.getWIDth(),prevIEwSize.getHeight());   } else {    textureVIEw.setAspectRatio(      prevIEwSize.getHeight(),prevIEwSize.getWIDth());   }  } catch (CameraAccessException e) {   e.printstacktrace();  } catch (NullPointerException e) {   Log.d(TAG,"出现错误");  } } private static Size chooSEOptimalSize(Size[] choices,int height,Size aspectRatio) {  // 收集摄像头支持的打过预览Surface的分辨率  List<Size> bigEnough = new ArrayList<>();  int w = aspectRatio.getWIDth();  int h = aspectRatio.getHeight();  for (Size option : choices) {   if (option.getHeight() == option.getWIDth() * h / w &&     option.getWIDth() >= wIDth && option.getHeight() >= height) {    bigEnough.add(option);   }  }  // 如果找到多个预览尺寸,获取其中面积最小的。  if (bigEnough.size() > 0) {   return Collections.min(bigEnough,new CompareSizesByArea());  } else {   System.out.println("找不到合适的预览尺寸!!!");   return choices[0];  } } // 为Size定义一个比较器Comparator static class CompareSizesByArea implements Comparator<Size> {  @OverrIDe  public int compare(Size lhs,Size rhs) {   // 强转为long保证不会发生溢出   return Long.signum((long) lhs.getWIDth() * lhs.getHeight() -     (long) rhs.getWIDth() * rhs.getHeight());  } }}

上面的程序中序号①的代码是用于打开系统摄像头,openCamera()方法的第一个参数代表请求打开的摄像头ID,此处传入的摄像头ID为“0”,这代表打开设备后置摄像头;如果需要打开设备指定摄像头(比如前置摄像头),可以在调用openCamera()方法时传入相应的摄像头ID。

注意:由于该程序需要使用手机的摄像头,因此还需要在清单文件AndroIDManifest.xml文件中授权相应的权限:

<!-- 授予该程序使用摄像头的权限 --> <uses-permission androID:name="androID.permission.CAMERA" />

Demo程序运行效果界面截图如下:

Demo程序源码下载地址

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

您可能感兴趣的文章:Android 实现调用系统照相机拍照和录像的功能Android 调用系统照相机拍照和录像Android自定义照相机倒计时拍照Android调用系统摄像头拍照并显示在ImageView上Android实现调用摄像头拍照与视频功能Android实现摄像头拍照功能Android调用摄像头拍照开发教程Android实现拍照、选择图片并裁剪图片功能Android调用系统照相机拍照与摄像的方法 总结

以上是内存溢出为你收集整理的Android实现调用摄像头进行拍照功能全部内容,希望文章能够帮你解决Android实现调用摄像头进行拍照功能所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1142794.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-31
下一篇 2022-05-31

发表评论

登录后才能评论

评论列表(0条)

保存