国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android實現調用攝像頭進行拍照功能

2019-10-22 18:12:22
字體:
來源:轉載
供稿:網友

現在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 width, 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, 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 width, 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程序運行效果界面截圖如下:

Android,攝像頭,拍照

Demo程序源碼下載地址

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VEVB武林網。


注:相關教程知識閱讀請移步到Android開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 巴林右旗| 福海县| 德化县| 河北区| 宣恩县| 监利县| 基隆市| 新平| 宜川县| 鄂州市| 永定县| 行唐县| 林西县| 板桥市| 济源市| 云梦县| 许昌县| 建始县| 肃宁县| 竹北市| 鄄城县| 玛纳斯县| 乌兰察布市| 百色市| 茌平县| 六盘水市| 临颍县| 莱西市| 游戏| 双城市| 武汉市| 柯坪县| 呼伦贝尔市| 阳春市| 大余县| 潞城市| 宜章县| 铁岭市| 双流县| 察隅县| 绥中县|